diff -r 000000000000 -r cb3d0d99955c pop3d.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pop3d.c Tue Apr 01 20:19:43 2014 +0500 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2014 Sunil Nimmagadda + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imsgev.h" +#include "pop3d.h" + +#define MBOX_PATH "/var/mail/%u" +#define MAILDIR_PATH "~/Maildir" +#define POP3D_USER "_pop3d" + +static void authenticate(struct imsgev *, struct imsg *); +static void pop3e_imsgev(struct imsgev *, int , struct imsg *); +static void needfd(struct imsgev *); +static void sig_handler(int, short, void *); +static enum m_type m_type(const char *); +static void usage(void); + +static struct imsgev iev_pop3e; +static pid_t pop3e_pid; +static const char *mpath = MBOX_PATH; +static int mtype = M_MBOX; + +int +main(int argc, char *argv[]) +{ + struct passwd *pw; + struct event ev_sigint, ev_sigterm, ev_sighup, ev_sigchld; + const char *mtype_str = "mbox"; + int ch, d = 0, pair[2]; + + while ((ch = getopt(argc, argv, "dp:t:")) != -1) { + switch (ch) { + case 'd': + d = 1; + break; + case 'p': + mpath = optarg; + break; + case 't': + if ((mtype = m_type(optarg)) == -1) + errx(1, "%s invalid argument", optarg); + if (mtype == M_MAILDIR) + mpath = MAILDIR_PATH; + mtype_str = optarg; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc > 0 || *argv) + usage(); + + log_init(d); + if (geteuid()) + fatalx("need root privileges"); + + if (!d && daemon(1, 0) == -1) + fatal("failed to daemonize"); + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) == -1) + fatal("socketpair"); + + set_nonblocking(pair[0]); + set_nonblocking(pair[1]); + if ((pw = getpwnam(POP3D_USER)) == NULL) + fatalx("main: getpwnam " POP3D_USER); + + pop3e_pid = pop3_main(pair, pw); + close(pair[1]); + setproctitle("[priv]"); + logit(LOG_INFO, "pop3d ready; type:%s, path:%s", mtype_str, mpath); + event_init(); + signal_set(&ev_sigint, SIGINT, sig_handler, NULL); + signal_set(&ev_sighup, SIGHUP, sig_handler, NULL); + signal_set(&ev_sigterm, SIGTERM, sig_handler, NULL); + signal_set(&ev_sigchld, SIGCHLD, sig_handler, NULL); + signal_add(&ev_sigint, NULL); + signal_add(&ev_sighup, NULL); + signal_add(&ev_sigterm, NULL); + signal_add(&ev_sigchld, NULL); + imsgev_init(&iev_pop3e, pair[0], NULL, pop3e_imsgev, needfd); + if (event_dispatch() < 0) + fatal("event_dispatch"); + + logit(LOG_INFO, "pop3d exiting"); + return (0); +} + +static void +pop3e_imsgev(struct imsgev *iev, int code, struct imsg *imsg) +{ + switch (code) { + case IMSGEV_IMSG: + switch (imsg->hdr.type) { + case IMSG_AUTH: + authenticate(iev, imsg); + break; + default: + logit(LOG_DEBUG, "%s: unexpected imsg %u", + __func__, imsg->hdr.type); + break; + } + break; + case IMSGEV_EREAD: + case IMSGEV_EWRITE: + case IMSGEV_EIMSG: + fatal("pop3d: imsgev read/write error"); + break; + case IMSGEV_DONE: + event_loopexit(NULL); + break; + } +} + +static void +authenticate(struct imsgev *iev, struct imsg *imsg) +{ + struct auth_req *req = imsg->data; + struct passwd *pw; + int pair[2]; + + if (auth_userokay(req->user, NULL, "auth-pop3", req->pass) == 0) { + logit(LOG_INFO, "%u: auth [%s] failed", + imsg->hdr.peerid, req->user); + pair[0] = -1; + goto end; + } + + logit(LOG_INFO, "%u: auth [%s] passed", imsg->hdr.peerid, + req->user); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) == -1) + fatal("socketpair"); + + set_nonblocking(pair[0]); + set_nonblocking(pair[1]); + if ((pw = getpwnam(req->user)) == NULL) + fatalx("authenticate: getpwnam"); + + if (maildrop_init(imsg->hdr.peerid, pair, pw, mtype, mpath) == -1) { + logit(LOG_INFO, "%u: unable to fork maildrop process", + imsg->hdr.peerid); + pair[0] = -1; + goto end; + } + + close(pair[1]); +end: + imsgev_xcompose(iev, IMSG_AUTH, imsg->hdr.peerid, 0, + pair[0], NULL, 0, "authenticate"); +} + +static void +needfd(struct imsgev *iev) +{ + fatalx("pop3d should never need an fd"); +} + +static void +sig_handler(int sig, short event, void *arg) +{ + int status; + + switch (sig) { + case SIGINT: + case SIGHUP: + case SIGTERM: + imsgev_clear(&iev_pop3e); + imsgev_close(&iev_pop3e); + event_loopexit(NULL); + break; + case SIGCHLD: + if (waitpid(pop3e_pid, &status, WNOHANG) > 0) + if (WIFEXITED(status) || WIFSIGNALED(status)) { + logit(LOG_ERR, "Lost pop3 engine"); + event_loopexit(NULL); + } + break; + } +} + +static enum m_type +m_type(const char *str) +{ + if (strcasecmp(str, "mbox") == 0) + return M_MBOX; + + if (strcasecmp(str, "maildir") == 0) + return M_MAILDIR; + + return (-1); +} + +static void +usage(void) +{ + extern char *__progname; + + fprintf(stderr, "usage: %s [-d] [-p path] [-t type]\n", __progname); + exit(EXIT_FAILURE); +} +