comparison src/master/login-process.c @ 1610:6850142c4e25 HEAD

New configuration file code. Some syntax changes, but tries to be somewhat backwards compatible. SIGHUP now reverts back to old configuration if it detected errors in new one.
author Timo Sirainen <tss@iki.fi>
date Thu, 10 Jul 2003 06:04:07 +0300
parents e7c627bacaaf
children b3526668de78
comparison
equal deleted inserted replaced
1609:5c2ad8ec50db 1610:6850142c4e25
15 #include "master-login-interface.h" 15 #include "master-login-interface.h"
16 16
17 #include <unistd.h> 17 #include <unistd.h>
18 #include <syslog.h> 18 #include <syslog.h>
19 19
20 struct login_group {
21 struct login_group *next;
22
23 struct login_settings *set;
24
25 unsigned int processes;
26 unsigned int listening_processes;
27 unsigned int wanted_processes_count;
28
29 struct login_process *oldest_nonlisten_process;
30 struct login_process *newest_nonlisten_process;
31
32 const char *executable;
33 const char *module_dir;
34 unsigned int process_size;
35 int process_type;
36 int *listen_fd, *ssl_listen_fd;
37 };
38
39 struct login_process { 20 struct login_process {
40 struct login_group *group; 21 struct login_group *group;
41 struct login_process *prev_nonlisten, *next_nonlisten; 22 struct login_process *prev_nonlisten, *next_nonlisten;
42 int refcount; 23 int refcount;
43 24
69 50
70 static void login_process_destroy(struct login_process *p); 51 static void login_process_destroy(struct login_process *p);
71 static void login_process_unref(struct login_process *p); 52 static void login_process_unref(struct login_process *p);
72 static int login_process_init_group(struct login_process *p); 53 static int login_process_init_group(struct login_process *p);
73 54
74 static void login_group_create(struct login_settings *login_set) 55 static void login_group_create(struct settings *set)
75 { 56 {
76 struct login_group *group; 57 struct login_group *group;
77 58
78 if (strstr(set->protocols, login_set->name) == NULL) {
79 /* not enabled */
80 return;
81 }
82
83 group = i_new(struct login_group, 1); 59 group = i_new(struct login_group, 1);
84 group->set = login_set; 60 group->set = set;
85 61 group->process_type = set->protocol == MAIL_PROTOCOL_IMAP ?
86 if (strcmp(login_set->name, "imap") == 0) { 62 PROCESS_TYPE_IMAP : PROCESS_TYPE_POP3;
87 group->executable = set->imap_executable;
88 group->process_size = set->imap_process_size;
89 group->process_type = PROCESS_TYPE_IMAP;
90 group->listen_fd = &mail_fd[FD_IMAP];
91 group->ssl_listen_fd = &mail_fd[FD_IMAPS];
92 group->module_dir = !set->imap_use_modules ? NULL :
93 set->imap_modules;
94 } else if (strcmp(login_set->name, "pop3") == 0) {
95 group->executable = set->pop3_executable;
96 group->process_size = set->pop3_process_size;
97 group->process_type = PROCESS_TYPE_POP3;
98 group->listen_fd = &mail_fd[FD_POP3];
99 group->ssl_listen_fd = &mail_fd[FD_POP3S];
100 group->module_dir = !set->pop3_use_modules ? NULL :
101 set->pop3_modules;
102 } else
103 i_panic("Unknown login group name '%s'", login_set->name);
104 63
105 group->next = login_groups; 64 group->next = login_groups;
106 login_groups = group; 65 login_groups = group;
107 } 66 }
108 67
121 master_reply.success = FALSE; 80 master_reply.success = FALSE;
122 else { 81 else {
123 struct login_group *group = request->process->group; 82 struct login_group *group = request->process->group;
124 83
125 master_reply.success = 84 master_reply.success =
126 create_mail_process(request->fd, &request->ip, 85 create_mail_process(group, request->fd, &request->ip,
127 group->executable,
128 group->module_dir,
129 group->process_size,
130 group->process_type,
131 reply, (const char *) data); 86 reply, (const char *) data);
132 } 87 }
133 88
134 /* reply to login */ 89 /* reply to login */
135 master_reply.tag = request->login_tag; 90 master_reply.tag = request->login_tag;
166 if (p->group->oldest_nonlisten_process == NULL) 121 if (p->group->oldest_nonlisten_process == NULL)
167 p->group->oldest_nonlisten_process = p; 122 p->group->oldest_nonlisten_process = p;
168 } 123 }
169 } 124 }
170 125
171 static struct login_group *login_group_process_find(const char *name) 126 static void login_process_groups_create(void)
127 {
128 struct server_settings *server;
129
130 for (server = settings_root; server != NULL; server = server->next) {
131 if (server->imap != NULL)
132 login_group_create(server->imap);
133 if (server->pop3 != NULL)
134 login_group_create(server->pop3);
135 }
136 }
137
138 static struct login_group *
139 login_group_process_find(const char *name, enum mail_protocol protocol)
172 { 140 {
173 struct login_group *group; 141 struct login_group *group;
174 struct login_settings *login; 142
175 143 if (login_groups == NULL)
176 if (login_groups == NULL) { 144 login_process_groups_create();
177 for (login = set->logins; login != NULL; login = login->next)
178 login_group_create(login);
179 }
180 145
181 for (group = login_groups; group != NULL; group = group->next) { 146 for (group = login_groups; group != NULL; group = group->next) {
182 if (strcmp(group->set->name, name) == 0) 147 if (strcmp(group->set->server->name, name) == 0 &&
148 group->set->protocol == protocol)
183 return group; 149 return group;
184 } 150 }
185 151
186 return NULL; 152 return NULL;
187 } 153 }
188 154
189 static int login_process_read_group(struct login_process *p) 155 static int login_process_read_group(struct login_process *p)
190 { 156 {
191 struct login_group *group; 157 struct login_group *group;
192 const char *name; 158 const char *name, *proto;
193 char buf[256]; 159 char buf[256];
160 enum mail_protocol protocol;
194 unsigned int len; 161 unsigned int len;
195 ssize_t ret; 162 ssize_t ret;
196 163
197 /* read length */ 164 /* read length */
198 ret = read(p->fd, buf, 1); 165 ret = read(p->fd, buf, 1);
199 if (ret != 1) 166 if (ret != 1)
200 len = 0; 167 len = 0;
201 else { 168 else {
202 len = buf[0]; 169 len = buf[0];
203 if (len >= sizeof(buf)) { 170 if (len >= sizeof(buf)) {
204 i_error("login: Process name length too large"); 171 i_error("login: Server name length too large");
205 return FALSE; 172 return FALSE;
206 } 173 }
207 174
208 ret = read(p->fd, buf, len); 175 ret = read(p->fd, buf, len);
209 } 176 }
210 177
211 if (ret < 0) 178 if (ret < 0)
212 i_error("login: read() failed: %m"); 179 i_error("login: read() failed: %m");
213 else if (len == 0 || (size_t)ret != len) 180 else if (len == 0 || (size_t)ret != len)
214 i_error("login: Process name wasn't sent"); 181 i_error("login: Server name wasn't sent");
215 else { 182 else {
216 name = t_strndup(buf, len); 183 name = t_strndup(buf, len);
217 group = login_group_process_find(name); 184 proto = strchr(buf, '/');
185 if (proto == NULL) {
186 i_error("login: Missing protocol from server name '%s'",
187 name);
188 return FALSE;
189 }
190 name = t_strdup_until(buf, proto++);
191
192 if (strcmp(proto, "imap") == 0)
193 protocol = MAIL_PROTOCOL_IMAP;
194 else if (strcmp(proto, "pop3") == 0)
195 protocol = MAIL_PROTOCOL_IMAP;
196 else {
197 i_error("login: Unknown protocol '%s'", proto);
198 return FALSE;
199 }
200
201 group = login_group_process_find(name, protocol);
218 if (group == NULL) { 202 if (group == NULL) {
219 i_error("login: Unknown process group '%s'", name); 203 i_error("login: Unknown server name '%s'", name);
220 return FALSE; 204 return FALSE;
221 } 205 }
222 206
223 p->group = group; 207 p->group = group;
224 return login_process_init_group(p); 208 return login_process_init_group(p);
382 i_free(p); 366 i_free(p);
383 } 367 }
384 368
385 static void login_process_init_env(struct login_group *group, pid_t pid) 369 static void login_process_init_env(struct login_group *group, pid_t pid)
386 { 370 {
387 child_process_init_env(); 371 struct settings *set = group->set;
372
373 child_process_init_env(set);
388 374
389 /* setup access environment - needs to be done after 375 /* setup access environment - needs to be done after
390 clean_child_process() since it clears environment */ 376 clean_child_process() since it clears environment */
391 restrict_access_set_env(group->set->user, 377 restrict_access_set_env(set->login_user, set->login_uid, set->login_gid,
392 group->set->uid, set->login_gid,
393 set->login_chroot ? set->login_dir : NULL, 378 set->login_chroot ? set->login_dir : NULL,
394 0, 0); 379 0, 0);
395 380
396 env_put("DOVECOT_MASTER=1"); 381 env_put("DOVECOT_MASTER=1");
397 382
398 if (!set->ssl_disable) { 383 if (!set->ssl_disable) {
399 env_put(t_strconcat("SSL_CERT_FILE=", 384 env_put(t_strconcat("SSL_CERT_FILE=",
400 set->ssl_cert_file, NULL)); 385 set->ssl_cert_file, NULL));
401 env_put(t_strconcat("SSL_KEY_FILE=", set->ssl_key_file, NULL)); 386 env_put(t_strconcat("SSL_KEY_FILE=",
387 set->ssl_key_file, NULL));
402 env_put(t_strconcat("SSL_PARAM_FILE=", 388 env_put(t_strconcat("SSL_PARAM_FILE=",
403 set->ssl_parameters_file, NULL)); 389 set->ssl_parameters_file, NULL));
404 } 390 }
405 391
406 if (set->disable_plaintext_auth) 392 if (set->disable_plaintext_auth)
408 if (set->verbose_proctitle) 394 if (set->verbose_proctitle)
409 env_put("VERBOSE_PROCTITLE=1"); 395 env_put("VERBOSE_PROCTITLE=1");
410 if (set->verbose_ssl) 396 if (set->verbose_ssl)
411 env_put("VERBOSE_SSL=1"); 397 env_put("VERBOSE_SSL=1");
412 398
413 if (group->set->process_per_connection) { 399 if (set->login_process_per_connection) {
414 env_put("PROCESS_PER_CONNECTION=1"); 400 env_put("PROCESS_PER_CONNECTION=1");
415 env_put("MAX_LOGGING_USERS=1"); 401 env_put("MAX_LOGGING_USERS=1");
416 } else { 402 } else {
417 env_put(t_strdup_printf("MAX_LOGGING_USERS=%u", 403 env_put(t_strdup_printf("MAX_LOGGING_USERS=%u",
418 group->set->max_logging_users)); 404 set->login_max_logging_users));
419 } 405 }
420 406
421 env_put(t_strdup_printf("PROCESS_UID=%s", dec2str(pid))); 407 env_put(t_strdup_printf("PROCESS_UID=%s", dec2str(pid)));
422 } 408 }
423 409
425 { 411 {
426 static const char *argv[] = { NULL, NULL }; 412 static const char *argv[] = { NULL, NULL };
427 pid_t pid; 413 pid_t pid;
428 int fd[2]; 414 int fd[2];
429 415
430 if (group->set->process_per_connection && 416 if (group->set->login_process_per_connection &&
431 group->processes - group->listening_processes >= 417 group->processes - group->listening_processes >=
432 group->set->max_logging_users) { 418 group->set->login_max_logging_users) {
433 if (group->oldest_nonlisten_process != NULL) 419 if (group->oldest_nonlisten_process != NULL)
434 login_process_destroy(group->oldest_nonlisten_process); 420 login_process_destroy(group->oldest_nonlisten_process);
435 } 421 }
436 422
437 if (group->set->uid == 0) 423 if (group->set->login_uid == 0)
438 i_fatal("Login process must not run as root"); 424 i_fatal("Login process must not run as root");
439 425
440 /* create communication to process with a socket pair */ 426 /* create communication to process with a socket pair */
441 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) { 427 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) {
442 i_error("socketpair() failed: %m"); 428 i_error("socketpair() failed: %m");
459 (void)close(fd[1]); 445 (void)close(fd[1]);
460 return pid; 446 return pid;
461 } 447 }
462 448
463 /* move the listen handle */ 449 /* move the listen handle */
464 if (dup2(*group->listen_fd, LOGIN_LISTEN_FD) < 0) 450 if (dup2(group->set->listen_fd, LOGIN_LISTEN_FD) < 0)
465 i_fatal("login: dup2(listen_fd) failed: %m"); 451 i_fatal("login: dup2(listen_fd) failed: %m");
466 fd_close_on_exec(LOGIN_LISTEN_FD, FALSE); 452 fd_close_on_exec(LOGIN_LISTEN_FD, FALSE);
467 453
468 /* move the SSL listen handle */ 454 /* move the SSL listen handle */
469 if (dup2(*group->ssl_listen_fd, LOGIN_SSL_LISTEN_FD) < 0) 455 if (dup2(group->set->ssl_listen_fd, LOGIN_SSL_LISTEN_FD) < 0)
470 i_fatal("login: dup2(ssl_listen_fd) failed: %m"); 456 i_fatal("login: dup2(ssl_listen_fd) failed: %m");
471 fd_close_on_exec(LOGIN_SSL_LISTEN_FD, FALSE); 457 fd_close_on_exec(LOGIN_SSL_LISTEN_FD, FALSE);
472 458
473 /* move communication handle */ 459 /* move communication handle */
474 if (dup2(fd[1], LOGIN_MASTER_SOCKET_FD) < 0) 460 if (dup2(fd[1], LOGIN_MASTER_SOCKET_FD) < 0)
478 (void)close(fd[0]); 464 (void)close(fd[0]);
479 (void)close(fd[1]); 465 (void)close(fd[1]);
480 466
481 login_process_init_env(group, getpid()); 467 login_process_init_env(group, getpid());
482 468
483 if (!set->login_chroot) { 469 if (!group->set->login_chroot) {
484 /* no chrooting, but still change to the directory */ 470 /* no chrooting, but still change to the directory */
485 if (chdir(set->login_dir) < 0) 471 if (chdir(group->set->login_dir) < 0) {
486 i_fatal("chdir(%s) failed: %m", set->login_dir); 472 i_fatal("chdir(%s) failed: %m",
487 } 473 group->set->login_dir);
488 474 }
489 restrict_process_size(group->set->process_size, (unsigned int)-1); 475 }
476
477 restrict_process_size(group->set->login_process_size, (unsigned int)-1);
490 478
491 /* make sure we don't leak syslog fd, but do it last so that 479 /* make sure we don't leak syslog fd, but do it last so that
492 any errors above will be logged */ 480 any errors above will be logged */
493 closelog(); 481 closelog();
494 482
495 /* hide the path, it's ugly */ 483 /* hide the path, it's ugly */
496 argv[0] = strrchr(group->set->executable, '/'); 484 argv[0] = strrchr(group->set->login_executable, '/');
497 if (argv[0] == NULL) argv[0] = group->set->executable; else argv[0]++; 485 if (argv[0] == NULL)
498 486 argv[0] = group->set->login_executable;
499 execv(group->set->executable, (char **) argv); 487 else
488 argv[0]++;
489
490 execv(group->set->login_executable, (char **) argv);
500 491
501 i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", 492 i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m",
502 group->set->executable); 493 group->set->login_executable);
503 return -1; 494 return -1;
504 } 495 }
505 496
506 void login_process_abormal_exit(pid_t pid) 497 void login_process_abormal_exit(pid_t pid)
507 { 498 {
532 } 523 }
533 } 524 }
534 525
535 static void login_group_start_missings(struct login_group *group) 526 static void login_group_start_missings(struct login_group *group)
536 { 527 {
537 if (!group->set->process_per_connection) { 528 if (!group->set->login_process_per_connection) {
538 /* create max. one process every second, that way if it keeps 529 /* create max. one process every second, that way if it keeps
539 dying all the time we don't eat all cpu with fork()ing. */ 530 dying all the time we don't eat all cpu with fork()ing. */
540 if (group->listening_processes < group->set->processes_count) 531 if (group->listening_processes <
532 group->set->login_processes_count)
541 (void)create_login_process(group); 533 (void)create_login_process(group);
542 return; 534 return;
543 } 535 }
544 536
545 /* we want to respond fast when multiple clients are connecting 537 /* we want to respond fast when multiple clients are connecting
547 same method as apache: check once a second if we need new 539 same method as apache: check once a second if we need new
548 processes. if yes and we've used all the existing processes, 540 processes. if yes and we've used all the existing processes,
549 double their amount (unless we've hit the high limit). 541 double their amount (unless we've hit the high limit).
550 Then for each second that didn't use all existing processes, 542 Then for each second that didn't use all existing processes,
551 drop the max. process count by one. */ 543 drop the max. process count by one. */
552 if (group->wanted_processes_count < group->set->processes_count) 544 if (group->wanted_processes_count < group->set->login_processes_count) {
553 group->wanted_processes_count = group->set->processes_count; 545 group->wanted_processes_count =
554 else if (group->listening_processes == 0) 546 group->set->login_processes_count;
547 } else if (group->listening_processes == 0)
555 group->wanted_processes_count *= 2; 548 group->wanted_processes_count *= 2;
556 else if (group->wanted_processes_count > group->set->processes_count) 549 else if (group->wanted_processes_count >
550 group->set->login_processes_count)
557 group->wanted_processes_count--; 551 group->wanted_processes_count--;
558 552
559 if (group->wanted_processes_count > group->set->max_processes_count) 553 if (group->wanted_processes_count >
560 group->wanted_processes_count = group->set->max_processes_count; 554 group->set->login_max_processes_count) {
555 group->wanted_processes_count =
556 group->set->login_max_processes_count;
557 }
561 558
562 while (group->listening_processes < group->wanted_processes_count) 559 while (group->listening_processes < group->wanted_processes_count)
563 (void)create_login_process(group); 560 (void)create_login_process(group);
564 } 561 }
565 562
566 static void 563 static void
567 login_processes_start_missing(void *context __attr_unused__) 564 login_processes_start_missing(void *context __attr_unused__)
568 { 565 {
569 struct login_group *group; 566 struct login_group *group;
570 struct login_settings *login; 567
571 568 if (login_groups == NULL)
572 if (login_groups == NULL) { 569 login_process_groups_create();
573 for (login = set->logins; login != NULL; login = login->next)
574 login_group_create(login);
575 }
576 570
577 for (group = login_groups; group != NULL; group = group->next) 571 for (group = login_groups; group != NULL; group = group->next)
578 login_group_start_missings(group); 572 login_group_start_missings(group);
579 } 573 }
580 574