comparison src/master/login-process.c @ 1055:a72bba3f8a55 HEAD

Rewrote setting handling. Changed some existing settings also since POP3 support required changes anyway. POP3 seems to be really working now :)
author Timo Sirainen <tss@iki.fi>
date Thu, 30 Jan 2003 19:59:31 +0200
parents 793f05a7e50e
children 6cb5b50aea71
comparison
equal deleted inserted replaced
1054:cd1ac4101adf 1055:a72bba3f8a55
9 #include "env-util.h" 9 #include "env-util.h"
10 #include "restrict-access.h" 10 #include "restrict-access.h"
11 #include "restrict-process-size.h" 11 #include "restrict-process-size.h"
12 #include "login-process.h" 12 #include "login-process.h"
13 #include "auth-process.h" 13 #include "auth-process.h"
14 #include "imap-process.h" 14 #include "mail-process.h"
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 unsigned int process_size;
34 int *listen_fd, *ssl_listen_fd;
35 };
36
20 struct login_process { 37 struct login_process {
38 struct login_group *group;
21 struct login_process *prev_nonlisten, *next_nonlisten; 39 struct login_process *prev_nonlisten, *next_nonlisten;
22 int refcount; 40 int refcount;
23 41
24 pid_t pid; 42 pid_t pid;
25 int fd; 43 int fd;
42 60
43 static unsigned int auth_id_counter; 61 static unsigned int auth_id_counter;
44 static struct timeout *to; 62 static struct timeout *to;
45 63
46 static struct hash_table *processes; 64 static struct hash_table *processes;
47 static struct login_process *oldest_nonlisten_process; 65 static struct login_group *login_groups;
48 static struct login_process *newest_nonlisten_process;
49 static unsigned int listening_processes;
50 static unsigned int wanted_processes_count;
51 66
52 static void login_process_destroy(struct login_process *p); 67 static void login_process_destroy(struct login_process *p);
53 static void login_process_unref(struct login_process *p); 68 static void login_process_unref(struct login_process *p);
69
70 static void login_group_create(struct login_settings *login_set)
71 {
72 struct login_group *group;
73
74 group = i_new(struct login_group, 1);
75 group->set = login_set;
76
77 if (strcmp(login_set->name, "imap") == 0) {
78 group->executable = set->imap_executable;
79 group->process_size = set->imap_process_size;
80 group->listen_fd = &mail_fd[FD_IMAP];
81 group->ssl_listen_fd = &mail_fd[FD_IMAPS];
82 } else if (strcmp(login_set->name, "pop3") == 0) {
83 group->executable = set->pop3_executable;
84 group->process_size = set->pop3_process_size;
85 group->listen_fd = &mail_fd[FD_POP3];
86 group->ssl_listen_fd = &mail_fd[FD_POP3S];
87 } else
88 i_panic("Unknown login group name '%s'", login_set->name);
89
90 group->next = login_groups;
91 login_groups = group;
92 }
93
94 static void login_group_destroy(struct login_group *group)
95 {
96 i_free(group);
97 }
54 98
55 void auth_master_callback(struct auth_master_reply *reply, 99 void auth_master_callback(struct auth_master_reply *reply,
56 const unsigned char *data, void *context) 100 const unsigned char *data, void *context)
57 { 101 {
58 struct login_auth_request *request = context; 102 struct login_auth_request *request = context;
59 struct master_login_reply master_reply; 103 struct master_login_reply master_reply;
60 104
61 if (reply == NULL || !reply->success) 105 if (reply == NULL || !reply->success)
62 master_reply.success = FALSE; 106 master_reply.success = FALSE;
63 else { 107 else {
108 struct login_group *group = request->process->group;
109
64 master_reply.success = 110 master_reply.success =
65 create_imap_process(request->fd, &request->ip, reply, 111 create_mail_process(request->fd, &request->ip,
66 (const char *) data); 112 group->executable,
113 group->process_size,
114 reply, (const char *) data);
67 } 115 }
68 116
69 /* reply to login */ 117 /* reply to login */
70 master_reply.tag = request->login_tag; 118 master_reply.tag = request->login_tag;
71 119
72 if (o_stream_send(request->process->output, &master_reply, 120 if (o_stream_send(request->process->output, &master_reply,
73 sizeof(master_reply)) < 0) 121 sizeof(master_reply)) < 0)
74 login_process_destroy(request->process); 122 login_process_destroy(request->process);
75 123
76 if (close(request->fd) < 0) 124 if (close(request->fd) < 0)
77 i_error("close(imap client) failed: %m"); 125 i_error("close(mail client) failed: %m");
78 login_process_unref(request->process); 126 login_process_unref(request->process);
79 i_free(request); 127 i_free(request);
80 } 128 }
81 129
82 static void login_process_mark_nonlistening(struct login_process *p) 130 static void login_process_mark_nonlistening(struct login_process *p)
86 "notification"); 134 "notification");
87 return; 135 return;
88 } 136 }
89 137
90 p->listening = FALSE; 138 p->listening = FALSE;
91 listening_processes--; 139 p->group->listening_processes--;
92 140
93 p->prev_nonlisten = newest_nonlisten_process; 141 p->prev_nonlisten = p->group->newest_nonlisten_process;
94 142
95 if (newest_nonlisten_process != NULL) 143 if (p->group->newest_nonlisten_process != NULL)
96 newest_nonlisten_process->next_nonlisten = p; 144 p->group->newest_nonlisten_process->next_nonlisten = p;
97 newest_nonlisten_process = p; 145 p->group->newest_nonlisten_process = p;
98 146
99 if (oldest_nonlisten_process == NULL) 147 if (p->group->oldest_nonlisten_process == NULL)
100 oldest_nonlisten_process = p; 148 p->group->oldest_nonlisten_process = p;
101 } 149 }
102 150
103 static void login_process_input(void *context) 151 static void login_process_input(void *context)
104 { 152 {
105 struct login_process *p = context; 153 struct login_process *p = context;
119 i_error("login: fd_read() failed: %m"); 167 i_error("login: fd_read() failed: %m");
120 } 168 }
121 169
122 if (client_fd != -1) { 170 if (client_fd != -1) {
123 if (close(client_fd) < 0) 171 if (close(client_fd) < 0)
124 i_error("close(imap client) failed: %m"); 172 i_error("close(mail client) failed: %m");
125 } 173 }
126 174
127 login_process_destroy(p); 175 login_process_destroy(p);
128 return; 176 return;
129 } 177 }
160 auth_process_request(auth_process, p->pid, 208 auth_process_request(auth_process, p->pid,
161 req.auth_id, authreq); 209 req.auth_id, authreq);
162 } 210 }
163 } 211 }
164 212
165 static struct login_process *login_process_new(pid_t pid, int fd) 213 static struct login_process *
214 login_process_new(struct login_group *group, pid_t pid, int fd)
166 { 215 {
167 struct login_process *p; 216 struct login_process *p;
168 217
169 PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_LOGIN); 218 PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_LOGIN);
170 219
171 p = i_new(struct login_process, 1); 220 p = i_new(struct login_process, 1);
221 p->group = group;
172 p->refcount = 1; 222 p->refcount = 1;
173 p->pid = pid; 223 p->pid = pid;
174 p->fd = fd; 224 p->fd = fd;
175 p->listening = TRUE; 225 p->listening = TRUE;
176 p->io = io_add(fd, IO_READ, login_process_input, p); 226 p->io = io_add(fd, IO_READ, login_process_input, p);
177 p->output = o_stream_create_file(fd, default_pool, 227 p->output = o_stream_create_file(fd, default_pool,
178 sizeof(struct master_login_reply)*10, 228 sizeof(struct master_login_reply)*10,
179 IO_PRIORITY_DEFAULT, FALSE); 229 IO_PRIORITY_DEFAULT, FALSE);
180 230
181 hash_insert(processes, POINTER_CAST(pid), p); 231 hash_insert(processes, POINTER_CAST(pid), p);
182 listening_processes++; 232 p->group->processes++;
233 p->group->listening_processes++;
183 return p; 234 return p;
184 } 235 }
185 236
186 static void login_process_remove_from_lists(struct login_process *p) 237 static void login_process_remove_from_lists(struct login_process *p)
187 { 238 {
188 if (p == oldest_nonlisten_process) 239 if (p == p->group->oldest_nonlisten_process)
189 oldest_nonlisten_process = p->next_nonlisten; 240 p->group->oldest_nonlisten_process = p->next_nonlisten;
190 else 241 else
191 p->prev_nonlisten->next_nonlisten = p->next_nonlisten; 242 p->prev_nonlisten->next_nonlisten = p->next_nonlisten;
192 243
193 if (p == newest_nonlisten_process) 244 if (p == p->group->newest_nonlisten_process)
194 newest_nonlisten_process = p->prev_nonlisten; 245 p->group->newest_nonlisten_process = p->prev_nonlisten;
195 else 246 else
196 p->next_nonlisten->prev_nonlisten = p->prev_nonlisten; 247 p->next_nonlisten->prev_nonlisten = p->prev_nonlisten;
197 248
198 p->next_nonlisten = p->prev_nonlisten = NULL; 249 p->next_nonlisten = p->prev_nonlisten = NULL;
199 } 250 }
207 if (!p->initialized && io_loop_is_running(ioloop)) { 258 if (!p->initialized && io_loop_is_running(ioloop)) {
208 i_error("Login process died too early - shutting down"); 259 i_error("Login process died too early - shutting down");
209 io_loop_stop(ioloop); 260 io_loop_stop(ioloop);
210 } 261 }
211 if (p->listening) 262 if (p->listening)
212 listening_processes--; 263 p->group->listening_processes--;
213 264
214 o_stream_close(p->output); 265 o_stream_close(p->output);
215 io_remove(p->io); 266 io_remove(p->io);
216 if (close(p->fd) < 0) 267 if (close(p->fd) < 0)
217 i_error("close(login) failed: %m"); 268 i_error("close(login) failed: %m");
218 269
219 if (!p->listening) 270 if (!p->listening)
220 login_process_remove_from_lists(p); 271 login_process_remove_from_lists(p);
221 272
273 p->group->processes--;
222 hash_remove(processes, POINTER_CAST(p->pid)); 274 hash_remove(processes, POINTER_CAST(p->pid));
223 275
224 login_process_unref(p); 276 login_process_unref(p);
225 } 277 }
226 278
231 283
232 o_stream_unref(p->output); 284 o_stream_unref(p->output);
233 i_free(p); 285 i_free(p);
234 } 286 }
235 287
236 static pid_t create_login_process(void) 288 static pid_t create_login_process(struct login_group *group)
237 { 289 {
238 static char *argv[] = { NULL, NULL }; 290 static const char *argv[] = { NULL, NULL };
239 pid_t pid; 291 pid_t pid;
240 int fd[2]; 292 int fd[2];
241 293
242 if (set_login_process_per_connection && 294 if (group->set->process_per_connection &&
243 hash_size(processes)-listening_processes >= set_max_logging_users) { 295 group->processes - group->listening_processes >=
244 if (oldest_nonlisten_process != NULL) 296 group->set->max_logging_users) {
245 login_process_destroy(oldest_nonlisten_process); 297 if (group->oldest_nonlisten_process != NULL)
246 } 298 login_process_destroy(group->oldest_nonlisten_process);
247 299 }
248 if (set_login_uid == 0) 300
301 if (group->set->uid == 0)
249 i_fatal("Login process must not run as root"); 302 i_fatal("Login process must not run as root");
250 303
251 /* create communication to process with a socket pair */ 304 /* create communication to process with a socket pair */
252 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) { 305 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) {
253 i_error("socketpair() failed: %m"); 306 i_error("socketpair() failed: %m");
263 } 316 }
264 317
265 if (pid != 0) { 318 if (pid != 0) {
266 /* master */ 319 /* master */
267 fd_close_on_exec(fd[0], TRUE); 320 fd_close_on_exec(fd[0], TRUE);
268 login_process_new(pid, fd[0]); 321 login_process_new(group, pid, fd[0]);
269 (void)close(fd[1]); 322 (void)close(fd[1]);
270 return pid; 323 return pid;
271 } 324 }
272 325
273 /* move communication handle */ 326 /* move communication handle */
274 if (dup2(fd[1], LOGIN_MASTER_SOCKET_FD) < 0) 327 if (dup2(fd[1], LOGIN_MASTER_SOCKET_FD) < 0)
275 i_fatal("login: dup2(master) failed: %m"); 328 i_fatal("login: dup2(master) failed: %m");
276 fd_close_on_exec(LOGIN_MASTER_SOCKET_FD, FALSE); 329 fd_close_on_exec(LOGIN_MASTER_SOCKET_FD, FALSE);
277 330
278 /* move the listen handle */ 331 /* move the listen handle */
279 if (dup2(imap_fd, LOGIN_IMAP_LISTEN_FD) < 0) 332 if (dup2(*group->listen_fd, LOGIN_LISTEN_FD) < 0)
280 i_fatal("login: dup2(imap) failed: %m"); 333 i_fatal("login: dup2(listen_fd) failed: %m");
281 fd_close_on_exec(LOGIN_IMAP_LISTEN_FD, FALSE); 334 fd_close_on_exec(LOGIN_LISTEN_FD, FALSE);
282 335
283 /* move the SSL listen handle */ 336 /* move the SSL listen handle */
284 if (!set_ssl_disable) { 337 if (!set->ssl_disable) {
285 if (dup2(imaps_fd, LOGIN_IMAPS_LISTEN_FD) < 0) 338 if (dup2(*group->ssl_listen_fd, LOGIN_SSL_LISTEN_FD) < 0)
286 i_fatal("login: dup2(imaps) failed: %m"); 339 i_fatal("login: dup2(ssl_listen_fd) failed: %m");
287 } else { 340 } else {
288 if (dup2(null_fd, LOGIN_IMAPS_LISTEN_FD) < 0) 341 if (dup2(null_fd, LOGIN_SSL_LISTEN_FD) < 0)
289 i_fatal("login: dup2(imaps) failed: %m"); 342 i_fatal("login: dup2(ssl_listen_fd) failed: %m");
290 } 343 }
291 fd_close_on_exec(LOGIN_IMAPS_LISTEN_FD, FALSE); 344 fd_close_on_exec(LOGIN_SSL_LISTEN_FD, FALSE);
292 345
293 /* imap_fd and imaps_fd are closed by clean_child_process() */ 346 /* listen_fds are closed by clean_child_process() */
294 347
295 (void)close(fd[0]); 348 (void)close(fd[0]);
296 (void)close(fd[1]); 349 (void)close(fd[1]);
297 350
298 clean_child_process(); 351 clean_child_process();
299 352
300 /* setup access environment - needs to be done after 353 /* setup access environment - needs to be done after
301 clean_child_process() since it clears environment */ 354 clean_child_process() since it clears environment */
302 restrict_access_set_env(set_login_user, set_login_uid, set_login_gid, 355 restrict_access_set_env(group->set->user,
303 set_login_chroot ? set_login_dir : NULL); 356 group->set->uid, set->login_gid,
304 357 set->login_chroot ? set->login_dir : NULL);
305 if (!set_login_chroot) { 358
359 if (!set->login_chroot) {
306 /* no chrooting, but still change to the directory */ 360 /* no chrooting, but still change to the directory */
307 if (chdir(set_login_dir) < 0) 361 if (chdir(set->login_dir) < 0)
308 i_fatal("chdir(%s) failed: %m", set_login_dir); 362 i_fatal("chdir(%s) failed: %m", set->login_dir);
309 } 363 }
310 364
311 if (!set_ssl_disable) { 365 if (!set->ssl_disable) {
312 env_put(t_strconcat("SSL_CERT_FILE=", set_ssl_cert_file, NULL)); 366 env_put(t_strconcat("SSL_CERT_FILE=",
313 env_put(t_strconcat("SSL_KEY_FILE=", set_ssl_key_file, NULL)); 367 set->ssl_cert_file, NULL));
368 env_put(t_strconcat("SSL_KEY_FILE=", set->ssl_key_file, NULL));
314 env_put(t_strconcat("SSL_PARAM_FILE=", 369 env_put(t_strconcat("SSL_PARAM_FILE=",
315 set_ssl_parameters_file, NULL)); 370 set->ssl_parameters_file, NULL));
316 } 371 }
317 372
318 if (set_disable_plaintext_auth) 373 if (set->disable_plaintext_auth)
319 env_put("DISABLE_PLAINTEXT_AUTH=1"); 374 env_put("DISABLE_PLAINTEXT_AUTH=1");
320 if (set_verbose_proctitle) 375 if (set->verbose_proctitle)
321 env_put("VERBOSE_PROCTITLE=1"); 376 env_put("VERBOSE_PROCTITLE=1");
322 377
323 if (set_login_process_per_connection) { 378 if (group->set->process_per_connection) {
324 env_put("PROCESS_PER_CONNECTION=1"); 379 env_put("PROCESS_PER_CONNECTION=1");
325 env_put("MAX_LOGGING_USERS=1"); 380 env_put("MAX_LOGGING_USERS=1");
326 } else { 381 } else {
327 env_put(t_strdup_printf("MAX_LOGGING_USERS=%u", 382 env_put(t_strdup_printf("MAX_LOGGING_USERS=%u",
328 set_max_logging_users)); 383 group->set->max_logging_users));
329 } 384 }
330 385
331 env_put(t_strdup_printf("PROCESS_UID=%s", dec2str(getpid()))); 386 env_put(t_strdup_printf("PROCESS_UID=%s", dec2str(getpid())));
332 387
333 restrict_process_size(set_login_process_size); 388 restrict_process_size(group->set->process_size);
334 389
335 /* make sure we don't leak syslog fd, but do it last so that 390 /* make sure we don't leak syslog fd, but do it last so that
336 any errors above will be logged */ 391 any errors above will be logged */
337 closelog(); 392 closelog();
338 393
339 /* hide the path, it's ugly */ 394 /* hide the path, it's ugly */
340 argv[0] = strrchr(set_login_executable, '/'); 395 argv[0] = strrchr(group->set->executable, '/');
341 if (argv[0] == NULL) argv[0] = set_login_executable; else argv[0]++; 396 if (argv[0] == NULL) argv[0] = group->set->executable; else argv[0]++;
342 397
343 execv(set_login_executable, (char **) argv); 398 execv(group->set->executable, (char **) argv);
344 399
345 i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", argv[0]); 400 i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", argv[0]);
346 return -1; 401 return -1;
347 } 402 }
348 403
349 void login_process_abormal_exit(pid_t pid __attr_unused__) 404 void login_process_abormal_exit(pid_t pid)
350 { 405 {
406 struct login_process *p;
407
351 /* don't start raising the process count if they're dying all 408 /* don't start raising the process count if they're dying all
352 the time */ 409 the time */
353 wanted_processes_count = 0; 410 p = hash_lookup(processes, POINTER_CAST(pid));
411 if (p != NULL)
412 p->group->wanted_processes_count = 0;
354 } 413 }
355 414
356 static void login_hash_destroy(void *key __attr_unused__, void *value, 415 static void login_hash_destroy(void *key __attr_unused__, void *value,
357 void *context __attr_unused__) 416 void *context __attr_unused__)
358 { 417 {
361 420
362 void login_processes_destroy_all(void) 421 void login_processes_destroy_all(void)
363 { 422 {
364 hash_foreach(processes, login_hash_destroy, NULL); 423 hash_foreach(processes, login_hash_destroy, NULL);
365 424
366 /* don't double their amount when restarting */ 425 while (login_groups != NULL) {
367 wanted_processes_count = 0; 426 struct login_group *group = login_groups;
427
428 login_groups = group->next;
429 login_group_destroy(group);
430 }
431 }
432
433 static void login_group_start_missings(struct login_group *group)
434 {
435 if (!group->set->process_per_connection) {
436 /* create max. one process every second, that way if it keeps
437 dying all the time we don't eat all cpu with fork()ing. */
438 if (group->listening_processes < group->set->processes_count)
439 (void)create_login_process(group);
440 return;
441 }
442
443 /* we want to respond fast when multiple clients are connecting
444 at once, but we also want to prevent fork-bombing. use the
445 same method as apache: check once a second if we need new
446 processes. if yes and we've used all the existing processes,
447 double their amount (unless we've hit the high limit).
448 Then for each second that didn't use all existing processes,
449 drop the max. process count by one. */
450 if (group->wanted_processes_count < group->set->processes_count)
451 group->wanted_processes_count = group->set->processes_count;
452 else if (group->listening_processes == 0)
453 group->wanted_processes_count *= 2;
454 else if (group->wanted_processes_count > group->set->processes_count)
455 group->wanted_processes_count--;
456
457 if (group->wanted_processes_count > group->set->max_processes_count)
458 group->wanted_processes_count = group->set->max_processes_count;
459
460 while (group->listening_processes < group->wanted_processes_count)
461 (void)create_login_process(group);
368 } 462 }
369 463
370 static void 464 static void
371 login_processes_start_missing(void *context __attr_unused__) 465 login_processes_start_missing(void *context __attr_unused__)
372 { 466 {
373 if (!set_login_process_per_connection) { 467 struct login_group *group;
374 /* create max. one process every second, that way if it keeps 468 struct login_settings *login;
375 dying all the time we don't eat all cpu with fork()ing. */ 469
376 if (listening_processes < set_login_processes_count) 470 if (login_groups == NULL) {
377 (void)create_login_process(); 471 for (login = set->logins; login != NULL; login = login->next)
378 } else { 472 login_group_create(login);
379 /* we want to respond fast when multiple clients are connecting 473 }
380 at once, but we also want to prevent fork-bombing. use the 474
381 same method as apache: check once a second if we need new 475 for (group = login_groups; group != NULL; group = group->next)
382 processes. if yes and we've used all the existing processes, 476 login_group_start_missings(group);
383 double their amount (unless we've hit the high limit).
384 Then for each second that didn't use all existing processes,
385 drop the max. process count by one. */
386 if (wanted_processes_count < set_login_processes_count)
387 wanted_processes_count = set_login_processes_count;
388 else if (listening_processes == 0)
389 wanted_processes_count *= 2;
390 else if (wanted_processes_count > set_login_processes_count)
391 wanted_processes_count--;
392
393 if (wanted_processes_count > set_login_max_processes_count)
394 wanted_processes_count = set_login_max_processes_count;
395
396 while (listening_processes < wanted_processes_count)
397 (void)create_login_process();
398 }
399 } 477 }
400 478
401 void login_processes_init(void) 479 void login_processes_init(void)
402 { 480 {
403 auth_id_counter = 0; 481 auth_id_counter = 0;
404 listening_processes = 0; 482 login_groups = NULL;
405 wanted_processes_count = 0;
406 oldest_nonlisten_process = newest_nonlisten_process = NULL;
407 483
408 processes = hash_create(default_pool, default_pool, 128, NULL, NULL); 484 processes = hash_create(default_pool, default_pool, 128, NULL, NULL);
409 to = timeout_add(1000, login_processes_start_missing, NULL); 485 to = timeout_add(1000, login_processes_start_missing, NULL);
410 } 486 }
411 487