|
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 |