1 /* pop3d.c -- POP3 server protocol parsing
2 *
3 * Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * 3. The name "Carnegie Mellon University" must not be used to
18 * endorse or promote products derived from this software without
19 * prior written permission. For permission or any legal
20 * details, please contact
21 * Carnegie Mellon University
22 * Center for Technology Transfer and Enterprise Creation
23 * 4615 Forbes Avenue
24 * Suite 302
25 * Pittsburgh, PA 15213
26 * (412) 268-7393, fax: (412) 268-7395
27 * innovation@andrew.cmu.edu
28 *
29 * 4. Redistributions of any form whatsoever must retain the following
30 * acknowledgment:
31 * "This product includes software developed by Computing Services
32 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33 *
34 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41 */
42
43 #include <config.h>
44
45
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #include <stdio.h>
50 #include <string.h>
51 #include <fcntl.h>
52 #include <signal.h>
53 #include <sys/types.h>
54 #include <sys/param.h>
55 #include <sysexits.h>
56 #include <syslog.h>
57 #include <netdb.h>
58 #include <sys/socket.h>
59 #include <netinet/in.h>
60 #include <arpa/inet.h>
61 #include "prot.h"
62
63 #include <sasl/sasl.h>
64 #include <sasl/saslutil.h>
65
66 #include "assert.h"
67 #include "acl.h"
68 #ifdef USE_AUTOCREATE
69 #include "autocreate.h"
70 #endif
71 #include "util.h"
72 #include "auth.h"
73 #include "global.h"
74 #include "tls.h"
75
76 #include "imapd.h"
77 #include "mailbox.h"
78 #include "mboxevent.h"
79 #include "version.h"
80 #include "xmalloc.h"
81 #include "xstrlcpy.h"
82 #include "mboxlist.h"
83 #include "idle.h"
84 #include "telemetry.h"
85 #include "backend.h"
86 #include "proc.h"
87 #include "proxy.h"
88 #include "sync_support.h"
89 #include "seen.h"
90 #include "userdeny.h"
91
92 /* generated headers are not necessarily in current directory */
93 #include "imap/imap_err.h"
94
95 #include "statuscache.h"
96
97 #include "iostat.h"
98
99 #ifndef MAXHOSTNAMELEN
100 #define MAXHOSTNAMELEN 256
101 #endif
102
103 #ifdef HAVE_KRB
104 /* kerberos des is purported to conflict with OpenSSL DES */
105 #define DES_DEFS
106 #include <krb.h>
107
108 /* MIT's kpop authentication kludge */
109 char klrealm[REALM_SZ];
110 AUTH_DAT kdata;
111 #endif /* HAVE_KRB */
112 static int kflag = 0;
113
114 extern int optind;
115 extern char *optarg;
116 extern int opterr;
117
118
119
120 #ifdef HAVE_SSL
121 static SSL *tls_conn;
122 #endif /* HAVE_SSL */
123
124 static sasl_conn_t *popd_saslconn; /* the sasl connection context */
125
126 static int popd_timeout;
127 static char *popd_userid = 0, *popd_subfolder = 0;
128 static struct mailbox *popd_mailbox = NULL;
129 static struct auth_state *popd_authstate = 0;
130 static int config_popuseacl, config_popuseimapflags;
131 static int popd_haveaddr = 0;
132 static const char *popd_clienthost = "[local]";
133 static struct protstream *popd_out = NULL;
134 static struct protstream *popd_in = NULL;
135 static int popd_logfd = -1;
136 static unsigned popd_exists = 0;
137 static time_t popd_login_time;
138 static int count_retr = 0;
139 static int count_top = 0;
140 static int count_dele = 0;
141 static struct msg {
142 uint32_t uid;
143 uint32_t recno;
144 uint32_t size;
145 int deleted:1;
146 int seen:1;
147 } *popd_map = NULL;
148
149 static struct io_count *io_count_start;
150 static struct io_count *io_count_stop;
151
152 static sasl_ssf_t extprops_ssf = 0;
153 static int pop3s = 0;
154 static int popd_starttls_done = 0;
155 static int popd_tls_required = 0;
156
157 static int popd_myrights;
158
159 /* the sasl proxy policy context */
160 static struct proxy_context popd_proxyctx = {
161 0, 1, &popd_authstate, NULL, NULL
162 };
163
164 /* signal to config.c */
165 const int config_need_data = CONFIG_NEED_PARTITION_DATA;
166
167 /* current namespace */
168 static struct namespace popd_namespace;
169
170 /* PROXY stuff */
171 struct backend *backend = NULL;
172
173 static struct protocol_t pop3_protocol =
174 { "pop3", "pop", TYPE_STD,
175 { { { 0, "+OK " },
176 { "CAPA", NULL, ".", NULL,
177 CAPAF_ONE_PER_LINE,
178 { { "SASL", CAPA_AUTH },
179 { "STLS", CAPA_STARTTLS },
180 { NULL, 0 } } },
181 { "STLS", "+OK", "-ERR", 0 },
182 { "AUTH", 255, 0, "+OK", "-ERR", "+ ", "*", NULL, 0 },
183 { NULL, NULL, NULL },
184 { "NOOP", NULL, "+OK" },
185 { "QUIT", NULL, "+OK" } } }
186 };
187
188 static void bitpipe(void);
189 /* end PROXY stuff */
190
191 static char popd_apop_chal[45 + MAXHOSTNAMELEN + 1]; /* <rand.time@hostname> */
192 static void cmd_apop(char *response);
193
194 static void cmd_auth(char *arg);
195 static void cmd_capa(void);
196 static void cmd_pass(char *pass);
197 static void cmd_user(char *user);
198 static void cmd_starttls(int pop3s);
199 static int blat(int msg, int lines);
200 static int openinbox(void);
201 static void cmdloop(void);
202 static void kpop(void);
203 static unsigned parse_msgno(char **ptr);
204 static void uidl_msg(uint32_t msgno);
205 static int msg_exists_or_err(uint32_t msgno);
206 static int update_seen(void);
207 static void usage(void);
208 void shut_down(int code) __attribute__ ((noreturn));
209
210 extern int saslserver(sasl_conn_t *conn, const char *mech,
211 const char *init_resp, const char *resp_prefix,
212 const char *continuation, const char *empty_chal,
213 struct protstream *pin, struct protstream *pout,
214 int *sasl_result, char **success_data);
215
216 /* Enable the resetting of a sasl_conn_t */
217 static int reset_saslconn(sasl_conn_t **conn);
218
219 static struct saslprops_t saslprops = SASLPROPS_INITIALIZER;
220
popd_canon_user(sasl_conn_t * conn,void * context,const char * user,unsigned ulen,unsigned flags,const char * user_realm,char * out,unsigned out_max,unsigned * out_ulen)221 static int popd_canon_user(sasl_conn_t *conn, void *context,
222 const char *user, unsigned ulen,
223 unsigned flags, const char *user_realm,
224 char *out, unsigned out_max, unsigned *out_ulen)
225 {
226 char userbuf[MAX_MAILBOX_BUFFER], *p;
227 size_t n;
228 int r;
229
230 if (!ulen) ulen = strlen(user);
231
232 if (config_getswitch(IMAPOPT_POPSUBFOLDERS)) {
233 /* make a working copy of the auth[z]id */
234 if (ulen >= MAX_MAILBOX_BUFFER) {
235 sasl_seterror(conn, 0, "buffer overflow while canonicalizing");
236 return SASL_BUFOVER;
237 }
238
239 memcpy(userbuf, user, ulen);
240 userbuf[ulen] = '\0';
241 user = userbuf;
242
243 /* See if we're trying to access a subfolder */
244 if ((p = strchr(userbuf, '+'))) {
245 n = config_virtdomains ? strcspn(p, "@") : strlen(p);
246
247 /* make a copy of the subfolder */
248 if (popd_subfolder) free(popd_subfolder);
249 popd_subfolder = NULL;
250 popd_subfolder = xstrndup(p, n);
251
252 /* strip the subfolder from the auth[z]id */
253 memmove(p, p+n, strlen(p+n)+1);
254 ulen -= n;
255 }
256 }
257
258 r = mysasl_canon_user(conn, context, user, ulen, flags, user_realm,
259 out, out_max, out_ulen);
260
261 if (!r && popd_subfolder && flags == SASL_CU_AUTHZID) {
262 /* If we're only doing the authzid, put back the subfolder
263 in case its used in the challenge/response calculation */
264 n = strlen(popd_subfolder);
265 if (*out_ulen + n > out_max) {
266 sasl_seterror(conn, 0, "buffer overflow while canonicalizing");
267 r = SASL_BUFOVER;
268 }
269 else {
270 p = (config_virtdomains && (p = strchr(out, '@'))) ?
271 p : out + *out_ulen;
272 memmove(p+n, p, strlen(p)+1);
273 memcpy(p, popd_subfolder, n);
274 *out_ulen += n;
275 }
276 }
277
278 return r;
279 }
280
popd_proxy_policy(sasl_conn_t * conn,void * context,const char * requested_user,unsigned rlen,const char * auth_identity,unsigned alen,const char * def_realm,unsigned urlen,struct propctx * propctx)281 static int popd_proxy_policy(sasl_conn_t *conn,
282 void *context,
283 const char *requested_user, unsigned rlen,
284 const char *auth_identity, unsigned alen,
285 const char *def_realm,
286 unsigned urlen,
287 struct propctx *propctx)
288 {
289 char userbuf[MAX_MAILBOX_BUFFER];
290
291 if (config_getswitch(IMAPOPT_POPSUBFOLDERS)) {
292 size_t n;
293 char *p;
294
295 /* make a working copy of the authzid */
296 if (!rlen) rlen = strlen(requested_user);
297 if (rlen >= MAX_MAILBOX_BUFFER) {
298 sasl_seterror(conn, 0, "buffer overflow while proxying");
299 return SASL_BUFOVER;
300 }
301 memcpy(userbuf, requested_user, rlen);
302 userbuf[rlen] = '\0';
303 requested_user = userbuf;
304
305 /* See if we're trying to access a subfolder */
306 if ((p = strchr(userbuf, '+'))) {
307 n = config_virtdomains ? strcspn(p, "@") : strlen(p);
308
309 /* strip the subfolder from the authzid */
310 memmove(p, p+n, strlen(p+n)+1);
311 rlen -= n;
312 }
313 }
314
315 return mysasl_proxy_policy(conn, context, requested_user, rlen,
316 auth_identity, alen, def_realm, urlen, propctx);
317 }
318
319 static struct sasl_callback mysasl_cb[] = {
320 { SASL_CB_GETOPT, (mysasl_cb_ft *) &mysasl_config, NULL },
321 { SASL_CB_PROXY_POLICY, (mysasl_cb_ft *) &popd_proxy_policy, (void*) &popd_proxyctx },
322 { SASL_CB_CANON_USER, (mysasl_cb_ft *) &popd_canon_user, NULL },
323 { SASL_CB_LIST_END, NULL, NULL }
324 };
325
popd_reset(void)326 static void popd_reset(void)
327 {
328 int bytes_in = 0;
329 int bytes_out = 0;
330
331 proc_cleanup();
332
333 syslog(LOG_NOTICE, "counts: retr=<%d> top=<%d> dele=<%d>",
334 count_retr, count_top, count_dele);
335 count_retr = 0;
336 count_top = 0;
337 count_dele = 0;
338
339 /* close local mailbox */
340 if (popd_mailbox)
341 mailbox_close(&popd_mailbox);
342
343 /* close backend connection */
344 if (backend) {
345 backend_disconnect(backend);
346 free(backend);
347 backend = NULL;
348 }
349
350 if (popd_in) {
351 prot_NONBLOCK(popd_in);
352 prot_fill(popd_in);
353 bytes_in = prot_bytes_in(popd_in);
354 prot_free(popd_in);
355 }
356
357 if (popd_out) {
358 prot_flush(popd_out);
359 bytes_out = prot_bytes_out(popd_out);
360 prot_free(popd_out);
361 }
362
363 if (config_auditlog)
364 syslog(LOG_NOTICE, "auditlog: traffic sessionid=<%s> bytes_in=<%d> bytes_out=<%d>",
365 session_id(), bytes_in, bytes_out);
366
367 popd_in = popd_out = NULL;
368
369 #ifdef HAVE_SSL
370 if (tls_conn) {
371 tls_reset_servertls(&tls_conn);
372 tls_conn = NULL;
373 }
374 #endif
375
376 cyrus_reset_stdio();
377
378 popd_clienthost = "[local]";
379 if (popd_logfd != -1) {
380 close(popd_logfd);
381 popd_logfd = -1;
382 }
383 if (popd_userid != NULL) {
384 free(popd_userid);
385 popd_userid = NULL;
386 }
387 if (popd_subfolder != NULL) {
388 free(popd_subfolder);
389 popd_subfolder = NULL;
390 }
391 if (popd_authstate) {
392 auth_freestate(popd_authstate);
393 popd_authstate = NULL;
394 }
395 if (popd_saslconn) {
396 sasl_dispose(&popd_saslconn);
397 popd_saslconn = NULL;
398 }
399 popd_starttls_done = 0;
400
401 saslprops_reset(&saslprops);
402
403 popd_exists = 0;
404 }
405
406 /*
407 * run once when process is forked;
408 * MUST NOT exit directly; must return with non-zero error code
409 */
service_init(int argc,char ** argv,char ** envp)410 int service_init(int argc __attribute__((unused)),
411 char **argv __attribute__((unused)),
412 char **envp __attribute__((unused)))
413 {
414 int r;
415 int opt;
416
417 if (geteuid() == 0) fatal("must run as the Cyrus user", EX_USAGE);
418 setproctitle_init(argc, argv, envp);
419
420 /* set signal handlers */
421 signals_set_shutdown(&shut_down);
422 signal(SIGPIPE, SIG_IGN);
423
424 /* load the SASL plugins */
425 global_sasl_init(1, 1, mysasl_cb);
426
427 /* setup for sending IMAP IDLE notifications */
428 idle_init();
429
430 /* Set namespace */
431 if ((r = mboxname_init_namespace(&popd_namespace, 1)) != 0) {
432 syslog(LOG_ERR, "%s", error_message(r));
433 fatal(error_message(r), EX_CONFIG);
434 }
435
436 mboxevent_setnamespace(&popd_namespace);
437
438 while ((opt = getopt(argc, argv, "skp:")) != EOF) {
439 switch(opt) {
440 case 's': /* pop3s (do starttls right away) */
441 pop3s = 1;
442 if (!tls_enabled()) {
443 syslog(LOG_ERR, "pop3s: required OpenSSL options not present");
444 fatal("pop3s: required OpenSSL options not present",
445 EX_CONFIG);
446 }
447 break;
448
449 case 'k':
450 kflag++;
451 break;
452
453 case 'p': /* external protection */
454 extprops_ssf = atoi(optarg);
455 break;
456
457 default:
458 usage();
459 }
460 }
461
462 return 0;
463 }
464
465 /*
466 * run for each accepted connection
467 */
service_main(int argc,char ** argv,char ** envp)468 int service_main(int argc __attribute__((unused)),
469 char **argv __attribute__((unused)),
470 char **envp __attribute__((unused)))
471 {
472 const char *localip, *remoteip;
473 sasl_security_properties_t *secprops=NULL;
474 struct mboxevent *mboxevent = NULL;
475
476 if (config_iolog) {
477 io_count_start = xmalloc (sizeof (struct io_count));
478 io_count_stop = xmalloc (sizeof (struct io_count));
479 read_io_count(io_count_start);
480 }
481
482 session_new_id();
483
484 signals_poll();
485
486 popd_in = prot_new(0, 0);
487 popd_out = prot_new(1, 1);
488
489 count_retr = 0;
490 count_top = 0;
491 count_dele = 0;
492
493 /* Find out name of client host */
494 popd_clienthost = get_clienthost(0, &localip, &remoteip);
495
496 if (localip && remoteip) {
497 buf_setcstr(&saslprops.ipremoteport, remoteip);
498 buf_setcstr(&saslprops.iplocalport, localip);
499 }
500
501 /* other params should be filled in */
502 if (sasl_server_new("pop", config_servername, NULL,
503 buf_cstringnull_ifempty(&saslprops.iplocalport),
504 buf_cstringnull_ifempty(&saslprops.ipremoteport),
505 NULL, 0, &popd_saslconn) != SASL_OK)
506 fatal("SASL failed initializing: sasl_server_new()",EX_TEMPFAIL);
507
508 /* will always return something valid */
509 secprops = mysasl_secprops(0);
510 if (sasl_setprop(popd_saslconn, SASL_SEC_PROPS, secprops) != SASL_OK)
511 fatal("Failed to set SASL property", EX_TEMPFAIL);
512 if (sasl_setprop(popd_saslconn, SASL_SSF_EXTERNAL, &extprops_ssf) != SASL_OK)
513 fatal("Failed to set SASL property", EX_TEMPFAIL);
514
515 if (localip) {
516 popd_haveaddr = 1;
517 }
518
519 popd_tls_required = config_getswitch(IMAPOPT_TLS_REQUIRED);
520
521 /* Set inactivity timer */
522 popd_timeout = config_getduration(IMAPOPT_POPTIMEOUT, 'm');
523 if (popd_timeout < 10 * 60) popd_timeout = 10 * 60;
524 prot_settimeout(popd_in, popd_timeout);
525 prot_setflushonread(popd_in, popd_out);
526
527 if (kflag) kpop();
528
529 /* we were connected on pop3s port so we should do
530 TLS negotiation immediatly */
531 if (pop3s == 1) cmd_starttls(1);
532
533 /* Create APOP challenge for banner */
534 *popd_apop_chal = 0;
535 if (!popd_tls_required && config_getswitch(IMAPOPT_ALLOWAPOP) &&
536 (sasl_checkapop(popd_saslconn, NULL, 0, NULL, 0) == SASL_OK) &&
537 !sasl_mkchal(popd_saslconn,
538 popd_apop_chal, sizeof(popd_apop_chal), 1)) {
539 syslog(LOG_WARNING, "APOP disabled: can't create challenge");
540 }
541
542 prot_printf(popd_out, "+OK");
543 if (config_serverinfo) prot_printf(popd_out, " %s", config_servername);
544 if (config_serverinfo == IMAP_ENUM_SERVERINFO_ON) {
545 prot_printf(popd_out, " Cyrus POP3 %s", CYRUS_VERSION);
546 }
547 prot_printf(popd_out, " server ready %s\r\n", popd_apop_chal);
548
549 cmdloop();
550
551 /* QUIT executed */
552
553 /* send a Logout event notification */
554 if ((mboxevent = mboxevent_new(EVENT_LOGOUT))) {
555 mboxevent_set_access(mboxevent,
556 buf_cstringnull_ifempty(&saslprops.iplocalport),
557 buf_cstringnull_ifempty(&saslprops.ipremoteport),
558 popd_userid, NULL, 1);
559
560 mboxevent_notify(&mboxevent);
561 mboxevent_free(&mboxevent);
562 }
563
564 /* don't bother reusing KPOP connections */
565 if (kflag) shut_down(0);
566
567 /* cleanup */
568 popd_reset();
569
570 if (config_iolog) {
571 read_io_count(io_count_stop);
572 syslog(LOG_INFO,
573 "POP session stats : I/O read : %d bytes : I/O write : %d bytes",
574 io_count_stop->io_read_count - io_count_start->io_read_count,
575 io_count_stop->io_write_count - io_count_start->io_write_count);
576 free(io_count_start);
577 free(io_count_stop);
578 }
579
580 return 0;
581 }
582
583 /* Called by service API to shut down the service */
service_abort(int error)584 void service_abort(int error)
585 {
586 shut_down(error);
587 }
588
usage(void)589 static void usage(void)
590 {
591 prot_printf(popd_out, "-ERR usage: pop3d [-C <alt_config>] [-k] [-s]\r\n");
592 prot_flush(popd_out);
593 exit(EX_USAGE);
594 }
595
596 /*
597 * Cleanly shut down and exit
598 */
shut_down(int code)599 void shut_down(int code)
600 {
601 int bytes_in = 0;
602 int bytes_out = 0;
603
604 in_shutdown = 1;
605
606 proc_cleanup();
607
608 /* close local mailbox */
609 if (popd_mailbox)
610 mailbox_close(&popd_mailbox);
611
612 if (popd_map) {
613 free(popd_map);
614 }
615
616 /* close backend connection */
617 if (backend) {
618 backend_disconnect(backend);
619 free(backend);
620 }
621
622 syslog(LOG_NOTICE, "counts: retr=<%d> top=<%d> dele=<%d>",
623 count_retr, count_top, count_dele);
624
625 idle_done();
626
627 /* make sure we didn't leak */
628 assert(!open_mailboxes_exist());
629 assert(!open_mboxlocks_exist());
630
631 sync_log_reset();
632
633 if (popd_in) {
634 prot_NONBLOCK(popd_in);
635 prot_fill(popd_in);
636 bytes_in = prot_bytes_in(popd_in);
637 prot_free(popd_in);
638 }
639
640 if (popd_out) {
641 prot_flush(popd_out);
642 bytes_out = prot_bytes_out(popd_out);
643 prot_free(popd_out);
644 }
645
646 if (config_auditlog)
647 syslog(LOG_NOTICE, "auditlog: traffic sessionid=<%s> bytes_in=<%d> bytes_out=<%d>",
648 session_id(), bytes_in, bytes_out);
649
650 #ifdef HAVE_SSL
651 tls_shutdown_serverengine();
652 #endif
653
654 saslprops_free(&saslprops);
655
656 cyrus_done();
657
658 if (config_iolog) {
659 read_io_count(io_count_stop);
660 syslog(LOG_INFO,
661 "POP session stats : I/O read : %d bytes : I/O write : %d bytes",
662 io_count_stop->io_read_count - io_count_start->io_read_count,
663 io_count_stop->io_write_count - io_count_start->io_write_count);
664 free (io_count_start);
665 free (io_count_stop);
666 }
667
668 exit(code);
669 }
670
fatal(const char * s,int code)671 EXPORTED void fatal(const char* s, int code)
672 {
673 static int recurse_code = 0;
674
675 if (recurse_code) {
676 /* We were called recursively. Just give up */
677 proc_cleanup();
678 exit(recurse_code);
679 }
680 recurse_code = code;
681 if (popd_out) {
682 prot_printf(popd_out, "-ERR [SYS/PERM] Fatal error: %s\r\n", s);
683 prot_flush(popd_out);
684 }
685 syslog(LOG_ERR, "Fatal error: %s", s);
686 shut_down(code);
687 }
688
689 #ifdef HAVE_KRB
690 /* translate IPv4 mapped IPv6 address to IPv4 address */
691 #ifdef IN6_IS_ADDR_V4MAPPED
sockaddr_unmapped(struct sockaddr * sa,socklen_t * len)692 static void sockaddr_unmapped(struct sockaddr *sa, socklen_t *len)
693 {
694 struct sockaddr_in6 *sin6;
695 struct sockaddr_in *sin4;
696 uint32_t addr;
697 int port;
698
699 if (sa->sa_family != AF_INET6)
700 return;
701 sin6 = (struct sockaddr_in6 *)sa;
702 if (!IN6_IS_ADDR_V4MAPPED((&sin6->sin6_addr)))
703 return;
704 sin4 = (struct sockaddr_in *)sa;
705 addr = *(uint32_t *)&sin6->sin6_addr.s6_addr[12];
706 port = sin6->sin6_port;
707 memset(sin4, 0, sizeof(struct sockaddr_in));
708 sin4->sin_addr.s_addr = addr;
709 sin4->sin_port = port;
710 sin4->sin_family = AF_INET;
711 #ifdef HAVE_SOCKADDR_SA_LEN
712 sin4->sin_len = sizeof(struct sockaddr_in);
713 #endif
714 *len = sizeof(struct sockaddr_in);
715 }
716 #else
sockaddr_unmapped(struct sockaddr * sa,socklen_t * len)717 static void sockaddr_unmapped(struct sockaddr *sa __attribute__((unused)),
718 socklen_t *len __attribute__((unused)))
719 {
720 return;
721 }
722 #endif
723
724
725 /*
726 * MIT's kludge of a kpop protocol
727 * Client does a krb_sendauth() first thing
728 */
kpop(void)729 void kpop(void)
730 {
731 Key_schedule schedule;
732 KTEXT_ST ticket;
733 char instance[INST_SZ];
734 char version[9];
735 const char *srvtab;
736 int r;
737 socklen_t len;
738
739 if (!popd_haveaddr) {
740 fatal("Cannot get client's IP address", EX_OSERR);
741 }
742
743 srvtab = config_getstring(IMAPOPT_SRVTAB);
744
745 sockaddr_unmapped((struct sockaddr *)&popd_remoteaddr, &len);
746 if (popd_remoteaddr.ss_family != AF_INET) {
747 prot_printf(popd_out,
748 "-ERR [AUTH] Kerberos authentication failure: %s\r\n",
749 "not an IPv4 connection");
750 shut_down(0);
751 }
752
753 strcpy(instance, "*");
754 r = krb_recvauth(0L, 0, &ticket, "pop", instance,
755 (struct sockaddr_in *) &popd_remoteaddr,
756 (struct sockaddr_in *) NULL,
757 &kdata, (char*) srvtab, schedule, version);
758
759 if (r) {
760 prot_printf(popd_out, "-ERR [AUTH] Kerberos authentication failure: %s\r\n",
761 krb_err_txt[r]);
762 syslog(LOG_NOTICE,
763 "badlogin: %s kpop ? %s%s%s@%s %s",
764 popd_clienthost, kdata.pname,
765 kdata.pinst[0] ? "." : "", kdata.pinst,
766 kdata.prealm, krb_err_txt[r]);
767 shut_down(0);
768 }
769
770 r = krb_get_lrealm(klrealm,1);
771 if (r) {
772 prot_printf(popd_out, "-ERR [AUTH] Kerberos failure: %s\r\n",
773 krb_err_txt[r]);
774 syslog(LOG_NOTICE,
775 "badlogin: %s kpop ? %s%s%s@%s krb_get_lrealm: %s",
776 popd_clienthost, kdata.pname,
777 kdata.pinst[0] ? "." : "", kdata.pinst,
778 kdata.prealm, krb_err_txt[r]);
779 shut_down(0);
780 }
781 }
782 #else
kpop(void)783 void kpop(void)
784 {
785 usage();
786 }
787 #endif
788
expunge_deleted(void)789 static int expunge_deleted(void)
790 {
791 struct index_record record;
792 uint32_t msgno;
793 int r = 0;
794 int numexpunged = 0;
795 struct mboxevent *mboxevent;
796
797 mboxevent = mboxevent_new(EVENT_MESSAGE_EXPUNGE);
798
799 /* loop over all known messages looking for deletes */
800 for (msgno = 1; msgno <= popd_exists; msgno++) {
801 /* not deleted? skip */
802 if (!popd_map[msgno-1].deleted)
803 continue;
804
805 /* error reading? abort */
806 memset(&record, 0, sizeof(struct index_record));
807 record.recno = popd_map[msgno-1].recno;
808 r = mailbox_reload_index_record(popd_mailbox, &record);
809 if (r) break;
810
811 /* already expunged? skip */
812 if (record.internal_flags & FLAG_INTERNAL_EXPUNGED)
813 continue;
814
815 /* mark expunged */
816 record.system_flags |= FLAG_DELETED;
817 record.internal_flags |= FLAG_INTERNAL_EXPUNGED;
818 numexpunged++;
819
820 /* store back to the mailbox */
821 r = mailbox_rewrite_index_record(popd_mailbox, &record);
822 if (r) break;
823
824 mboxevent_extract_record(mboxevent, popd_mailbox, &record);
825 }
826
827 if (r) {
828 syslog(LOG_ERR, "IOERROR: %s failed to expunge record %u uid %u, aborting",
829 popd_mailbox->name, msgno, popd_map[msgno-1].uid);
830 }
831
832 if (!r && (numexpunged > 0)) {
833 syslog(LOG_NOTICE, "Expunged %d messages from %s",
834 numexpunged, popd_mailbox->name);
835 }
836
837 /* send the MessageExpunge event notification */
838 mboxevent_extract_mailbox(mboxevent, popd_mailbox);
839 mboxevent_set_numunseen(mboxevent, popd_mailbox, -1);
840 mboxevent_set_access(mboxevent, NULL, NULL, popd_userid, NULL, 0);
841 mboxevent_notify(&mboxevent);
842 mboxevent_free(&mboxevent);
843
844 return r;
845 }
846
847 /*
848 * Top-level command loop parsing
849 */
cmdloop(void)850 static void cmdloop(void)
851 {
852 char inputbuf[8192];
853 char *p;
854 char *arg;
855 uint32_t msgno = 0;
856
857 for (;;) {
858 signals_poll();
859
860 /* register process */
861 proc_register(config_ident, popd_clienthost, popd_userid, popd_mailbox ? popd_mailbox->name : NULL, NULL);
862
863 if (backend) {
864 /* create a pipe from client to backend */
865 bitpipe();
866
867 /* pipe has been closed */
868 telemetry_rusage( popd_userid );
869 return;
870 }
871
872 /* check for shutdown file */
873 if (shutdown_file(inputbuf, sizeof(inputbuf)) ||
874 (popd_userid &&
875 userdeny(popd_userid, config_ident, inputbuf, sizeof(inputbuf)))) {
876 for (p = inputbuf; *p == '['; p++); /* can't have [ be first char */
877 prot_printf(popd_out, "-ERR [SYS/TEMP] %s\r\n", p);
878 telemetry_rusage( popd_userid );
879 shut_down(0);
880 }
881
882 if (!prot_fgets(inputbuf, sizeof(inputbuf), popd_in)) {
883 telemetry_rusage( popd_userid );
884 shut_down(0);
885 }
886
887 if (popd_mailbox &&
888 config_getswitch(IMAPOPT_DISCONNECT_ON_VANISHED_MAILBOX)) {
889 if (popd_mailbox->i.options & OPT_MAILBOX_DELETED) {
890 /* Mailbox has been (re)moved */
891 syslog(LOG_WARNING,
892 "Maildrop %s has been (re)moved out from under client",
893 popd_mailbox->name);
894 prot_printf(popd_out,
895 "-ERR [SYS/TEMP] "
896 "Maildrop has been (re)moved\r\n");
897 shut_down(0);
898 }
899 }
900
901 p = inputbuf + strlen(inputbuf);
902 if (p > inputbuf && p[-1] == '\n') *--p = '\0';
903 if (p > inputbuf && p[-1] == '\r') *--p = '\0';
904
905 /* Parse into keyword and argument */
906 for (p = inputbuf; *p && !Uisspace(*p); p++);
907 if (*p) {
908 *p++ = '\0';
909 arg = p;
910 if (strcasecmp(inputbuf, "pass") != 0) {
911 while (*arg && Uisspace(*arg)) {
912 arg++;
913 }
914 }
915 if (!*arg) {
916 if (strcasecmp(inputbuf, "auth") == 0) {
917 /* HACK for MS Outlook's incorrect use of the old-style
918 * SASL discovery method.
919 * Outlook uses "AUTH \r\n" instead if "AUTH\r\n"
920 */
921 arg = 0;
922 }
923 else {
924 prot_printf(popd_out, "-ERR Syntax error\r\n");
925 continue;
926 }
927 }
928 }
929 else {
930 arg = 0;
931 }
932 lcase(inputbuf);
933
934 if (config_getswitch(IMAPOPT_CHATTY))
935 syslog(LOG_NOTICE, "command: %s", inputbuf);
936
937 /* register process */
938 proc_register(config_ident, popd_clienthost, popd_userid, popd_mailbox ? popd_mailbox->name : NULL, inputbuf);
939
940 if (!strcmp(inputbuf, "quit")) {
941 if (!arg) {
942 int pollpadding =config_getint(IMAPOPT_POPPOLLPADDING);
943 int minpollsec = config_getduration(IMAPOPT_POPMINPOLL, 'm');
944
945 /* check preconditions! */
946 if (!popd_mailbox)
947 goto done;
948 if (mailbox_lock_index(popd_mailbox, LOCK_EXCLUSIVE))
949 goto done;
950
951 /* mark dirty in case everything else misses it - we're updating
952 * at least the last login */
953 mailbox_index_dirty(popd_mailbox);
954 if ((minpollsec > 0) && (pollpadding > 1)) {
955 time_t mintime = popd_login_time - (minpollsec*(pollpadding));
956 if (popd_mailbox->i.pop3_last_login < mintime) {
957 popd_mailbox->i.pop3_last_login = mintime + minpollsec;
958 } else {
959 popd_mailbox->i.pop3_last_login += minpollsec;
960 }
961 } else {
962 popd_mailbox->i.pop3_last_login = popd_login_time;
963 }
964
965 /* look for deleted messages */
966 expunge_deleted();
967
968 /* update seen data */
969 update_seen();
970
971 /* unlock will commit changes */
972 mailbox_unlock_index(popd_mailbox, NULL);
973
974 done:
975 mailbox_close(&popd_mailbox);
976 sync_checkpoint(popd_in);
977
978 prot_printf(popd_out, "+OK\r\n");
979 telemetry_rusage( popd_userid );
980 return;
981 }
982 else
983 prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
984 }
985 else if (!strcmp(inputbuf, "capa")) {
986 if (arg) {
987 prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
988 } else {
989 cmd_capa();
990 }
991 }
992 else if (!popd_authstate) {
993 if (!strcmp(inputbuf, "user")) {
994 if (!arg) {
995 prot_printf(popd_out, "-ERR Missing argument\r\n");
996 }
997 else {
998 cmd_user(arg);
999 }
1000 }
1001 else if (!strcmp(inputbuf, "pass")) {
1002 if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
1003 else cmd_pass(arg);
1004 }
1005 else if (!strcmp(inputbuf, "apop") && *popd_apop_chal) {
1006 if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
1007 else cmd_apop(arg);
1008 }
1009 else if (!strcmp(inputbuf, "auth")) {
1010 cmd_auth(arg);
1011 }
1012 else if (!strcmp(inputbuf, "stls") && tls_enabled()) {
1013 if (arg) {
1014 prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
1015 } else {
1016 /* XXX discard any input pipelined after STLS */
1017 prot_flush(popd_in);
1018
1019 cmd_starttls(0);
1020 }
1021 }
1022 else {
1023 prot_printf(popd_out, "-ERR Unrecognized command\r\n");
1024 }
1025 }
1026 else if (!strcmp(inputbuf, "stat")) {
1027 unsigned nmsgs = 0, totsize = 0;
1028 if (arg) {
1029 prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
1030 }
1031 else {
1032 for (msgno = 1; msgno <= popd_exists; msgno++) {
1033 if (!popd_map[msgno-1].deleted) {
1034 nmsgs++;
1035 totsize += popd_map[msgno-1].size;
1036 }
1037 }
1038 prot_printf(popd_out, "+OK %u %u\r\n", nmsgs, totsize);
1039 }
1040 }
1041 else if (!strcmp(inputbuf, "list")) {
1042 if (arg) {
1043 msgno = parse_msgno(&arg);
1044 if (msgno) {
1045 prot_printf(popd_out, "+OK %u %u\r\n",
1046 msgno, popd_map[msgno-1].size);
1047 }
1048 }
1049 else {
1050 prot_printf(popd_out, "+OK scan listing follows\r\n");
1051 for (msgno = 1; msgno <= popd_exists; msgno++) {
1052 if (!popd_map[msgno-1].deleted)
1053 prot_printf(popd_out, "%u %u\r\n",
1054 msgno, popd_map[msgno-1].size);
1055 }
1056 prot_printf(popd_out, ".\r\n");
1057 }
1058 }
1059 else if (!strcmp(inputbuf, "retr")) {
1060 if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
1061 else {
1062 msgno = parse_msgno(&arg);
1063 if (msgno) {
1064 blat(msgno, -1);
1065 popd_map[msgno-1].seen = 1;
1066 count_retr++;
1067 }
1068 }
1069 }
1070 else if (!strcmp(inputbuf, "dele")) {
1071 if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
1072 else if (config_popuseacl && !(popd_myrights & ACL_DELETEMSG)) {
1073 prot_printf(popd_out, "-ERR [SYS/PERM] %s\r\n",
1074 error_message(IMAP_PERMISSION_DENIED));
1075 }
1076 else if (config_getswitch(IMAPOPT_READONLY)) {
1077 prot_printf(popd_out, "-ERR [SYS/PERM] %s\r\n",
1078 error_message(IMAP_CONNECTION_READONLY));
1079 }
1080 else {
1081 msgno = parse_msgno(&arg);
1082 if (msgno) {
1083 popd_map[msgno-1].deleted = 1;
1084 prot_printf(popd_out, "+OK message deleted\r\n");
1085 count_dele++;
1086 }
1087 }
1088 }
1089 else if (!strcmp(inputbuf, "noop")) {
1090 if (arg)
1091 prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
1092 else
1093 prot_printf(popd_out, "+OK\r\n");
1094 }
1095 else if (!strcmp(inputbuf, "rset")) {
1096 if (arg)
1097 prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
1098 else {
1099 for (msgno = 1; msgno <= popd_exists; msgno++) {
1100 popd_map[msgno-1].deleted = 0;
1101 popd_map[msgno-1].seen = 0;
1102 }
1103 prot_printf(popd_out, "+OK\r\n");
1104 }
1105 }
1106 else if (!strcmp(inputbuf, "top")) {
1107 const char *p = arg;
1108 uint32_t num;
1109 uint32_t lines;
1110 int r;
1111
1112 if (!p)
1113 p = "";
1114 while (*p && Uisspace(*p)) {
1115 p++;
1116 }
1117
1118 /* special case, can't just parse_msgno */
1119 r = parseuint32(p, &p, &num);
1120 if (r || !*p) {
1121 prot_printf(popd_out, "-ERR Missing argument\r\n");
1122 }
1123 else {
1124 msgno = num;
1125 /* skip over whitespace */
1126 while (*p && Uisspace(*p)) {
1127 p++;
1128 }
1129 if (parseuint32(p, &p, &lines)) {
1130 prot_printf(popd_out, "-ERR Invalid number of lines\r\n");
1131 }
1132 else if (*p) {
1133 prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
1134 }
1135 else if (msg_exists_or_err(msgno)) {
1136 blat(msgno, lines);
1137 count_top++;
1138 }
1139 }
1140 }
1141 else if (!strcmp(inputbuf, "uidl")) {
1142 if (arg) {
1143 msgno = parse_msgno(&arg);
1144 if (msgno) {
1145 prot_printf(popd_out, "+OK ");
1146 uidl_msg(msgno);
1147 }
1148 }
1149 else {
1150 prot_printf(popd_out, "+OK unique-id listing follows\r\n");
1151 for (msgno = 1; msgno <= popd_exists; msgno++) {
1152 if (!popd_map[msgno-1].deleted)
1153 uidl_msg(msgno);
1154 }
1155 prot_printf(popd_out, ".\r\n");
1156 }
1157 }
1158 else {
1159 prot_printf(popd_out, "-ERR Unrecognized command\r\n");
1160 }
1161 }
1162 }
1163
parse_msgno(char ** ptr)1164 unsigned parse_msgno(char **ptr)
1165 {
1166 const char *p;
1167 uint32_t msgno;
1168 int r;
1169
1170 p = *ptr;
1171
1172 /* skip leading whitespace */
1173 while (*p && Uisspace(*p)) {
1174 p++;
1175 }
1176
1177 r = parseuint32(p, &p, &msgno);
1178
1179 if (r) {
1180 prot_printf(popd_out, "-ERR Not a number\r\n");
1181 *ptr = (char *)p;
1182 }
1183 else if (*p) {
1184 prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
1185 *ptr = (char *)p;
1186 }
1187 else if (msg_exists_or_err(msgno))
1188 return msgno;
1189
1190 return 0;
1191 }
1192
msg_exists_or_err(uint32_t msgno)1193 int msg_exists_or_err(uint32_t msgno)
1194 {
1195 if (msgno < 1 || msgno > popd_exists ||
1196 popd_map[msgno-1].deleted) {
1197 prot_printf(popd_out, "-ERR No such message\r\n");
1198 return 0;
1199 }
1200 return 1;
1201 }
1202
uidl_msg(uint32_t msgno)1203 void uidl_msg(uint32_t msgno)
1204 {
1205 if (popd_mailbox->i.options & OPT_POP3_NEW_UIDL) {
1206 switch (config_getenum(IMAPOPT_UIDL_FORMAT)) {
1207 case IMAP_ENUM_UIDL_FORMAT_UIDONLY:
1208 prot_printf(popd_out, "%u %u\r\n", msgno,
1209 popd_map[msgno-1].uid);
1210 break;
1211 case IMAP_ENUM_UIDL_FORMAT_CYRUS:
1212 prot_printf(popd_out, "%u %u.%u\r\n", msgno,
1213 popd_mailbox->i.uidvalidity,
1214 popd_map[msgno-1].uid);
1215 break;
1216 case IMAP_ENUM_UIDL_FORMAT_DOVECOT: {
1217 char uidl[100];
1218 snprintf(uidl, 100, "%08x%08x",
1219 popd_map[msgno-1].uid,
1220 popd_mailbox->i.uidvalidity);
1221 prot_printf(popd_out, "%u %s\r\n", msgno, uidl);
1222 }
1223 break;
1224 case IMAP_ENUM_UIDL_FORMAT_COURIER:
1225 prot_printf(popd_out, "%u %u-%u\r\n", msgno,
1226 popd_mailbox->i.uidvalidity,
1227 popd_map[msgno-1].uid);
1228 break;
1229 default:
1230 abort();
1231 }
1232 }
1233 else {
1234 prot_printf(popd_out, "%u %u\r\n", msgno,
1235 popd_map[msgno-1].uid);
1236 }
1237 }
1238
1239 #ifdef HAVE_SSL
cmd_starttls(int pop3s)1240 static void cmd_starttls(int pop3s)
1241 {
1242 int result;
1243 char *localip, *remoteip;
1244
1245 if (popd_starttls_done == 1)
1246 {
1247 prot_printf(popd_out, "-ERR %s\r\n",
1248 "Already successfully executed STLS");
1249 return;
1250 }
1251
1252 result=tls_init_serverengine("pop3",
1253 5, /* depth to verify */
1254 !pop3s, /* can client auth? */
1255 NULL);
1256
1257 if (result == -1) {
1258
1259 syslog(LOG_ERR, "[pop3d] error initializing TLS");
1260
1261 if (pop3s == 0)
1262 prot_printf(popd_out, "-ERR [SYS/PERM] %s\r\n", "Error initializing TLS");
1263 else
1264 shut_down(0);
1265
1266 return;
1267 }
1268
1269 if (pop3s == 0)
1270 {
1271 prot_printf(popd_out, "+OK %s\r\n", "Begin TLS negotiation now");
1272 /* must flush our buffers before starting tls */
1273 prot_flush(popd_out);
1274 }
1275
1276 /* tls_start_servertls is going to reset saslprops, discarding the
1277 * iplocalport and ipremoteport fields. Preserve them, then put them back
1278 * after the call.
1279 */
1280 localip = buf_release(&saslprops.iplocalport);
1281 remoteip = buf_release(&saslprops.ipremoteport);
1282
1283 result=tls_start_servertls(0, /* read */
1284 1, /* write */
1285 pop3s ? 180 : popd_timeout,
1286 &saslprops,
1287 &tls_conn);
1288
1289 /* put the iplocalport and ipremoteport back */
1290 if (localip) buf_initm(&saslprops.iplocalport, localip, strlen(localip));
1291 if (remoteip) buf_initm(&saslprops.ipremoteport, remoteip, strlen(remoteip));
1292
1293 /* if error */
1294 if (result==-1) {
1295 if (pop3s == 0) {
1296 prot_printf(popd_out, "-ERR [SYS/PERM] Starttls failed\r\n");
1297 syslog(LOG_NOTICE, "[pop3d] STARTTLS failed: %s", popd_clienthost);
1298 } else {
1299 syslog(LOG_NOTICE, "pop3s failed: %s", popd_clienthost);
1300 shut_down(0);
1301 }
1302 return;
1303 }
1304
1305 /* tell SASL about the negotiated layer */
1306 result = saslprops_set_tls(&saslprops, popd_saslconn);
1307 if (result != SASL_OK) {
1308 syslog(LOG_NOTICE, "saslprops_set_tls() failed: cmd_starttls()");
1309 if (pop3s == 0) {
1310 fatal("saslprops_set_tls() failed: cmd_starttls()", EX_TEMPFAIL);
1311 } else {
1312 shut_down(0);
1313 }
1314 }
1315
1316 /* tell the prot layer about our new layers */
1317 prot_settls(popd_in, tls_conn);
1318 prot_settls(popd_out, tls_conn);
1319
1320 popd_starttls_done = 1;
1321 popd_tls_required = 0;
1322 }
1323 #else
cmd_starttls(int pop3s)1324 static void cmd_starttls(int pop3s __attribute__((unused)))
1325 {
1326 fatal("cmd_starttls() called, but no OpenSSL", EX_SOFTWARE);
1327 }
1328 #endif /* HAVE_SSL */
1329
cmd_apop(char * response)1330 static void cmd_apop(char *response)
1331 {
1332 int sasl_result;
1333 const void *canon_user;
1334 int failedloginpause;
1335
1336 /* possibly disallow APOP */
1337 if (popd_tls_required) {
1338 prot_printf(popd_out,
1339 "-ERR [AUTH] APOP command only available under a layer\r\n");
1340 return;
1341 }
1342
1343 assert(response != NULL);
1344
1345 if (popd_userid) {
1346 prot_printf(popd_out, "-ERR [AUTH] Must give PASS command\r\n");
1347 return;
1348 }
1349
1350 sasl_result = sasl_checkapop(popd_saslconn,
1351 popd_apop_chal,
1352 strlen(popd_apop_chal),
1353 response,
1354 strlen(response));
1355
1356 /* failed authentication */
1357 if (sasl_result != SASL_OK)
1358 {
1359 syslog(LOG_NOTICE, "badlogin: %s APOP (%s) %s",
1360 popd_clienthost, popd_apop_chal,
1361 sasl_errdetail(popd_saslconn));
1362
1363 failedloginpause = config_getduration(IMAPOPT_FAILEDLOGINPAUSE, 's');
1364 if (failedloginpause != 0) {
1365 sleep(failedloginpause);
1366 }
1367
1368 /* Don't allow user probing */
1369 if (sasl_result == SASL_NOUSER) sasl_result = SASL_BADAUTH;
1370
1371 prot_printf(popd_out, "-ERR [AUTH] authenticating: %s\r\n",
1372 sasl_errstring(sasl_result, NULL, NULL));
1373
1374 free(popd_subfolder);
1375 popd_subfolder = NULL;
1376 return;
1377 }
1378
1379 /* successful authentication */
1380
1381 /*
1382 * get the userid from SASL --- already canonicalized from
1383 * mysasl_proxy_policy()
1384 */
1385 sasl_result = sasl_getprop(popd_saslconn, SASL_USERNAME, &canon_user);
1386 if (sasl_result != SASL_OK) {
1387 prot_printf(popd_out,
1388 "-ERR [AUTH] weird SASL error %d getting SASL_USERNAME\r\n",
1389 sasl_result);
1390 free(popd_subfolder);
1391 popd_subfolder = NULL;
1392 return;
1393 }
1394 popd_userid = xstrdup((const char *) canon_user);
1395
1396 syslog(LOG_NOTICE, "login: %s %s%s APOP%s %s SESSIONID=<%s>", popd_clienthost,
1397 popd_userid, popd_subfolder ? popd_subfolder : "",
1398 popd_starttls_done ? "+TLS" : "", "User logged in", session_id());
1399
1400 popd_authstate = auth_newstate(popd_userid);
1401
1402 openinbox();
1403 }
1404
cmd_user(char * user)1405 static void cmd_user(char *user)
1406 {
1407 char userbuf[MAX_MAILBOX_BUFFER], *dot, *domain;
1408 unsigned userlen;
1409
1410 /* possibly disallow USER */
1411 if (popd_tls_required ||
1412 !(kflag || popd_starttls_done || (extprops_ssf > 1) ||
1413 config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
1414 prot_printf(popd_out,
1415 "-ERR [AUTH] USER command only available under a layer\r\n");
1416 return;
1417 }
1418
1419 if (popd_userid) {
1420 prot_printf(popd_out, "-ERR [AUTH] Must give PASS command\r\n");
1421 return;
1422 }
1423
1424 if (popd_canon_user(popd_saslconn, NULL, user, 0,
1425 SASL_CU_AUTHID | SASL_CU_AUTHZID,
1426 NULL, userbuf, sizeof(userbuf), &userlen) ||
1427 /* '.' isn't allowed if '.' is the hierarchy separator */
1428 (popd_namespace.hier_sep == '.' && (dot = strchr(userbuf, '.')) &&
1429 !(config_virtdomains && /* allow '.' in dom.ain */
1430 (domain = strchr(userbuf, '@')) && (dot > domain))) ||
1431 strlen(userbuf) + 6 >= MAX_MAILBOX_BUFFER) {
1432 prot_printf(popd_out, "-ERR [AUTH] Invalid user\r\n");
1433 syslog(LOG_NOTICE,
1434 "badlogin: %s plaintext (%s) invalid user",
1435 popd_clienthost, beautify_string(user));
1436 }
1437 else {
1438 popd_userid = xstrdup(userbuf);
1439 prot_printf(popd_out, "+OK Name is a valid mailbox\r\n");
1440 }
1441
1442 }
1443
cmd_pass(char * pass)1444 static void cmd_pass(char *pass)
1445 {
1446 int failedloginpause;
1447
1448 if (!popd_userid) {
1449 prot_printf(popd_out, "-ERR [AUTH] Must give USER command\r\n");
1450 return;
1451 }
1452
1453 #ifdef HAVE_KRB
1454 if (kflag) {
1455 if (strcmp(popd_userid, kdata.pname) != 0 ||
1456 kdata.pinst[0] ||
1457 strcmp(klrealm, kdata.prealm) != 0) {
1458 prot_printf(popd_out, "-ERR [AUTH] Invalid login\r\n");
1459 syslog(LOG_NOTICE,
1460 "badlogin: %s kpop %s %s%s%s@%s access denied",
1461 popd_clienthost, popd_userid,
1462 kdata.pname, kdata.pinst[0] ? "." : "",
1463 kdata.pinst, kdata.prealm);
1464 return;
1465 }
1466
1467 syslog(LOG_NOTICE, "login: %s %s%s KPOP%s %s SESSIONID=<%s>", popd_clienthost,
1468 popd_userid, popd_subfolder ? popd_subfolder : "",
1469 popd_starttls_done ? "+TLS" : "", "User logged in", session_id());
1470
1471 openinbox();
1472 return;
1473 }
1474 #endif
1475
1476 if (!strcmp(popd_userid, "anonymous")) {
1477 if (config_getswitch(IMAPOPT_ALLOWANONYMOUSLOGIN)) {
1478 pass = beautify_string(pass);
1479 if (strlen(pass) > 500) pass[500] = '\0';
1480 syslog(LOG_NOTICE, "login: %s anonymous %s",
1481 popd_clienthost, pass);
1482 }
1483 else {
1484 syslog(LOG_NOTICE, "badlogin: %s anonymous login refused",
1485 popd_clienthost);
1486 prot_printf(popd_out, "-ERR [AUTH] Invalid login\r\n");
1487 return;
1488 }
1489 }
1490 else if (sasl_checkpass(popd_saslconn,
1491 popd_userid,
1492 strlen(popd_userid),
1493 pass,
1494 strlen(pass))!=SASL_OK) {
1495 syslog(LOG_NOTICE, "badlogin: %s plaintext (%s) [%s]",
1496 popd_clienthost, popd_userid, sasl_errdetail(popd_saslconn));
1497 failedloginpause = config_getduration(IMAPOPT_FAILEDLOGINPAUSE, 's');
1498 if (failedloginpause != 0) {
1499 sleep(failedloginpause);
1500 }
1501 prot_printf(popd_out, "-ERR [AUTH] Invalid login\r\n");
1502 free(popd_userid);
1503 popd_userid = NULL;
1504 free(popd_subfolder);
1505 popd_subfolder = NULL;
1506 return;
1507 }
1508 else {
1509 /* successful authentication */
1510 int sasl_result, plaintextloginpause;
1511 const void *val;
1512
1513 free(popd_userid);
1514 popd_userid = 0;
1515
1516 /* get the userid from SASL --- already canonicalized from
1517 * mysasl_proxy_policy()
1518 */
1519 sasl_result = sasl_getprop(popd_saslconn, SASL_USERNAME, &val);
1520 if (sasl_result != SASL_OK) {
1521 prot_printf(popd_out,
1522 "-ERR [AUTH] weird SASL error %d getting SASL_USERNAME\r\n",
1523 sasl_result);
1524 if (popd_subfolder) {
1525 free(popd_subfolder);
1526 popd_subfolder = 0;
1527 }
1528 return;
1529 }
1530 popd_userid = xstrdup((const char *) val);
1531
1532 syslog(LOG_NOTICE, "login: %s %s%s plaintext%s %s SESSIONID=<%s>", popd_clienthost,
1533 popd_userid, popd_subfolder ? popd_subfolder : "",
1534 popd_starttls_done ? "+TLS" : "", "User logged in", session_id());
1535
1536 if ((!popd_starttls_done) &&
1537 (plaintextloginpause = config_getduration(IMAPOPT_PLAINTEXTLOGINPAUSE, 's'))
1538 != 0) {
1539 sleep(plaintextloginpause);
1540 }
1541 }
1542
1543 /* popd_authstate may have been set as a side effect
1544 * of sasl_checkpass() calling mysasl_proxy_policy */
1545 if (popd_authstate)
1546 auth_freestate(popd_authstate);
1547
1548 popd_authstate = auth_newstate(popd_userid);
1549
1550 openinbox();
1551 }
1552
1553 /* Handle the POP3 Extension extension.
1554 */
cmd_capa(void)1555 static void cmd_capa(void)
1556 {
1557 int minpoll = config_getduration(IMAPOPT_POPMINPOLL, 'm');
1558 int expire = config_getduration(IMAPOPT_POPEXPIRETIME, 'd');
1559 int mechcount;
1560 const char *mechlist;
1561
1562 prot_printf(popd_out, "+OK List of capabilities follows\r\n");
1563
1564 /* SASL special case: print SASL, then a list of supported capabilities */
1565 if (!popd_tls_required && (!popd_authstate || saslprops.ssf) &&
1566 sasl_listmech(popd_saslconn,
1567 NULL, /* should be id string */
1568 "SASL ", " ", "\r\n",
1569 &mechlist,
1570 NULL, &mechcount) == SASL_OK && mechcount > 0) {
1571 prot_write(popd_out, mechlist, strlen(mechlist));
1572 }
1573
1574 if (tls_enabled() && !popd_starttls_done && !popd_authstate) {
1575 prot_printf(popd_out, "STLS\r\n");
1576 }
1577 if (expire < 0) {
1578 prot_printf(popd_out, "EXPIRE NEVER\r\n");
1579 } else {
1580 expire /= (24 * 60 * 60);
1581 prot_printf(popd_out, "EXPIRE %d\r\n", expire);
1582 }
1583
1584 prot_printf(popd_out, "LOGIN-DELAY %d\r\n", minpoll);
1585 prot_printf(popd_out, "TOP\r\n");
1586 prot_printf(popd_out, "UIDL\r\n");
1587 prot_printf(popd_out, "PIPELINING\r\n");
1588 prot_printf(popd_out, "RESP-CODES\r\n");
1589 prot_printf(popd_out, "AUTH-RESP-CODE\r\n");
1590
1591 if (!popd_tls_required && !popd_authstate &&
1592 (kflag || popd_starttls_done || (extprops_ssf > 1)
1593 || config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
1594 prot_printf(popd_out, "USER\r\n");
1595 }
1596
1597 if (popd_authstate || (config_serverinfo == IMAP_ENUM_SERVERINFO_ON)) {
1598 prot_printf(popd_out,
1599 "IMPLEMENTATION Cyrus POP3 %s\r\n",
1600 CYRUS_VERSION);
1601 }
1602
1603 prot_printf(popd_out, ".\r\n");
1604 prot_flush(popd_out);
1605 }
1606
1607
cmd_auth(char * arg)1608 static void cmd_auth(char *arg)
1609 {
1610 int r, sasl_result;
1611 char *authtype;
1612 const void *val;
1613 const char *canon_user;
1614 int failedloginpause;
1615
1616 /* possibly disallow AUTH */
1617 if (popd_tls_required) {
1618 prot_printf(popd_out,
1619 "-ERR [AUTH] AUTH command only available under a layer\r\n");
1620 return;
1621 }
1622
1623 /* if client didn't specify an argument we give them the list
1624 *
1625 * XXX This method of mechanism discovery is an undocumented feature
1626 * that appeared in draft-myers-sasl-pop3 and is still used by
1627 * some clients.
1628 */
1629 if (!arg) {
1630 const char *sasllist;
1631 int mechnum;
1632
1633 prot_printf(popd_out, "+OK List of supported mechanisms follows\r\n");
1634
1635 /* CRLF separated, dot terminated */
1636 if (sasl_listmech(popd_saslconn, NULL,
1637 "", "\r\n", "\r\n",
1638 &sasllist,
1639 NULL, &mechnum) == SASL_OK) {
1640 if (mechnum>0) {
1641 prot_printf(popd_out,"%s",sasllist);
1642 }
1643 }
1644
1645 prot_printf(popd_out, ".\r\n");
1646 return;
1647 }
1648
1649 authtype = arg;
1650
1651 /* according to RFC 2449, since we advertise the "SASL" capability, we
1652 * must accept an optional second argument as an initial client
1653 * response (base64 encoded!).
1654 */
1655 while (*arg && !Uisspace(*arg)) {
1656 arg++;
1657 }
1658 if (Uisspace(*arg)) {
1659 /* null terminate authtype, get argument */
1660 *arg++ = '\0';
1661 } else {
1662 /* no optional client response */
1663 arg = NULL;
1664 }
1665
1666 r = saslserver(popd_saslconn, authtype, arg, "", "+ ", "",
1667 popd_in, popd_out, &sasl_result, NULL);
1668
1669 if (r) {
1670 const char *errorstring = NULL;
1671 const char *userid = "-notset-";
1672
1673 switch (r) {
1674 case IMAP_SASL_CANCEL:
1675 prot_printf(popd_out,
1676 "-ERR [AUTH] Client canceled authentication\r\n");
1677 break;
1678 case IMAP_SASL_PROTERR:
1679 errorstring = prot_error(popd_in);
1680
1681 prot_printf(popd_out,
1682 "-ERR [AUTH] Error reading client response: %s\r\n",
1683 errorstring ? errorstring : "");
1684 break;
1685 default:
1686 /* failed authentication */
1687 if (authtype) {
1688 if (sasl_result != SASL_NOUSER)
1689 sasl_getprop(popd_saslconn, SASL_USERNAME,
1690 (const void **) &userid);
1691
1692 syslog(LOG_NOTICE, "badlogin: %s %s (%s) [%s]",
1693 popd_clienthost, authtype, userid,
1694 sasl_errstring(sasl_result, NULL, NULL));
1695 } else {
1696 syslog(LOG_NOTICE, "badlogin: %s %s",
1697 popd_clienthost, authtype);
1698 }
1699
1700 failedloginpause = config_getduration(IMAPOPT_FAILEDLOGINPAUSE, 's');
1701 if (failedloginpause != 0) {
1702 sleep(failedloginpause);
1703 }
1704
1705 /* Don't allow user probing */
1706 if (sasl_result == SASL_NOUSER) sasl_result = SASL_BADAUTH;
1707
1708 prot_printf(popd_out, "-ERR [AUTH] authenticating: %s\r\n",
1709 sasl_errstring(sasl_result, NULL, NULL));
1710 }
1711
1712 free(popd_subfolder);
1713 popd_subfolder = NULL;
1714
1715 reset_saslconn(&popd_saslconn);
1716 return;
1717 }
1718
1719 /* successful authentication */
1720
1721 /* get the userid from SASL --- already canonicalized from
1722 * mysasl_proxy_policy()
1723 */
1724 sasl_result = sasl_getprop(popd_saslconn, SASL_USERNAME, &val);
1725 if (sasl_result != SASL_OK) {
1726 prot_printf(popd_out,
1727 "-ERR [AUTH] weird SASL error %d getting SASL_USERNAME\r\n",
1728 sasl_result);
1729 return;
1730 }
1731 canon_user = (const char *) val;
1732
1733 /* If we're proxying, the authzid may contain a subfolder,
1734 so re-canonify it */
1735 if (config_getswitch(IMAPOPT_POPSUBFOLDERS) && strchr(canon_user, '+')) {
1736 char userbuf[MAX_MAILBOX_BUFFER];
1737 unsigned userlen;
1738
1739 sasl_result = popd_canon_user(popd_saslconn, NULL, canon_user, 0,
1740 SASL_CU_AUTHID | SASL_CU_AUTHZID,
1741 NULL, userbuf, sizeof(userbuf), &userlen);
1742 if (sasl_result != SASL_OK) {
1743 prot_printf(popd_out,
1744 "-ERR [AUTH] SASL canonification error %d\r\n",
1745 sasl_result);
1746 return;
1747 }
1748
1749 popd_userid = xstrdup(userbuf);
1750 } else {
1751 popd_userid = xstrdup(canon_user);
1752 }
1753 syslog(LOG_NOTICE, "login: %s %s%s %s%s %s SESSIONID=<%s>", popd_clienthost,
1754 popd_userid, popd_subfolder ? popd_subfolder : "",
1755 authtype, popd_starttls_done ? "+TLS" : "", "User logged in", session_id());
1756
1757 if (!openinbox()) {
1758 sasl_getprop(popd_saslconn, SASL_SSF, &val);
1759 saslprops.ssf = *((sasl_ssf_t *) val);
1760
1761 prot_setsasl(popd_in, popd_saslconn);
1762 prot_setsasl(popd_out, popd_saslconn);
1763 }
1764 else {
1765 reset_saslconn(&popd_saslconn);
1766 }
1767 }
1768
1769 /*
1770 * Complete the login process by opening and locking the user's inbox
1771 */
openinbox(void)1772 int openinbox(void)
1773 {
1774 int myrights = 0;
1775 int r, log_level = LOG_ERR;
1776 const char *statusline = NULL;
1777 mbentry_t *mbentry = NULL;
1778 struct statusdata sdata = STATUSDATA_INIT;
1779 struct proc_limits limits;
1780 struct mboxevent *mboxevent;
1781
1782 /* send a Login event notification */
1783 if ((mboxevent = mboxevent_new(EVENT_LOGIN))) {
1784 mboxevent_set_access(mboxevent,
1785 buf_cstringnull_ifempty(&saslprops.iplocalport),
1786 buf_cstringnull_ifempty(&saslprops.ipremoteport),
1787 popd_userid, NULL, 0);
1788
1789 mboxevent_notify(&mboxevent);
1790 mboxevent_free(&mboxevent);
1791 }
1792
1793 const char *subfolder = popd_subfolder ? popd_subfolder + 1 : NULL;
1794 mbname_t *mbname = mbname_from_extsub(subfolder, &popd_namespace, popd_userid);
1795
1796 r = mboxlist_lookup(mbname_intname(mbname), &mbentry, NULL);
1797
1798 #ifdef USE_AUTOCREATE
1799 /* Try once again after autocreate_inbox */
1800 if (r == IMAP_MAILBOX_NONEXISTENT) {
1801 /* NOTE - if we have a subfolder, autocreateinbox should still create
1802 * it if it's an autocreate folder - otherwise tough luck */
1803 r = autocreate_user(&popd_namespace, popd_userid);
1804 if (!r) r = mboxlist_lookup(mbname_intname(mbname), &mbentry, NULL);
1805 }
1806 #endif
1807
1808 if (!r && (config_popuseacl = config_getswitch(IMAPOPT_POPUSEACL)) &&
1809 (!mbentry->acl ||
1810 !((myrights = cyrus_acl_myrights(popd_authstate, mbentry->acl)) & ACL_READ))) {
1811 r = (myrights & ACL_LOOKUP) ?
1812 IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
1813 }
1814 else if (!r && (mbentry->mbtype & MBTYPE_DELETED)) {
1815 r = IMAP_MAILBOX_NONEXISTENT;
1816 }
1817 else if (!r && (mbentry->mbtype & MBTYPE_RESERVE)) {
1818 r = IMAP_MAILBOX_RESERVED;
1819 }
1820 else if (!r && (mbentry->mbtype & MBTYPE_MOVING)) {
1821 r = IMAP_MAILBOX_MOVED;
1822 }
1823 if (r) {
1824 sleep(3);
1825 log_level = LOG_INFO;
1826 syslog(log_level, "Unable to open maildrop %s: %s",
1827 mbname_intname(mbname), error_message(r));
1828 prot_printf(popd_out,
1829 "-ERR [SYS/TEMP] Unable to open maildrop: %s\r\n",
1830 error_message(r));
1831 goto fail;
1832 }
1833
1834 if (mbentry->mbtype & MBTYPE_REMOTE) {
1835 /* remote mailbox */
1836 char userid[MAX_MAILBOX_NAME];
1837
1838 /* Make a working copy of userid in case we need to alter it */
1839 strlcpy(userid, popd_userid, sizeof(userid));
1840
1841 if (popd_subfolder) {
1842 /* Add the subfolder back to the userid for proxying */
1843 size_t n = strlen(popd_subfolder);
1844 char *p = (config_virtdomains && (p = strchr(userid, '@'))) ?
1845 p : userid + strlen(userid);
1846 memmove(p+n, p, strlen(p)+1);
1847 memcpy(p, popd_subfolder, n);
1848 }
1849
1850 backend = backend_connect(NULL, mbentry->server, &pop3_protocol,
1851 userid, NULL, &statusline, -1);
1852
1853 if (!backend) {
1854 syslog(LOG_ERR, "couldn't authenticate to backend server");
1855 prot_printf(popd_out, "-ERR%s",
1856 statusline ? statusline :
1857 " Authentication to backend server failed\r\n");
1858 prot_flush(popd_out);
1859
1860 goto fail;
1861 }
1862 }
1863 else if (config_getswitch(IMAPOPT_STATUSCACHE) &&
1864 !(r = status_lookup_mbname(mbname, popd_userid, STATUS_MESSAGES, &sdata)) &&
1865 !sdata.messages) {
1866 /* local mailbox (empty) -- don't bother opening the mailbox */
1867 syslog(LOG_INFO, "optimized mode for empty maildrop: %s", popd_userid);
1868 }
1869 else {
1870 /* local mailbox */
1871 uint32_t exists;
1872 int minpoll;
1873
1874 popd_login_time = time(0);
1875
1876 r = mailbox_open_iwl(mbname_intname(mbname), &popd_mailbox);
1877 if (r) {
1878 sleep(3);
1879 syslog(log_level, "Unable to open maildrop %s: %s",
1880 mbname_intname(mbname), error_message(r));
1881 prot_printf(popd_out,
1882 "-ERR [SYS/PERM] Unable to open maildrop: %s\r\n",
1883 error_message(r));
1884 goto fail;
1885 }
1886 popd_myrights = cyrus_acl_myrights(popd_authstate, popd_mailbox->acl);
1887 if (config_popuseacl && !(popd_myrights & ACL_READ)) {
1888 r = (popd_myrights & ACL_LOOKUP) ?
1889 IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
1890 log_level = LOG_INFO;
1891 }
1892
1893 if (r) {
1894 mailbox_close(&popd_mailbox);
1895 syslog(LOG_ERR, "Unable to lock maildrop %s: %s",
1896 mbname_intname(mbname), error_message(r));
1897 prot_printf(popd_out,
1898 "-ERR [IN-USE] Unable to lock maildrop: %s\r\n",
1899 error_message(r));
1900 goto fail;
1901 }
1902
1903 if ((minpoll = config_getduration(IMAPOPT_POPMINPOLL, 'm')) &&
1904 popd_mailbox->i.pop3_last_login + minpoll > popd_login_time) {
1905 syslog(LOG_ERR, "%s: Logins must be at least %d minute%s apart",
1906 mbname_intname(mbname),
1907 minpoll / 60, minpoll / 60 > 1 ? "s" : "");
1908 prot_printf(popd_out,
1909 "-ERR [LOGIN-DELAY] Logins must be at least %d minute%s apart\r\n",
1910 minpoll / 60, minpoll / 60 > 1 ? "s" : "");
1911 mailbox_close(&popd_mailbox);
1912 goto fail;
1913 }
1914
1915 free(popd_map);
1916 popd_map = (struct msg *)xmalloc(popd_mailbox->i.exists *
1917 sizeof(struct msg));
1918 config_popuseimapflags = config_getswitch(IMAPOPT_POPUSEIMAPFLAGS);
1919 exists = 0;
1920
1921 unsigned iterflags = ITER_SKIP_EXPUNGED;
1922 if (config_popuseimapflags) iterflags |= ITER_SKIP_DELETED;
1923
1924 struct mailbox_iter *iter = mailbox_iter_init(popd_mailbox, 0, iterflags);
1925
1926 const message_t *msg;
1927 while ((msg = mailbox_iter_step(iter))) {
1928 const struct index_record *record = msg_record(msg);
1929 if (popd_mailbox->i.pop3_show_after &&
1930 record->internaldate <= popd_mailbox->i.pop3_show_after) {
1931 /* Ignore messages older than the "show after" date */
1932 continue;
1933 }
1934
1935 popd_map[exists].recno = record->recno;
1936 popd_map[exists].uid = record->uid;
1937 popd_map[exists].size = record->size;
1938 popd_map[exists].deleted = 0;
1939 popd_map[exists].seen = 0;
1940 exists++;
1941
1942 if (exists >= popd_mailbox->i.exists)
1943 break; /* we're full! */
1944 }
1945
1946 mailbox_iter_done(&iter);
1947
1948 popd_exists = exists;
1949
1950 /* finished our initial read */
1951 mailbox_unlock_index(popd_mailbox, NULL);
1952 }
1953
1954 limits.procname = "pop3d";
1955 limits.clienthost = popd_clienthost;
1956 limits.userid = popd_userid;
1957 if (proc_checklimits(&limits)) {
1958 const char *sep = "";
1959 char part1[1024] = "";
1960 char part2[1024] = "";
1961 prot_printf(popd_out,
1962 "-ERR Too many open connections (");
1963 if (limits.maxhost) {
1964 prot_printf(popd_out, "%s%d of %d from %s", sep,
1965 limits.host, limits.maxhost, popd_clienthost);
1966 snprintf(part1, sizeof(part1), "%s%d of %d from %s", sep,
1967 limits.host, limits.maxhost, popd_clienthost);
1968 sep = ", ";
1969 }
1970 if (limits.maxuser) {
1971 prot_printf(popd_out, "%s%d of %d for %s", sep,
1972 limits.user, limits.maxuser, popd_userid);
1973 snprintf(part2, sizeof(part2), "%s%d of %d for %s", sep,
1974 limits.user, limits.maxuser, popd_userid);
1975 }
1976 prot_printf(popd_out, ")\r\n");
1977 syslog(LOG_ERR, "Too many open connections (%s%s)", part1, part2);
1978 mailbox_close(&popd_mailbox);
1979 goto fail;
1980 }
1981
1982 /* Create telemetry log */
1983 popd_logfd = telemetry_log(popd_userid, popd_in, popd_out, 0);
1984
1985 mboxlist_entry_free(&mbentry);
1986 mbname_free(&mbname);
1987
1988 if (statusline)
1989 prot_printf(popd_out, "+OK%s", statusline);
1990 else
1991 prot_printf(popd_out, "+OK Mailbox locked and ready SESSIONID=<%s>\r\n",
1992 session_id());
1993 prot_flush(popd_out);
1994
1995 return 0;
1996
1997 fail:
1998 mboxlist_entry_free(&mbentry);
1999 mbname_free(&mbname);
2000 free(popd_userid);
2001 popd_userid = 0;
2002 if (popd_subfolder) {
2003 free(popd_subfolder);
2004 popd_subfolder = 0;
2005 }
2006 auth_freestate(popd_authstate);
2007 popd_authstate = NULL;
2008 return 1;
2009 }
2010
blat(int msgno,int lines)2011 static int blat(int msgno, int lines)
2012 {
2013 FILE *msgfile;
2014 char buf[4096];
2015 const char *fname;
2016 int thisline = -2;
2017 struct index_record record;
2018
2019 /* XXX - map file */
2020
2021 memset(&record, 0, sizeof(struct index_record));
2022 record.recno = popd_map[msgno-1].recno;
2023 if (mailbox_reload_index_record(popd_mailbox, &record)) {
2024 prot_printf(popd_out, "-ERR [SYS/PERM] Could not read index record\r\n");
2025 return IMAP_IOERROR;
2026 }
2027
2028 fname = mailbox_record_fname(popd_mailbox, &record);
2029 msgfile = fopen(fname, "r");
2030 if (!msgfile) {
2031 prot_printf(popd_out, "-ERR [SYS/PERM] Could not read message file\r\n");
2032 return IMAP_IOERROR;
2033 }
2034 prot_printf(popd_out, "+OK Message follows\r\n");
2035 while (lines != thisline) {
2036 if (!fgets(buf, sizeof(buf), msgfile)) break;
2037
2038 if (thisline < 0) {
2039 if (buf[0] == '\r' && buf[1] == '\n') thisline = 0;
2040 }
2041 else thisline++;
2042
2043 if (buf[0] == '.')
2044 (void)prot_putc('.', popd_out);
2045 do {
2046 prot_printf(popd_out, "%s", buf);
2047 }
2048 while (buf[strlen(buf)-1] != '\n' && fgets(buf, sizeof(buf), msgfile));
2049 }
2050 fclose(msgfile);
2051
2052 /* Protect against messages not ending in CRLF */
2053 if (buf[strlen(buf)-1] != '\n') prot_printf(popd_out, "\r\n");
2054
2055 prot_printf(popd_out, ".\r\n");
2056
2057 /* Reset inactivity timer in case we spend a long time
2058 pushing data to the client over a slow link. */
2059 prot_resettimeout(popd_in);
2060
2061 return 0;
2062 }
2063
2064 /* Reset the given sasl_conn_t to a sane state */
reset_saslconn(sasl_conn_t ** conn)2065 static int reset_saslconn(sasl_conn_t **conn)
2066 {
2067 int ret;
2068 sasl_security_properties_t *secprops = NULL;
2069
2070 sasl_dispose(conn);
2071 /* do initialization typical of service_main */
2072 ret = sasl_server_new("pop", config_servername, NULL,
2073 buf_cstringnull_ifempty(&saslprops.iplocalport),
2074 buf_cstringnull_ifempty(&saslprops.ipremoteport),
2075 NULL, 0, conn);
2076 if(ret != SASL_OK) return ret;
2077
2078 secprops = mysasl_secprops(0);
2079 ret = sasl_setprop(*conn, SASL_SEC_PROPS, secprops);
2080 if(ret != SASL_OK) return ret;
2081 /* end of service_main initialization excepting SSF */
2082
2083 /* If we have TLS/SSL info, set it */
2084 if(saslprops.ssf) {
2085 ret = saslprops_set_tls(&saslprops, *conn);
2086 } else {
2087 ret = sasl_setprop(*conn, SASL_SSF_EXTERNAL, &extprops_ssf);
2088 }
2089
2090 if(ret != SASL_OK) return ret;
2091 /* End TLS/SSL Info */
2092
2093 return SASL_OK;
2094 }
2095
2096 /* we've authenticated the client, we've connected to the backend.
2097 now it's all up to them */
bitpipe(void)2098 static void bitpipe(void)
2099 {
2100 struct protgroup *protin = protgroup_new(2);
2101 int shutdown = 0;
2102 char buf[4096];
2103
2104 protgroup_insert(protin, popd_in);
2105 protgroup_insert(protin, backend->in);
2106
2107 do {
2108 /* Flush any buffered output */
2109 prot_flush(popd_out);
2110 prot_flush(backend->out);
2111
2112 /* check for shutdown file */
2113 if (shutdown_file(buf, sizeof(buf)) ||
2114 userdeny(popd_userid, config_ident, buf, sizeof(buf))) {
2115 shutdown = 1;
2116 goto done;
2117 }
2118 } while (!proxy_check_input(protin, popd_in, popd_out,
2119 backend->in, backend->out, 0));
2120
2121 done:
2122 /* ok, we're done. */
2123 protgroup_free(protin);
2124
2125 if (shutdown) {
2126 char *p;
2127 for (p = buf; *p == '['; p++); /* can't have [ be first char */
2128 prot_printf(popd_out, "-ERR [SYS/TEMP] %s\r\n", p);
2129 shut_down(0);
2130 }
2131
2132 return;
2133 }
2134
2135 /* Merge our read messages with the existing \Seen database */
update_seen(void)2136 static int update_seen(void)
2137 {
2138 unsigned msgno;
2139 struct index_record record;
2140 int r = 0;
2141
2142 if (!config_popuseimapflags)
2143 return 0;
2144
2145 if (config_popuseacl && !(popd_myrights & ACL_SETSEEN))
2146 return 0;
2147
2148 /* we know this mailbox must be owned by the user, because
2149 * all POP mailboxes are */
2150 for (msgno = 1; msgno <= popd_exists; msgno++) {
2151 if (!popd_map[msgno-1].seen)
2152 continue; /* don't even need to check */
2153 memset(&record, 0, sizeof(struct index_record));
2154 record.recno = popd_map[msgno-1].recno;
2155 if (mailbox_reload_index_record(popd_mailbox, &record))
2156 continue;
2157 if (record.internal_flags & FLAG_INTERNAL_EXPUNGED)
2158 continue; /* already expunged */
2159 if (record.system_flags & FLAG_SEEN)
2160 continue; /* already seen */
2161 record.system_flags |= FLAG_SEEN;
2162 r = mailbox_rewrite_index_record(popd_mailbox, &record);
2163 if (r) break;
2164 }
2165
2166 return r;
2167 }
2168