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