pop3d.c
changeset 0 9e2cb1ed20b1
child 5 9e370734cb36
equal deleted inserted replaced
-1:000000000000 0:9e2cb1ed20b1
       
     1 /*
       
     2  * Copyright (c) 2014 Sunil Nimmagadda <sunil@nimmagadda.net>
       
     3  *
       
     4  * Permission to use, copy, modify, and distribute this software for any
       
     5  * purpose with or without fee is hereby granted, provided that the above
       
     6  * copyright notice and this permission notice appear in all copies.
       
     7  *
       
     8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       
     9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
       
    10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
       
    11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
       
    12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
       
    13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
       
    14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
       
    15  */
       
    16 
       
    17 #include <sys/param.h>
       
    18 #include <sys/types.h>
       
    19 #include <sys/socket.h>
       
    20 #include <sys/time.h>
       
    21 #include <sys/wait.h>
       
    22 
       
    23 #include <bsd_auth.h>
       
    24 #include <err.h>
       
    25 #include <event.h>
       
    26 #include <login_cap.h>
       
    27 #include <pwd.h>
       
    28 #include <signal.h>
       
    29 #include <stdio.h>
       
    30 #include <stdlib.h>
       
    31 #include <string.h>
       
    32 #include <syslog.h>
       
    33 #include <unistd.h>
       
    34 
       
    35 #include "imsgev.h"
       
    36 #include "pop3d.h"
       
    37 
       
    38 #define	MBOX_PATH	"/var/mail/%u"
       
    39 #define MAILDIR_PATH	"~/Maildir"
       
    40 #define	POP3D_USER	"_pop3d"
       
    41 
       
    42 static void authenticate(struct imsgev *, struct imsg *);
       
    43 static void pop3e_imsgev(struct imsgev *, int , struct imsg *);
       
    44 static void needfd(struct imsgev *);
       
    45 static void sig_handler(int, short, void *);
       
    46 static enum m_type m_type(const char *);
       
    47 static void usage(void);
       
    48 
       
    49 static struct imsgev	iev_pop3e;
       
    50 static pid_t		pop3e_pid;
       
    51 static const char	*mpath = MBOX_PATH;
       
    52 static int		mtype = M_MBOX;
       
    53 
       
    54 int
       
    55 main(int argc, char *argv[])
       
    56 {
       
    57 	struct passwd	*pw;
       
    58 	struct event	ev_sigint, ev_sigterm, ev_sighup, ev_sigchld;
       
    59 	const char	*mtype_str = "mbox";
       
    60 	int		ch, d = 0, pair[2];
       
    61 
       
    62 	while ((ch = getopt(argc, argv, "dp:t:")) != -1) {
       
    63 		switch (ch) {
       
    64 		case 'd':
       
    65 			d = 1;
       
    66 			break;
       
    67 		case 'p':
       
    68 			mpath = optarg;
       
    69 			break;
       
    70 		case 't':
       
    71 			if ((mtype = m_type(optarg)) == -1)
       
    72 				errx(1, "%s invalid argument", optarg);
       
    73 			if (mtype == M_MAILDIR)
       
    74 				mpath = MAILDIR_PATH;
       
    75 			mtype_str = optarg;
       
    76 			break;
       
    77 		default:
       
    78 			usage();
       
    79 		}
       
    80 	}
       
    81 
       
    82 	argc -= optind;
       
    83 	argv += optind;
       
    84 	if (argc > 0 || *argv)
       
    85 		usage();
       
    86 
       
    87 	log_init(d);
       
    88 	if (geteuid())
       
    89 		fatalx("need root privileges");
       
    90 
       
    91 	if (!d && daemon(1, 0) == -1)
       
    92 		fatal("failed to daemonize");
       
    93 
       
    94 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) == -1)
       
    95 		fatal("socketpair");
       
    96 
       
    97 	set_nonblocking(pair[0]);
       
    98 	set_nonblocking(pair[1]);
       
    99 	if ((pw = getpwnam(POP3D_USER)) == NULL)
       
   100 		fatalx("main: getpwnam " POP3D_USER);
       
   101 
       
   102 	pop3e_pid = pop3_main(pair, pw);
       
   103 	close(pair[1]);
       
   104 	setproctitle("[priv]");
       
   105 	logit(LOG_INFO, "pop3d ready; type:%s, path:%s", mtype_str, mpath);
       
   106 	event_init();
       
   107 	signal_set(&ev_sigint, SIGINT, sig_handler, NULL);
       
   108 	signal_set(&ev_sighup, SIGHUP, sig_handler, NULL);
       
   109 	signal_set(&ev_sigterm, SIGTERM, sig_handler, NULL);
       
   110 	signal_set(&ev_sigchld, SIGCHLD, sig_handler, NULL);
       
   111 	signal_add(&ev_sigint, NULL);
       
   112 	signal_add(&ev_sighup, NULL);
       
   113 	signal_add(&ev_sigterm, NULL);
       
   114 	signal_add(&ev_sigchld, NULL);
       
   115 	imsgev_init(&iev_pop3e, pair[0], NULL, pop3e_imsgev, needfd);
       
   116 	if (event_dispatch() < 0)
       
   117 		fatal("event_dispatch");
       
   118 
       
   119 	logit(LOG_INFO, "pop3d exiting");
       
   120 	return (0);
       
   121 }
       
   122 
       
   123 static void
       
   124 pop3e_imsgev(struct imsgev *iev, int code, struct imsg *imsg)
       
   125 {
       
   126 	switch (code) {
       
   127 	case IMSGEV_IMSG:
       
   128 		switch (imsg->hdr.type) {
       
   129 		case IMSG_AUTH:
       
   130 			authenticate(iev, imsg);
       
   131 			break;
       
   132 		default:
       
   133 			logit(LOG_DEBUG, "%s: unexpected imsg %u",
       
   134 			    __func__, imsg->hdr.type);
       
   135 			break;
       
   136 		}
       
   137 		break;
       
   138 	case IMSGEV_EREAD:
       
   139 	case IMSGEV_EWRITE:
       
   140 	case IMSGEV_EIMSG:
       
   141 		fatal("pop3d: imsgev read/write error");
       
   142 		break;
       
   143 	case IMSGEV_DONE:
       
   144 		event_loopexit(NULL);
       
   145 		break;
       
   146 	}
       
   147 }
       
   148 
       
   149 static void
       
   150 authenticate(struct imsgev *iev, struct imsg *imsg)
       
   151 {
       
   152 	struct auth_req	*req = imsg->data;
       
   153 	struct passwd	*pw;
       
   154 	int		pair[2];
       
   155 
       
   156 	if (auth_userokay(req->user, NULL, "auth-pop3", req->pass) == 0) {
       
   157 		logit(LOG_INFO, "%u: auth [%s] failed",
       
   158 		    imsg->hdr.peerid, req->user);
       
   159 		pair[0] = -1;
       
   160 		goto end;
       
   161 	}
       
   162 
       
   163 	logit(LOG_INFO, "%u: auth [%s] passed", imsg->hdr.peerid,
       
   164 	    req->user);
       
   165 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) == -1)
       
   166 		fatal("socketpair");
       
   167 
       
   168 	set_nonblocking(pair[0]);
       
   169 	set_nonblocking(pair[1]);
       
   170 	if ((pw = getpwnam(req->user)) == NULL)
       
   171 		fatalx("authenticate: getpwnam");
       
   172 
       
   173 	maildrop_init(imsg->hdr.peerid, pair, pw, mtype, mpath);
       
   174 	close(pair[1]);
       
   175 
       
   176 end:
       
   177 	imsgev_xcompose(iev, IMSG_AUTH, imsg->hdr.peerid, 0,
       
   178 	    pair[0], NULL, 0, "authenticate");
       
   179 }
       
   180 
       
   181 static void
       
   182 needfd(struct imsgev *iev)
       
   183 {
       
   184 	fatalx("pop3d should never need an fd");
       
   185 }
       
   186 
       
   187 static void
       
   188 sig_handler(int sig, short event, void *arg)
       
   189 {
       
   190 	int status;
       
   191 
       
   192 	switch (sig) {
       
   193 	case SIGINT:
       
   194 	case SIGHUP:
       
   195 	case SIGTERM:
       
   196 		imsgev_clear(&iev_pop3e);
       
   197 		imsgev_close(&iev_pop3e);
       
   198 		event_loopexit(NULL);
       
   199 		break;
       
   200 	case SIGCHLD:
       
   201 		if (waitpid(pop3e_pid, &status, WNOHANG) > 0)
       
   202 			if (WIFEXITED(status) || WIFSIGNALED(status)) {
       
   203 				logit(LOG_ERR, "Lost pop3 engine");
       
   204 				event_loopexit(NULL);
       
   205 			}
       
   206 		break;
       
   207 	}
       
   208 }
       
   209 
       
   210 static enum m_type
       
   211 m_type(const char *str)
       
   212 {
       
   213 	if (strcasecmp(str, "mbox") == 0)
       
   214 		return M_MBOX;
       
   215 
       
   216 	if (strcasecmp(str, "maildir") == 0)
       
   217 		return M_MAILDIR;
       
   218 
       
   219 	return (-1);
       
   220 }
       
   221 
       
   222 static void
       
   223 usage(void)
       
   224 {
       
   225 	extern char *__progname;
       
   226 
       
   227 	fprintf(stderr, "usage: %s [-d] [-p path] [-t type]\n", __progname);
       
   228 	exit(EXIT_FAILURE);
       
   229 }
       
   230