Mercurial > dovecot > original-hg > dovecot-1.2
view src/master/login-process.c @ 100:867ec80dbf42 HEAD
Custom flags are now shown in FLAGS and PERMANENTFLAGS lists after SELECT.
It also warns if there's for some reason a duplicate index number in custom
flags file.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 29 Aug 2002 22:21:51 +0300 |
parents | 82b7de533f98 |
children | db6e288be0e9 |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "common.h" #include "network.h" #include "iobuffer.h" #include "fdpass.h" #include "restrict-access.h" #include "login-process.h" #include "auth-process.h" #include "master-interface.h" #include <stdlib.h> #include <unistd.h> #include <syslog.h> typedef struct { int refcount; pid_t pid; int fd; IO io; IOBuffer *outbuf; unsigned int destroyed:1; } LoginProcess; typedef struct { LoginProcess *process; int login_id; int auth_id; int fd; char login_tag[LOGIN_TAG_SIZE]; } LoginAuthRequest; static int auth_id_counter; static Timeout to; static HashTable *processes = NULL; static void login_process_destroy(LoginProcess *p); static void login_process_unref(LoginProcess *p); static void auth_callback(AuthCookieReplyData *cookie_reply, void *context) { const char *env[] = { "MAIL", NULL, "LOGIN_TAG", NULL, NULL }; LoginAuthRequest *request = context; LoginProcess *process; MasterReply reply; env[1] = cookie_reply->mail; env[3] = request->login_tag; if (cookie_reply == NULL || !cookie_reply->success) reply.result = MASTER_RESULT_FAILURE; else { reply.result = create_imap_process(request->fd, cookie_reply->user, cookie_reply->uid, cookie_reply->gid, cookie_reply->home, cookie_reply->chroot, env); } /* reply to login */ reply.id = request->login_id; process = request->process; if (io_buffer_send(process->outbuf, &reply, sizeof(reply)) < 0) login_process_destroy(process); (void)close(request->fd); login_process_unref(process); i_free(request); } static void login_process_input(void *context, int fd __attr_unused__, IO io __attr_unused__) { LoginProcess *p = context; AuthProcess *auth_process; LoginAuthRequest *authreq; MasterRequest req; int client_fd, ret; ret = fd_read(p->fd, &req, sizeof(req), &client_fd); if (ret != sizeof(req)) { if (ret == 0) { /* disconnected, ie. the login process died */ } else if (ret > 0) { /* req wasn't fully read */ i_error("login: fd_read() couldn't read all req"); } else { i_error("login: fd_read() failed: %m"); } login_process_destroy(p); return; } /* login process isn't trusted, validate all data to make sure it's not trying to exploit us */ if (!VALIDATE_STR(req.login_tag)) { i_error("login: Received corrupted data"); login_process_destroy(p); return; } /* ask the cookie from the auth process */ authreq = i_new(LoginAuthRequest, 1); p->refcount++; authreq->process = p; authreq->login_id = req.id; authreq->auth_id = ++auth_id_counter; authreq->fd = client_fd; strcpy(authreq->login_tag, req.login_tag); auth_process = auth_process_find(req.auth_process); if (auth_process == NULL) { i_error("login: Authentication process %u doesn't exist", req.auth_process); auth_callback(NULL, &authreq); } else { auth_process_request(auth_process, authreq->auth_id, req.cookie, auth_callback, authreq); } } static LoginProcess *login_process_new(pid_t pid, int fd) { LoginProcess *p; PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_LOGIN); p = i_new(LoginProcess, 1); p->refcount = 1; p->pid = pid; p->fd = fd; p->io = io_add(fd, IO_READ, login_process_input, p); p->outbuf = io_buffer_create(fd, default_pool, IO_PRIORITY_DEFAULT, sizeof(MasterReply)*10); hash_insert(processes, INT_TO_POINTER(pid), p); return p; } static void login_process_destroy(LoginProcess *p) { if (p->destroyed) return; p->destroyed = TRUE; io_buffer_close(p->outbuf); io_remove(p->io); (void)close(p->fd); hash_remove(processes, INT_TO_POINTER(p->pid)); login_process_unref(p); } static void login_process_unref(LoginProcess *p) { if (--p->refcount > 0) return; io_buffer_destroy(p->outbuf); i_free(p); } static pid_t create_login_process(void) { static const char *argv[] = { NULL, NULL }; pid_t pid; int fd[2]; if (set_login_uid == 0) i_fatal("Login process must not run as root"); /* create communication to process with a socket pair */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) { i_error("socketpair() failed: %m"); return -1; } pid = fork(); if (pid < 0) { (void)close(fd[0]); (void)close(fd[1]); i_error("fork() failed: %m"); return -1; } if (pid != 0) { /* master */ login_process_new(pid, fd[0]); (void)close(fd[1]); return pid; } /* move communication handle */ if (dup2(fd[1], LOGIN_MASTER_SOCKET_FD) < 0) i_fatal("login: dup2() failed: %m"); /* move the listen handle */ if (dup2(imap_fd, LOGIN_IMAP_LISTEN_FD) < 0) i_fatal("login: dup2() failed: %m"); /* move the SSL listen handle */ if (dup2(imaps_fd, LOGIN_IMAPS_LISTEN_FD) < 0) i_fatal("login: dup2() failed: %m"); /* imap_fd and imaps_fd are closed by clean_child_process() */ (void)close(fd[0]); (void)close(fd[1]); clean_child_process(); /* setup access environment - needs to be done after clean_child_process() since it clears environment */ restrict_access_set_env(set_login_user, set_login_uid, set_login_gid, set_login_chroot ? set_login_dir : NULL); if (!set_login_chroot) { /* no chrooting, but still change to the directory */ if (chdir(set_login_dir) < 0) { i_fatal("chdir(%s) failed: %m", set_login_dir); } } if (set_ssl_cert_file != NULL) { putenv((char *) t_strconcat("SSL_CERT_FILE=", set_ssl_cert_file, NULL)); } if (set_ssl_key_file != NULL) { putenv((char *) t_strconcat("SSL_KEY_FILE=", set_ssl_key_file, NULL)); } if (set_disable_plaintext_auth) putenv("DISABLE_PLAINTEXT_AUTH=1"); putenv((char *) t_strdup_printf("MAX_LOGGING_USERS=%d", set_max_logging_users)); /* hide the path, it's ugly */ argv[0] = strrchr(set_login_executable, '/'); if (argv[0] == NULL) argv[0] = set_login_executable; else argv[0]++; execv(set_login_executable, (char **) argv); i_fatal("execv(%s) failed: %m", argv[0]); return -1; } static void login_hash_cleanup(void *key __attr_unused__, void *value, void *context __attr_unused__) { LoginProcess *p = value; (void)close(p->fd); } void login_processes_cleanup(void) { hash_foreach(processes, login_hash_cleanup, NULL); } static void login_processes_start_missing(void *context __attr_unused__, Timeout timeout __attr_unused__) { /* create max. one process every second, that way if it keeps dying all the time we don't eat all cpu with fork()ing. */ if (hash_size(processes) < set_login_processes_count) (void)create_login_process(); } void login_processes_init(void) { auth_id_counter = 0; processes = hash_create(default_pool, 128, NULL, NULL); to = timeout_add(1000, login_processes_start_missing, NULL); } static void login_hash_destroy(void *key __attr_unused__, void *value, void *context __attr_unused__) { login_process_destroy(value); } void login_processes_deinit(void) { timeout_remove(to); hash_foreach(processes, login_hash_destroy, NULL); hash_destroy(processes); }