]> diplodocus.org Git - nmh/blob - mts/smtp/smtp.c
c973c9191500d417c425aa9f4f0660f273de1445
[nmh] / mts / smtp / smtp.c
1 /*
2 * smtp.c -- nmh SMTP interface
3 *
4 * This code is Copyright (c) 2002, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include "smtp.h"
11 #include <h/mts.h>
12 #include <signal.h>
13 #include <h/signals.h>
14
15 #ifdef CYRUS_SASL
16 #include <sasl/sasl.h>
17 #include <sasl/saslutil.h>
18 # if SASL_VERSION_FULL < 0x020125
19 /* Cyrus SASL 2.1.25 introduced the sasl_callback_ft prototype,
20 which has an explicit void parameter list, according to best
21 practice. So we need to cast to avoid compile warnings.
22 Provide this prototype for earlier versions. */
23 typedef int (*sasl_callback_ft)();
24 # endif /* SASL_VERSION_FULL < 0x020125 */
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <netdb.h>
29 #include <errno.h>
30 #endif /* CYRUS_SASL */
31
32 #ifdef TLS_SUPPORT
33 #include <openssl/ssl.h>
34 #include <openssl/err.h>
35 #endif /* TLS_SUPPORT */
36
37 /*
38 * This module implements an interface to SendMail very similar
39 * to the MMDF mm_(3) routines. The sm_() routines herein talk
40 * SMTP to a sendmail process, mapping SMTP reply codes into
41 * RP_-style codes.
42 */
43
44 /*
45 * On older 4.2BSD machines without the POSIX function `sigaction',
46 * the alarm handing stuff for time-outs will NOT work due to the way
47 * syscalls get restarted. This is not really crucial, since SendMail
48 * is generally well-behaved in this area.
49 */
50
51 #ifdef SENDMAILBUG
52 /*
53 * It appears that some versions of Sendmail will return Code 451
54 * when they don't really want to indicate a failure.
55 * "Code 451 almost always means sendmail has deferred; we don't
56 * really want bomb out at this point since sendmail will rectify
57 * things later." So, if you define SENDMAILBUG, Code 451 is
58 * considered the same as Code 250. Yuck!
59 */
60 #endif
61
62 #define TRUE 1
63 #define FALSE 0
64
65 #define NBITS ((sizeof (int)) * 8)
66
67 /*
68 * these codes must all be different!
69 */
70 #define SM_OPEN 300 /* Changed to 5 minutes to comply with a SHOULD in RFC 1123 */
71 #define SM_HELO 20
72 #define SM_RSET 15
73 #define SM_MAIL 301 /* changed to 5 minutes and a second (for uniqueness), see above */
74 #define SM_RCPT 302 /* see above */
75 #define SM_DATA 120 /* see above */
76 #define SM_TEXT 180 /* see above */
77 #define SM_DOT 600 /* see above */
78 #define SM_QUIT 30
79 #define SM_CLOS 10
80 #ifdef CYRUS_SASL
81 #define SM_AUTH 45
82 #endif /* CYRUS_SASL */
83
84 static int sm_addrs = 0;
85 static int sm_alarmed = 0;
86 static int sm_child = NOTOK;
87 static int sm_debug = 0;
88 static int sm_nl = TRUE;
89 static int sm_verbose = 0;
90
91 static FILE *sm_rfp = NULL;
92 static FILE *sm_wfp = NULL;
93
94 #ifdef CYRUS_SASL
95 /*
96 * Some globals needed by SASL
97 */
98
99 static sasl_conn_t *conn = NULL; /* SASL connection state */
100 static int sasl_complete = 0; /* Has authentication succeded? */
101 static sasl_ssf_t sasl_ssf; /* Our security strength factor */
102 static char *sasl_pw_context[2]; /* Context to pass into sm_get_pass */
103 static int maxoutbuf; /* Maximum crypto output buffer */
104 static char *sasl_outbuffer; /* SASL output buffer for encryption */
105 static int sasl_outbuflen; /* Current length of data in outbuf */
106 static int sm_get_user(void *, int, const char **, unsigned *);
107 static int sm_get_pass(sasl_conn_t *, void *, int, sasl_secret_t **);
108
109 static sasl_callback_t callbacks[] = {
110 { SASL_CB_USER, (sasl_callback_ft) sm_get_user, NULL },
111 #define SM_SASL_N_CB_USER 0
112 { SASL_CB_PASS, (sasl_callback_ft) sm_get_pass, NULL },
113 #define SM_SASL_N_CB_PASS 1
114 { SASL_CB_AUTHNAME, (sasl_callback_ft) sm_get_user, NULL },
115 #define SM_SASL_N_CB_AUTHNAME 2
116 { SASL_CB_LIST_END, NULL, NULL },
117 };
118
119 #else /* CYRUS_SASL */
120 int sasl_ssf = 0;
121 #endif /* CYRUS_SASL */
122
123 #ifdef TLS_SUPPORT
124 static SSL_CTX *sslctx = NULL;
125 static SSL *ssl = NULL;
126 static BIO *sbior = NULL;
127 static BIO *sbiow = NULL;
128 static BIO *io = NULL;
129
130 static int tls_negotiate(void);
131 #endif /* TLS_SUPPORT */
132
133 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
134 #define SASL_MAXRECVBUF 65536
135 static int sm_fgetc(FILE *);
136 static char *sasl_inbuffer; /* SASL input buffer for encryption */
137 static char *sasl_inptr; /* Pointer to current inbuf position */
138 static int sasl_inbuflen; /* Current length of data in inbuf */
139 #else
140 #define sm_fgetc fgetc
141 #endif
142
143 static int tls_active = 0;
144
145 static char *sm_noreply = "No reply text given";
146 static char *sm_moreply = "; ";
147
148 struct smtp sm_reply; /* global... */
149
150 #define MAXEHLO 20
151
152 static int doingEHLO;
153 char *EHLOkeys[MAXEHLO + 1];
154
155 /*
156 * static prototypes
157 */
158 static int smtp_init (char *, char *, char *, int, int, int, int, int, int,
159 char *, char *, int);
160 static int sendmail_init (char *, char *, int, int, int, int, int, int,
161 char *, char *);
162
163 static int rclient (char *, char *);
164 static int sm_ierror (char *fmt, ...);
165 static int smtalk (int time, char *fmt, ...);
166 static int sm_wrecord (char *, int);
167 static int sm_wstream (char *, int);
168 static int sm_werror (void);
169 static int smhear (void);
170 static int sm_rrecord (char *, int *);
171 static int sm_rerror (int);
172 static void alrmser (int);
173 static char *EHLOset (char *);
174 static int sm_fwrite(char *, int);
175 static int sm_fputs(char *);
176 static int sm_fputc(int);
177 static void sm_fflush(void);
178 static int sm_fgets(char *, int, FILE *);
179
180 #ifdef CYRUS_SASL
181 /*
182 * Function prototypes needed for SASL
183 */
184
185 static int sm_auth_sasl(char *, int, char *, char *);
186 #endif /* CYRUS_SASL */
187
188 int
189 sm_init (char *client, char *server, char *port, int watch, int verbose,
190 int debug, int queued, int sasl, int saslssf,
191 char *saslmech, char *user, int tls)
192 {
193 if (sm_mts == MTS_SMTP)
194 return smtp_init (client, server, port, watch, verbose,
195 debug, queued, sasl, saslssf, saslmech,
196 user, tls);
197 else
198 return sendmail_init (client, server, watch, verbose,
199 debug, queued, sasl, saslssf, saslmech,
200 user);
201 }
202
203 static int
204 smtp_init (char *client, char *server, char *port, int watch, int verbose,
205 int debug, int queued,
206 int sasl, int saslssf, char *saslmech, char *user, int tls)
207 {
208 int result, sd1, sd2;
209 #ifdef CYRUS_SASL
210 char *server_mechs;
211 #else /* CYRUS_SASL */
212 NMH_UNUSED (sasl);
213 NMH_UNUSED (saslssf);
214 NMH_UNUSED (saslmech);
215 NMH_UNUSED (user);
216 #endif /* CYRUS_SASL */
217
218 if (watch)
219 verbose = TRUE;
220
221 sm_verbose = verbose;
222 sm_debug = debug;
223
224 if (sm_rfp != NULL && sm_wfp != NULL)
225 goto send_options;
226
227 if (client == NULL || *client == '\0') {
228 if (clientname) {
229 client = clientname;
230 } else {
231 client = LocalName(1); /* no clientname -> LocalName */
232 }
233 }
234
235 /*
236 * Last-ditch check just in case client still isn't set to anything
237 */
238
239 if (client == NULL || *client == '\0')
240 client = "localhost";
241
242 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
243 sasl_inbuffer = malloc(SASL_MAXRECVBUF);
244 if (!sasl_inbuffer)
245 return sm_ierror("Unable to allocate %d bytes for read buffer",
246 SASL_MAXRECVBUF);
247 #endif /* CYRUS_SASL || TLS_SUPPORT */
248
249 if ((sd1 = rclient (server, port)) == NOTOK)
250 return RP_BHST;
251
252 if ((sd2 = dup (sd1)) == NOTOK) {
253 close (sd1);
254 return sm_ierror ("unable to dup");
255 }
256
257 SIGNAL (SIGALRM, alrmser);
258 SIGNAL (SIGPIPE, SIG_IGN);
259
260 if ((sm_rfp = fdopen (sd1, "r")) == NULL
261 || (sm_wfp = fdopen (sd2, "w")) == NULL) {
262 close (sd1);
263 close (sd2);
264 sm_rfp = sm_wfp = NULL;
265 return sm_ierror ("unable to fdopen");
266 }
267
268 tls_active = 0;
269
270 #ifdef TLS_SUPPORT
271 /*
272 * If tls == 2, that means that the user requested "initial" TLS,
273 * which happens right after the connection has opened. Do that
274 * negotiation now
275 */
276
277 if (tls == 2) {
278 result = tls_negotiate();
279
280 /*
281 * Note: if tls_negotiate() fails it will call sm_end() for us,
282 * which closes the connection.
283 */
284 if (result != RP_OK)
285 return result;
286 }
287 #endif /* TLS_SUPPORT */
288
289 sm_alarmed = 0;
290 alarm (SM_OPEN);
291 result = smhear ();
292 alarm (0);
293
294 switch (result) {
295 case 220:
296 break;
297
298 default:
299 sm_end (NOTOK);
300 return RP_RPLY;
301 }
302
303 /*
304 * Give EHLO or HELO command
305 */
306
307 doingEHLO = 1;
308 result = smtalk (SM_HELO, "EHLO %s", client);
309 doingEHLO = 0;
310
311 if (result >= 500 && result <= 599)
312 result = smtalk (SM_HELO, "HELO %s", client);
313
314 if (result != 250) {
315 sm_end (NOTOK);
316 return RP_RPLY;
317 }
318
319 #ifdef TLS_SUPPORT
320 /*
321 * If the user requested TLS support, then try to do the STARTTLS command
322 * as part of the initial dialog. Assuming this works, we then need to
323 * restart the EHLO dialog after TLS negotiation is complete.
324 */
325
326 if (tls == 1) {
327 if (! EHLOset("STARTTLS")) {
328 sm_end(NOTOK);
329 return sm_ierror("SMTP server does not support TLS");
330 }
331
332 result = smtalk(SM_HELO, "STARTTLS");
333
334 if (result != 220) {
335 sm_end(NOTOK);
336 return RP_RPLY;
337 }
338
339 /*
340 * Okay, the other side should be waiting for us to start TLS
341 * negotiation. Oblige them.
342 */
343
344 result = tls_negotiate();
345
346 if (result != RP_OK)
347 return result;
348
349 doingEHLO = 1;
350 result = smtalk (SM_HELO, "EHLO %s", client);
351 doingEHLO = 0;
352
353 if (result != 250) {
354 sm_end (NOTOK);
355 return RP_RPLY;
356 }
357 }
358 #else /* TLS_SUPPORT */
359 NMH_UNUSED (tls);
360 #endif /* TLS_SUPPORT */
361
362 #ifdef CYRUS_SASL
363 /*
364 * If the user asked for SASL, then check to see if the SMTP server
365 * supports it. Otherwise, error out (because the SMTP server
366 * might have been spoofed; we don't want to just silently not
367 * do authentication
368 */
369
370 if (sasl) {
371 if (! (server_mechs = EHLOset("AUTH"))) {
372 sm_end(NOTOK);
373 return sm_ierror("SMTP server does not support SASL");
374 }
375
376 if (saslmech && stringdex(saslmech, server_mechs) == -1) {
377 sm_end(NOTOK);
378 return sm_ierror("Requested SASL mech \"%s\" is not in the "
379 "list of supported mechanisms:\n%s",
380 saslmech, server_mechs);
381 }
382
383 if (sm_auth_sasl(user, saslssf, saslmech ? saslmech : server_mechs,
384 server) != RP_OK) {
385 sm_end(NOTOK);
386 return NOTOK;
387 }
388 }
389 #endif /* CYRUS_SASL */
390
391 send_options: ;
392 if (watch && EHLOset ("XVRB"))
393 smtalk (SM_HELO, "VERB on");
394 if (queued && EHLOset ("XQUE"))
395 smtalk (SM_HELO, "QUED");
396
397 return RP_OK;
398 }
399
400 int
401 sendmail_init (char *client, char *server, int watch, int verbose,
402 int debug, int queued,
403 int sasl, int saslssf, char *saslmech, char *user)
404 {
405 unsigned int i, result, vecp;
406 int pdi[2], pdo[2];
407 char *vec[15];
408 #ifdef CYRUS_SASL
409 char *server_mechs;
410 #else /* CYRUS_SASL */
411 NMH_UNUSED (server);
412 NMH_UNUSED (sasl);
413 NMH_UNUSED (saslssf);
414 NMH_UNUSED (saslmech);
415 NMH_UNUSED (user);
416 #endif /* CYRUS_SASL */
417
418 if (watch)
419 verbose = TRUE;
420
421 sm_verbose = verbose;
422 sm_debug = debug;
423 if (sm_rfp != NULL && sm_wfp != NULL)
424 return RP_OK;
425
426 if (client == NULL || *client == '\0') {
427 if (clientname)
428 client = clientname;
429 else
430 client = LocalName(1); /* no clientname -> LocalName */
431 }
432
433 /*
434 * Last-ditch check just in case client still isn't set to anything
435 */
436
437 if (client == NULL || *client == '\0')
438 client = "localhost";
439
440 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
441 sasl_inbuffer = malloc(SASL_MAXRECVBUF);
442 if (!sasl_inbuffer)
443 return sm_ierror("Unable to allocate %d bytes for read buffer",
444 SASL_MAXRECVBUF);
445 #endif /* CYRUS_SASL || TLS_SUPPORT */
446
447 if (pipe (pdi) == NOTOK)
448 return sm_ierror ("no pipes");
449 if (pipe (pdo) == NOTOK) {
450 close (pdi[0]);
451 close (pdi[1]);
452 return sm_ierror ("no pipes");
453 }
454
455 for (i = 0; (sm_child = fork ()) == NOTOK && i < 5; i++)
456 sleep (5);
457
458 switch (sm_child) {
459 case NOTOK:
460 close (pdo[0]);
461 close (pdo[1]);
462 close (pdi[0]);
463 close (pdi[1]);
464 return sm_ierror ("unable to fork");
465
466 case OK:
467 if (pdo[0] != fileno (stdin))
468 dup2 (pdo[0], fileno (stdin));
469 if (pdi[1] != fileno (stdout))
470 dup2 (pdi[1], fileno (stdout));
471 if (pdi[1] != fileno (stderr))
472 dup2 (pdi[1], fileno (stderr));
473 for (i = fileno (stderr) + 1; i < NBITS; i++)
474 close (i);
475
476 vecp = 0;
477 vec[vecp++] = r1bindex (sendmail, '/');
478 vec[vecp++] = "-bs";
479 vec[vecp++] = watch ? "-odi" : queued ? "-odq" : "-odb";
480 vec[vecp++] = "-oem";
481 vec[vecp++] = "-om";
482 if (verbose)
483 vec[vecp++] = "-ov";
484 vec[vecp++] = NULL;
485
486 setgid (getegid ());
487 setuid (geteuid ());
488 execvp (sendmail, vec);
489 fprintf (stderr, "unable to exec ");
490 perror (sendmail);
491 _exit (-1); /* NOTREACHED */
492
493 default:
494 SIGNAL (SIGALRM, alrmser);
495 SIGNAL (SIGPIPE, SIG_IGN);
496
497 close (pdi[1]);
498 close (pdo[0]);
499 if ((sm_rfp = fdopen (pdi[0], "r")) == NULL
500 || (sm_wfp = fdopen (pdo[1], "w")) == NULL) {
501 close (pdi[0]);
502 close (pdo[1]);
503 sm_rfp = sm_wfp = NULL;
504 return sm_ierror ("unable to fdopen");
505 }
506 sm_alarmed = 0;
507 alarm (SM_OPEN);
508 result = smhear ();
509 alarm (0);
510 switch (result) {
511 case 220:
512 break;
513
514 default:
515 sm_end (NOTOK);
516 return RP_RPLY;
517 }
518
519 doingEHLO = 1;
520 result = smtalk (SM_HELO, "EHLO %s", client);
521 doingEHLO = 0;
522
523 if (500 <= result && result <= 599)
524 result = smtalk (SM_HELO, "HELO %s", client);
525
526 switch (result) {
527 case 250:
528 break;
529
530 default:
531 sm_end (NOTOK);
532 return RP_RPLY;
533 }
534
535 #ifdef CYRUS_SASL
536 /*
537 * If the user asked for SASL, then check to see if the SMTP server
538 * supports it. Otherwise, error out (because the SMTP server
539 * might have been spoofed; we don't want to just silently not
540 * do authentication
541 */
542
543 if (sasl) {
544 if (! (server_mechs = EHLOset("AUTH"))) {
545 sm_end(NOTOK);
546 return sm_ierror("SMTP server does not support SASL");
547 }
548
549 if (saslmech && stringdex(saslmech, server_mechs) == -1) {
550 sm_end(NOTOK);
551 return sm_ierror("Requested SASL mech \"%s\" is not in the "
552 "list of supported mechanisms:\n%s",
553 saslmech, server_mechs);
554 }
555
556 if (sm_auth_sasl(user, saslssf, saslmech ? saslmech : server_mechs,
557 server) != RP_OK) {
558 sm_end(NOTOK);
559 return NOTOK;
560 }
561 }
562 #endif /* CYRUS_SASL */
563
564 if (watch)
565 smtalk (SM_HELO, "VERB on");
566
567 return RP_OK;
568 }
569 }
570
571 static int
572 rclient (char *server, char *service)
573 {
574 int sd;
575 char response[BUFSIZ];
576
577 if ((sd = client (server, service, response, sizeof(response),
578 sm_debug)) != NOTOK)
579 return sd;
580
581 sm_ierror ("%s", response);
582 return NOTOK;
583 }
584
585 int
586 sm_winit (char *from)
587 {
588 switch (smtalk (SM_MAIL, "MAIL FROM:<%s>", from)) {
589 case 250:
590 sm_addrs = 0;
591 return RP_OK;
592
593 case 500:
594 case 501:
595 case 552:
596 return RP_PARM;
597
598 default:
599 return RP_RPLY;
600 }
601 }
602
603
604 int
605 sm_wadr (char *mbox, char *host, char *path)
606 {
607 switch (smtalk (SM_RCPT, host && *host ? "RCPT TO:<%s%s@%s>"
608 : "RCPT TO:<%s%s>",
609 path ? path : "", mbox, host)) {
610 case 250:
611 case 251:
612 sm_addrs++;
613 return RP_OK;
614
615 case 451:
616 #ifdef SENDMAILBUG
617 sm_addrs++;
618 return RP_OK;
619 #endif /* SENDMAILBUG */
620 case 421:
621 case 450:
622 case 452:
623 return RP_NO;
624
625 case 500:
626 case 501:
627 return RP_PARM;
628
629 case 550:
630 case 551:
631 case 552:
632 case 553:
633 return RP_USER;
634
635 default:
636 return RP_RPLY;
637 }
638 }
639
640
641 int
642 sm_waend (void)
643 {
644 switch (smtalk (SM_DATA, "DATA")) {
645 case 354:
646 sm_nl = TRUE;
647 return RP_OK;
648
649 case 451:
650 #ifdef SENDMAILBUG
651 sm_nl = TRUE;
652 return RP_OK;
653 #endif /* SENDMAILBUG */
654 case 421:
655 return RP_NO;
656
657 case 500:
658 case 501:
659 case 503:
660 case 554:
661 return RP_NDEL;
662
663 default:
664 return RP_RPLY;
665 }
666 }
667
668
669 int
670 sm_wtxt (char *buffer, int len)
671 {
672 int result;
673
674 sm_alarmed = 0;
675 alarm (SM_TEXT);
676 result = sm_wstream (buffer, len);
677 alarm (0);
678
679 return (result == NOTOK ? RP_BHST : RP_OK);
680 }
681
682
683 int
684 sm_wtend (void)
685 {
686 if (sm_wstream ((char *) NULL, 0) == NOTOK)
687 return RP_BHST;
688
689 switch (smtalk (SM_DOT + 3 * sm_addrs, ".")) {
690 case 250:
691 case 251:
692 return RP_OK;
693
694 case 451:
695 #ifdef SENDMAILBUG
696 return RP_OK;
697 #endif /* SENDMAILBUG */
698 case 452:
699 default:
700 return RP_NO;
701
702 case 552:
703 case 554:
704 return RP_NDEL;
705 }
706 }
707
708
709 int
710 sm_end (int type)
711 {
712 int status;
713 struct smtp sm_note;
714
715 if (sm_mts == MTS_SENDMAIL_SMTP) {
716 switch (sm_child) {
717 case NOTOK:
718 case OK:
719 return RP_OK;
720
721 default:
722 break;
723 }
724 }
725
726 if (sm_rfp == NULL && sm_wfp == NULL)
727 return RP_OK;
728
729 switch (type) {
730 case OK:
731 smtalk (SM_QUIT, "QUIT");
732 break;
733
734 case NOTOK:
735 sm_note.code = sm_reply.code;
736 sm_note.length = sm_reply.length;
737 memcpy (sm_note.text, sm_reply.text, sm_reply.length + 1);/* fall */
738 case DONE:
739 if (smtalk (SM_RSET, "RSET") == 250 && type == DONE)
740 return RP_OK;
741 if (sm_mts == MTS_SMTP)
742 smtalk (SM_QUIT, "QUIT");
743 else {
744 /* The SIGPIPE block replaces old calls to discard ().
745 We're not sure what the discard () calls were for,
746 maybe to prevent deadlock on old systems. In any
747 case, blocking SIGPIPE should be harmless.
748 Because the file handles are closed below, leave it
749 blocked. */
750 sigset_t set, oset;
751 sigemptyset (&set);
752 sigaddset (&set, SIGPIPE);
753 sigprocmask (SIG_BLOCK, &set, &oset);
754
755 kill (sm_child, SIGKILL);
756 sm_child = NOTOK;
757 }
758 if (type == NOTOK) {
759 sm_reply.code = sm_note.code;
760 sm_reply.length = sm_note.length;
761 memcpy (sm_reply.text, sm_note.text, sm_note.length + 1);
762 }
763 break;
764 }
765
766 #ifdef TLS_SUPPORT
767 if (tls_active) {
768 BIO_ssl_shutdown(io);
769 BIO_free_all(io);
770 }
771 #endif /* TLS_SUPPORT */
772
773 if (sm_rfp != NULL) {
774 alarm (SM_CLOS);
775 fclose (sm_rfp);
776 alarm (0);
777 }
778 if (sm_wfp != NULL) {
779 alarm (SM_CLOS);
780 fclose (sm_wfp);
781 alarm (0);
782 }
783
784 if (sm_mts == MTS_SMTP) {
785 status = 0;
786 #ifdef CYRUS_SASL
787 if (conn) {
788 sasl_dispose(&conn);
789 if (sasl_outbuffer) {
790 free(sasl_outbuffer);
791 }
792 }
793 if (sasl_inbuffer)
794 free(sasl_inbuffer);
795 #endif /* CYRUS_SASL */
796 } else if (sm_child != NOTOK) {
797 status = pidwait (sm_child, OK);
798 sm_child = NOTOK;
799 } else {
800 status = OK;
801 }
802
803 sm_rfp = sm_wfp = NULL;
804 return (status ? RP_BHST : RP_OK);
805 }
806
807 #ifdef CYRUS_SASL
808 /*
809 * This function implements SASL authentication for SMTP. If this function
810 * completes successfully, then authentication is successful and we've
811 * (optionally) negotiated a security layer.
812 */
813 static int
814 sm_auth_sasl(char *user, int saslssf, char *mechlist, char *inhost)
815 {
816 int result, status;
817 unsigned int buflen, outlen;
818 char *buf, outbuf[BUFSIZ], host[NI_MAXHOST];
819 const char *chosen_mech;
820 sasl_security_properties_t secprops;
821 sasl_ssf_t *ssf;
822 int *outbufmax;
823
824 /*
825 * Initialize the callback contexts
826 */
827
828 if (user == NULL)
829 user = getusername();
830
831 callbacks[SM_SASL_N_CB_USER].context = user;
832 callbacks[SM_SASL_N_CB_AUTHNAME].context = user;
833
834 /*
835 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
836 * to us on the command line, then call getpeername and do a
837 * reverse-address lookup on the IP address to get the name.
838 */
839
840 memset(host, 0, sizeof(host));
841
842 if (!inhost) {
843 struct sockaddr_storage sin;
844 socklen_t len = sizeof(sin);
845 int result;
846
847 if (getpeername(fileno(sm_wfp), (struct sockaddr *) &sin, &len) < 0) {
848 sm_ierror("getpeername on SMTP socket failed: %s",
849 strerror(errno));
850 return NOTOK;
851 }
852
853 result = getnameinfo((struct sockaddr *) &sin, len, host, sizeof(host),
854 NULL, 0, NI_NAMEREQD);
855 if (result != 0) {
856 sm_ierror("Unable to look up name of connected host: %s",
857 gai_strerror(result));
858 return NOTOK;
859 }
860 } else {
861 strncpy(host, inhost, sizeof(host) - 1);
862 }
863
864 sasl_pw_context[0] = host;
865 sasl_pw_context[1] = user;
866
867 callbacks[SM_SASL_N_CB_PASS].context = sasl_pw_context;
868
869 result = sasl_client_init(callbacks);
870
871 if (result != SASL_OK) {
872 sm_ierror("SASL library initialization failed: %s",
873 sasl_errstring(result, NULL, NULL));
874 return NOTOK;
875 }
876
877 result = sasl_client_new("smtp", host, NULL, NULL, NULL, 0, &conn);
878
879 if (result != SASL_OK) {
880 sm_ierror("SASL client initialization failed: %s",
881 sasl_errstring(result, NULL, NULL));
882 return NOTOK;
883 }
884
885 /*
886 * Initialize the security properties. But if TLS is active, then
887 * don't negotiate encryption here.
888 */
889
890 memset(&secprops, 0, sizeof(secprops));
891 secprops.maxbufsize = SASL_MAXRECVBUF;
892 secprops.max_ssf =
893 tls_active ? 0 : (saslssf != -1 ? (unsigned int) saslssf : UINT_MAX);
894
895 result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
896
897 if (result != SASL_OK) {
898 sm_ierror("SASL security property initialization failed: %s",
899 sasl_errstring(result, NULL, NULL));
900 return NOTOK;
901 }
902
903 /*
904 * Start the actual protocol. Feed the mech list into the library
905 * and get out a possible initial challenge
906 */
907
908 result = sasl_client_start(conn, mechlist, NULL, (const char **) &buf,
909 &buflen, (const char **) &chosen_mech);
910
911 if (result != SASL_OK && result != SASL_CONTINUE) {
912 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn));
913 return NOTOK;
914 }
915
916 /*
917 * If we got an initial challenge, send it as part of the AUTH
918 * command; otherwise, just send a plain AUTH command.
919 */
920
921 if (buflen) {
922 status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
923 if (status != SASL_OK) {
924 sm_ierror("SASL base64 encode failed: %s",
925 sasl_errstring(status, NULL, NULL));
926 return NOTOK;
927 }
928
929 status = smtalk(SM_AUTH, "AUTH %s %s", chosen_mech, outbuf);
930 } else
931 status = smtalk(SM_AUTH, "AUTH %s", chosen_mech);
932
933 /*
934 * Now we loop until we either fail, get a SASL_OK, or a 235
935 * response code. Receive the challenges and process them until
936 * we're all done.
937 */
938
939 while (result == SASL_CONTINUE) {
940
941 /*
942 * If we get a 235 response, that means authentication has
943 * succeeded and we need to break out of the loop (yes, even if
944 * we still get SASL_CONTINUE from sasl_client_step()).
945 *
946 * Otherwise, if we get a message that doesn't seem to be a
947 * valid response, then abort
948 */
949
950 if (status == 235)
951 break;
952 else if (status < 300 || status > 399)
953 return RP_BHST;
954
955 /*
956 * Special case; a zero-length response from the SMTP server
957 * is returned as a single =. If we get that, then set buflen
958 * to be zero. Otherwise, just decode the response.
959 */
960
961 if (strcmp("=", sm_reply.text) == 0) {
962 outlen = 0;
963 } else {
964 result = sasl_decode64(sm_reply.text, sm_reply.length,
965 outbuf, sizeof(outbuf), &outlen);
966
967 if (result != SASL_OK) {
968 smtalk(SM_AUTH, "*");
969 sm_ierror("SASL base64 decode failed: %s",
970 sasl_errstring(result, NULL, NULL));
971 return NOTOK;
972 }
973 }
974
975 result = sasl_client_step(conn, outbuf, outlen, NULL,
976 (const char **) &buf, &buflen);
977
978 if (result != SASL_OK && result != SASL_CONTINUE) {
979 smtalk(SM_AUTH, "*");
980 sm_ierror("SASL client negotiation failed: %s",
981 sasl_errstring(result, NULL, NULL));
982 return NOTOK;
983 }
984
985 status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
986
987 if (status != SASL_OK) {
988 smtalk(SM_AUTH, "*");
989 sm_ierror("SASL base64 encode failed: %s",
990 sasl_errstring(status, NULL, NULL));
991 return NOTOK;
992 }
993
994 status = smtalk(SM_AUTH, outbuf);
995 }
996
997 /*
998 * Make sure that we got the correct response
999 */
1000
1001 if (status < 200 || status > 299)
1002 return RP_BHST;
1003
1004 /*
1005 * We _should_ have completed the authentication successfully.
1006 * Get a few properties from the authentication exchange.
1007 */
1008
1009 result = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **) &outbufmax);
1010
1011 if (result != SASL_OK) {
1012 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1013 sasl_errstring(result, NULL, NULL));
1014 return NOTOK;
1015 }
1016
1017 maxoutbuf = *outbufmax;
1018
1019 result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf);
1020
1021 sasl_ssf = *ssf;
1022
1023 if (result != SASL_OK) {
1024 sm_ierror("Cannot retrieve SASL negotiated security strength "
1025 "factor: %s", sasl_errstring(result, NULL, NULL));
1026 return NOTOK;
1027 }
1028
1029 if (sasl_ssf > 0) {
1030 sasl_outbuffer = malloc(maxoutbuf);
1031
1032 if (sasl_outbuffer == NULL) {
1033 sm_ierror("Unable to allocate %d bytes for SASL output "
1034 "buffer", maxoutbuf);
1035 return NOTOK;
1036 }
1037 sasl_outbuflen = 0;
1038 sasl_inbuflen = 0;
1039 sasl_inptr = sasl_inbuffer;
1040 } else {
1041 sasl_outbuffer = NULL;
1042 /* Don't NULL out sasl_inbuffer because it could be used in
1043 sm_fgetc (). */
1044 }
1045
1046 sasl_complete = 1;
1047
1048 return RP_OK;
1049 }
1050
1051 /*
1052 * Our callback functions to feed data to the SASL library
1053 */
1054
1055 static int
1056 sm_get_user(void *context, int id, const char **result, unsigned *len)
1057 {
1058 char *user = (char *) context;
1059
1060 if (! result || ((id != SASL_CB_USER) && (id != SASL_CB_AUTHNAME)))
1061 return SASL_BADPARAM;
1062
1063 *result = user;
1064 if (len)
1065 *len = strlen(user);
1066
1067 return SASL_OK;
1068 }
1069
1070 static int
1071 sm_get_pass(sasl_conn_t *conn, void *context, int id,
1072 sasl_secret_t **psecret)
1073 {
1074 char **pw_context = (char **) context;
1075 char *pass = NULL;
1076 int len;
1077
1078 NMH_UNUSED (conn);
1079
1080 if (! psecret || id != SASL_CB_PASS)
1081 return SASL_BADPARAM;
1082
1083 ruserpass(pw_context[0], &(pw_context[1]), &pass);
1084
1085 len = strlen(pass);
1086
1087 *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len);
1088
1089 if (! *psecret) {
1090 free(pass);
1091 return SASL_NOMEM;
1092 }
1093
1094 (*psecret)->len = len;
1095 strcpy((char *) (*psecret)->data, pass);
1096 /* free(pass); */
1097
1098 return SASL_OK;
1099 }
1100 #endif /* CYRUS_SASL */
1101
1102 static int
1103 sm_ierror (char *fmt, ...)
1104 {
1105 va_list ap;
1106
1107 va_start(ap, fmt);
1108 vsnprintf (sm_reply.text, sizeof(sm_reply.text), fmt, ap);
1109 va_end(ap);
1110
1111 sm_reply.length = strlen (sm_reply.text);
1112 sm_reply.code = NOTOK;
1113
1114 return RP_BHST;
1115 }
1116
1117 static int
1118 smtalk (int time, char *fmt, ...)
1119 {
1120 va_list ap;
1121 int result;
1122 char buffer[BUFSIZ];
1123
1124 va_start(ap, fmt);
1125 vsnprintf (buffer, sizeof(buffer), fmt, ap);
1126 va_end(ap);
1127
1128 if (sm_debug) {
1129 if (sasl_ssf)
1130 printf("(sasl-encrypted) ");
1131 if (tls_active)
1132 printf("(tls-encrypted) ");
1133 printf ("=> %s\n", buffer);
1134 fflush (stdout);
1135 }
1136
1137 sm_alarmed = 0;
1138 alarm ((unsigned) time);
1139 if ((result = sm_wrecord (buffer, strlen (buffer))) != NOTOK)
1140 result = smhear ();
1141 alarm (0);
1142
1143 return result;
1144 }
1145
1146
1147 /*
1148 * write the buffer to the open SMTP channel
1149 */
1150
1151 static int
1152 sm_wrecord (char *buffer, int len)
1153 {
1154 if (sm_wfp == NULL)
1155 return sm_werror ();
1156
1157 sm_fwrite (buffer, len);
1158 sm_fputs ("\r\n");
1159 sm_fflush ();
1160
1161 return (ferror (sm_wfp) ? sm_werror () : OK);
1162 }
1163
1164
1165 static int
1166 sm_wstream (char *buffer, int len)
1167 {
1168 char *bp;
1169 static char lc = '\0';
1170
1171 if (sm_wfp == NULL)
1172 return sm_werror ();
1173
1174 if (buffer == NULL && len == 0) {
1175 if (lc != '\n')
1176 sm_fputs ("\r\n");
1177 lc = '\0';
1178 return (ferror (sm_wfp) ? sm_werror () : OK);
1179 }
1180
1181 for (bp = buffer; len > 0; bp++, len--) {
1182 switch (*bp) {
1183 case '\n':
1184 sm_nl = TRUE;
1185 sm_fputc ('\r');
1186 break;
1187
1188 case '.':
1189 if (sm_nl)
1190 sm_fputc ('.');/* FALL THROUGH */
1191 default:
1192 sm_nl = FALSE;
1193 }
1194 sm_fputc (*bp);
1195 if (ferror (sm_wfp))
1196 return sm_werror ();
1197 }
1198
1199 if (bp > buffer)
1200 lc = *--bp;
1201 return (ferror (sm_wfp) ? sm_werror () : OK);
1202 }
1203
1204 /*
1205 * Write out to the network, but do buffering for SASL (if enabled)
1206 */
1207
1208 static int
1209 sm_fwrite(char *buffer, int len)
1210 {
1211 #ifdef CYRUS_SASL
1212 const char *output;
1213 unsigned int outputlen;
1214
1215 if (sasl_complete == 0 || sasl_ssf == 0) {
1216 #endif /* CYRUS_SASL */
1217 #ifdef TLS_SUPPORT
1218 if (tls_active) {
1219 int ret;
1220
1221 ret = BIO_write(io, buffer, len);
1222
1223 if (ret <= 0) {
1224 sm_ierror("TLS error during write: %s",
1225 ERR_error_string(ERR_get_error(), NULL));
1226 return NOTOK;
1227 }
1228 } else
1229 #endif /* TLS_SUPPORT */
1230 fwrite(buffer, sizeof(*buffer), len, sm_wfp);
1231 #ifdef CYRUS_SASL
1232 } else {
1233 while (len >= maxoutbuf - sasl_outbuflen) {
1234 memcpy(sasl_outbuffer + sasl_outbuflen, buffer,
1235 maxoutbuf - sasl_outbuflen);
1236 len -= maxoutbuf - sasl_outbuflen;
1237 sasl_outbuflen = 0;
1238
1239 if (sasl_encode(conn, sasl_outbuffer, maxoutbuf,
1240 &output, &outputlen) != SASL_OK) {
1241 sm_ierror("Unable to SASL encode connection data: %s",
1242 sasl_errdetail(conn));
1243 return NOTOK;
1244 }
1245
1246 fwrite(output, sizeof(*output), outputlen, sm_wfp);
1247 }
1248
1249 if (len > 0) {
1250 memcpy(sasl_outbuffer + sasl_outbuflen, buffer, len);
1251 sasl_outbuflen += len;
1252 }
1253 }
1254 #endif /* CYRUS_SASL */
1255 return ferror(sm_wfp) ? NOTOK : RP_OK;
1256 }
1257
1258 #ifdef TLS_SUPPORT
1259 /*
1260 * Negotiate Transport Layer Security
1261 */
1262
1263 static int
1264 tls_negotiate(void)
1265 {
1266 BIO *ssl_bio;
1267
1268 if (! sslctx) {
1269 const SSL_METHOD *method;
1270
1271 SSL_library_init();
1272 SSL_load_error_strings();
1273
1274 method = TLSv1_client_method(); /* Not sure about this */
1275
1276 /* Older ssl takes a non-const arg. */
1277 sslctx = SSL_CTX_new((SSL_METHOD *) method);
1278
1279 if (! sslctx) {
1280 sm_end(NOTOK);
1281 return sm_ierror("Unable to initialize OpenSSL context: %s",
1282 ERR_error_string(ERR_get_error(), NULL));
1283 }
1284 }
1285
1286 ssl = SSL_new(sslctx);
1287
1288 if (! ssl) {
1289 sm_end(NOTOK);
1290 return sm_ierror("Unable to create SSL connection: %s",
1291 ERR_error_string(ERR_get_error(), NULL));
1292 }
1293
1294 sbior = BIO_new_socket(fileno(sm_rfp), BIO_NOCLOSE);
1295 sbiow = BIO_new_socket(fileno(sm_wfp), BIO_NOCLOSE);
1296
1297 if (sbior == NULL || sbiow == NULL) {
1298 sm_end(NOTOK);
1299 return sm_ierror("Unable to create BIO endpoints: %s",
1300 ERR_error_string(ERR_get_error(), NULL));
1301 }
1302
1303 SSL_set_bio(ssl, sbior, sbiow);
1304 SSL_set_connect_state(ssl);
1305
1306 /*
1307 * Set up a BIO to handle buffering for us
1308 */
1309
1310 io = BIO_new(BIO_f_buffer());
1311
1312 if (! io) {
1313 sm_end(NOTOK);
1314 return sm_ierror("Unable to create a buffer BIO: %s",
1315 ERR_error_string(ERR_get_error(), NULL));
1316 }
1317
1318 ssl_bio = BIO_new(BIO_f_ssl());
1319
1320 if (! ssl_bio) {
1321 sm_end(NOTOK);
1322 return sm_ierror("Unable to create a SSL BIO: %s",
1323 ERR_error_string(ERR_get_error(), NULL));
1324 }
1325
1326 BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE);
1327 BIO_push(io, ssl_bio);
1328
1329 /*
1330 * Try doing the handshake now
1331 */
1332
1333 if (BIO_do_handshake(io) < 1) {
1334 sm_end(NOTOK);
1335 return sm_ierror("Unable to negotiate SSL connection: %s",
1336 ERR_error_string(ERR_get_error(), NULL));
1337 }
1338
1339 if (sm_debug) {
1340 const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
1341 printf("SSL negotiation successful: %s(%d) %s\n",
1342 SSL_CIPHER_get_name(cipher),
1343 SSL_CIPHER_get_bits(cipher, NULL),
1344 SSL_CIPHER_get_version(cipher));
1345
1346 }
1347
1348 tls_active = 1;
1349
1350 return RP_OK;
1351 }
1352 #endif /* TLS_SUPPORT */
1353
1354 /*
1355 * Convenience functions to replace occurences of fputs() and fputc()
1356 */
1357
1358 static int
1359 sm_fputs(char *buffer)
1360 {
1361 return sm_fwrite(buffer, strlen(buffer));
1362 }
1363
1364 static int
1365 sm_fputc(int c)
1366 {
1367 char h = c;
1368
1369 return sm_fwrite(&h, 1);
1370 }
1371
1372 /*
1373 * Flush out any pending data on the connection
1374 */
1375
1376 static void
1377 sm_fflush(void)
1378 {
1379 #ifdef CYRUS_SASL
1380 const char *output;
1381 unsigned int outputlen;
1382 int result;
1383
1384 if (sasl_complete == 1 && sasl_ssf > 0 && sasl_outbuflen > 0) {
1385 result = sasl_encode(conn, sasl_outbuffer, sasl_outbuflen,
1386 &output, &outputlen);
1387 if (result != SASL_OK) {
1388 sm_ierror("Unable to SASL encode connection data: %s",
1389 sasl_errdetail(conn));
1390 return;
1391 }
1392
1393 fwrite(output, sizeof(*output), outputlen, sm_wfp);
1394 sasl_outbuflen = 0;
1395 }
1396 #endif /* CYRUS_SASL */
1397
1398 #ifdef TLS_SUPPORT
1399 if (tls_active) {
1400 (void) BIO_flush(io);
1401 }
1402 #endif /* TLS_SUPPORT */
1403
1404 fflush(sm_wfp);
1405 }
1406
1407 static int
1408 sm_werror (void)
1409 {
1410 sm_reply.length =
1411 strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no socket opened"
1412 : sm_alarmed ? "write to socket timed out"
1413 : "error writing to socket"));
1414
1415 return (sm_reply.code = NOTOK);
1416 }
1417
1418
1419 static int
1420 smhear (void)
1421 {
1422 int i, code, cont, bc = 0, rc, more;
1423 unsigned char *bp;
1424 char *rp;
1425 char **ehlo = NULL, buffer[BUFSIZ];
1426
1427 if (doingEHLO) {
1428 static int at_least_once = 0;
1429
1430 if (at_least_once) {
1431 char *ep;
1432
1433 for (ehlo = EHLOkeys; *ehlo; ehlo++) {
1434 ep = *ehlo;
1435 free (ep);
1436 }
1437 } else {
1438 at_least_once = 1;
1439 }
1440
1441 ehlo = EHLOkeys;
1442 *ehlo = NULL;
1443 }
1444
1445 again: ;
1446
1447 sm_reply.length = 0;
1448 sm_reply.text[0] = 0;
1449 rp = sm_reply.text;
1450 rc = sizeof(sm_reply.text) - 1;
1451
1452 for (more = FALSE; sm_rrecord ((char *) (bp = (unsigned char *) buffer),
1453 &bc) != NOTOK ; ) {
1454 if (sm_debug) {
1455 if (sasl_ssf > 0)
1456 printf("(sasl-decrypted) ");
1457 if (tls_active)
1458 printf("(tls-decrypted) ");
1459 printf ("<= %s\n", buffer);
1460 fflush (stdout);
1461 }
1462
1463 if (doingEHLO
1464 && strncmp (buffer, "250", sizeof("250") - 1) == 0
1465 && (buffer[3] == '-' || doingEHLO == 2)
1466 && buffer[4]) {
1467 if (doingEHLO == 2) {
1468 if ((*ehlo = malloc ((size_t) (strlen (buffer + 4) + 1)))) {
1469 strcpy (*ehlo++, buffer + 4);
1470 *ehlo = NULL;
1471 if (ehlo >= EHLOkeys + MAXEHLO)
1472 doingEHLO = 0;
1473 }
1474 else
1475 doingEHLO = 0;
1476 }
1477 else
1478 doingEHLO = 2;
1479 }
1480
1481 for (; bc > 0 && (!isascii (*bp) || !isdigit (*bp)); bp++, bc--)
1482 continue;
1483
1484 cont = FALSE;
1485 code = atoi ((char *) bp);
1486 bp += 3, bc -= 3;
1487 for (; bc > 0 && isspace (*bp); bp++, bc--)
1488 continue;
1489 if (bc > 0 && *bp == '-') {
1490 cont = TRUE;
1491 bp++, bc--;
1492 for (; bc > 0 && isspace (*bp); bp++, bc--)
1493 continue;
1494 }
1495
1496 if (more) {
1497 if (code != sm_reply.code || cont)
1498 continue;
1499 more = FALSE;
1500 } else {
1501 sm_reply.code = code;
1502 more = cont;
1503 if (bc <= 0) {
1504 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1505 strncpy (buffer, sm_noreply, sizeof(buffer));
1506 bp = (unsigned char *) buffer;
1507 bc = strlen (sm_noreply);
1508 }
1509 }
1510
1511 if ((i = min (bc, rc)) > 0) {
1512 memcpy (rp, bp, i);
1513 rp += i;
1514 rc -= i;
1515 i = strlen(sm_moreply);
1516 if (more && rc > i + 1) {
1517 memcpy (rp, sm_moreply, i); /* safe because of check in if() */
1518 rp += i;
1519 rc -= i;
1520 }
1521 }
1522 if (more)
1523 continue;
1524 if (sm_reply.code < 100) {
1525 if (sm_verbose) {
1526 printf ("%s\n", sm_reply.text);
1527 fflush (stdout);
1528 }
1529 goto again;
1530 }
1531
1532 sm_reply.length = rp - sm_reply.text;
1533 sm_reply.text[sm_reply.length] = 0;
1534 return sm_reply.code;
1535 }
1536 return NOTOK;
1537 }
1538
1539
1540 static int
1541 sm_rrecord (char *buffer, int *len)
1542 {
1543 int retval;
1544
1545 if (sm_rfp == NULL)
1546 return sm_rerror(0);
1547
1548 buffer[*len = 0] = 0;
1549
1550 if ((retval = sm_fgets (buffer, BUFSIZ, sm_rfp)) != RP_OK)
1551 return sm_rerror (retval);
1552 *len = strlen (buffer);
1553 /* *len should be >0 except on EOF, but check for safety's sake */
1554 if (*len == 0)
1555 return sm_rerror (RP_EOF);
1556 if (buffer[*len - 1] != '\n')
1557 while ((retval = sm_fgetc (sm_rfp)) != '\n' && retval != EOF &&
1558 retval != -2)
1559 continue;
1560 else
1561 if ((*len > 1) && (buffer[*len - 2] == '\r'))
1562 *len -= 1;
1563 *len -= 1;
1564 buffer[*len] = 0;
1565
1566 return OK;
1567 }
1568
1569 /*
1570 * Our version of fgets, which calls our private fgetc function
1571 */
1572
1573 static int
1574 sm_fgets(char *buffer, int size, FILE *f)
1575 {
1576 int c;
1577
1578 do {
1579 c = sm_fgetc(f);
1580
1581 if (c == EOF)
1582 return RP_EOF;
1583
1584 if (c == -2)
1585 return NOTOK;
1586
1587 *buffer++ = c;
1588 } while (size > 1 && c != '\n');
1589
1590 *buffer = '\0';
1591
1592 return RP_OK;
1593 }
1594
1595
1596 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1597 /*
1598 * Read from the network, but do SASL or TLS encryption
1599 */
1600
1601 static int
1602 sm_fgetc(FILE *f)
1603 {
1604 char tmpbuf[BUFSIZ], *retbuf;
1605 unsigned int retbufsize = 0;
1606 int cc, result;
1607
1608 /*
1609 * If we have leftover data, return it
1610 */
1611
1612 if (sasl_inbuflen) {
1613 sasl_inbuflen--;
1614 return (int) *sasl_inptr++;
1615 }
1616
1617 /*
1618 * If not, read from the network until we have some data to return
1619 */
1620
1621 while (retbufsize == 0) {
1622
1623 #ifdef TLS_SUPPORT
1624 if (tls_active) {
1625 cc = SSL_read(ssl, tmpbuf, sizeof(tmpbuf));
1626
1627 if (cc == 0) {
1628 result = SSL_get_error(ssl, cc);
1629
1630 if (result != SSL_ERROR_ZERO_RETURN) {
1631 sm_ierror("TLS peer aborted connection");
1632 }
1633
1634 return EOF;
1635 }
1636
1637 if (cc < 0) {
1638 sm_ierror("SSL_read failed: %s",
1639 ERR_error_string(ERR_get_error(), NULL));
1640 return -2;
1641 }
1642 } else
1643 #endif /* TLS_SUPPORT */
1644
1645 cc = read(fileno(f), tmpbuf, sizeof(tmpbuf));
1646
1647 if (cc == 0)
1648 return EOF;
1649
1650 if (cc < 0) {
1651 sm_ierror("Unable to read from network: %s", strerror(errno));
1652 return -2;
1653 }
1654
1655 /*
1656 * Don't call sasl_decode unless sasl is complete and we have
1657 * encryption working
1658 */
1659
1660 #ifdef CYRUS_SASL
1661 if (sasl_complete == 0 || sasl_ssf == 0) {
1662 retbuf = tmpbuf;
1663 retbufsize = cc;
1664 } else {
1665 result = sasl_decode(conn, tmpbuf, cc, (const char **) &retbuf,
1666 &retbufsize);
1667
1668 if (result != SASL_OK) {
1669 sm_ierror("Unable to decode SASL network data: %s",
1670 sasl_errdetail(conn));
1671 return -2;
1672 }
1673 }
1674 #else /* ! CYRUS_SASL */
1675 retbuf = tmpbuf;
1676 retbufsize = cc;
1677 #endif /* CYRUS_SASL */
1678 }
1679
1680 if (retbufsize > SASL_MAXRECVBUF) {
1681 sm_ierror("Received data (%d bytes) is larger than the buffer "
1682 "size (%d bytes)", retbufsize, SASL_MAXRECVBUF);
1683 return -2;
1684 }
1685
1686 memcpy(sasl_inbuffer, retbuf, retbufsize);
1687 sasl_inptr = sasl_inbuffer + 1;
1688 sasl_inbuflen = retbufsize - 1;
1689
1690 return (int) sasl_inbuffer[0];
1691 }
1692 #endif /* CYRUS_SASL || TLS_SUPPORT */
1693
1694 static int
1695 sm_rerror (int rc)
1696 {
1697 if (sm_mts == MTS_SMTP)
1698 sm_reply.length =
1699 strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened"
1700 : sm_alarmed ? "read from socket timed out"
1701 : rc == RP_EOF ? "premature end-of-file on socket"
1702 : "error reading from socket"));
1703 else
1704 sm_reply.length =
1705 strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no pipe opened"
1706 : sm_alarmed ? "read from pipe timed out"
1707 : rc == RP_EOF ? "premature end-of-file on pipe"
1708 : "error reading from pipe"));
1709
1710 return (sm_reply.code = NOTOK);
1711 }
1712
1713
1714 static void
1715 alrmser (int i)
1716 {
1717 NMH_UNUSED (i);
1718
1719 #ifndef RELIABLE_SIGNALS
1720 SIGNAL (SIGALRM, alrmser);
1721 #endif
1722
1723 sm_alarmed++;
1724 if (sm_debug) {
1725 printf ("timed out...\n");
1726 fflush (stdout);
1727 }
1728 }
1729
1730
1731 char *
1732 rp_string (int code)
1733 {
1734 char *text;
1735 static char buffer[BUFSIZ];
1736
1737 switch (sm_reply.code != NOTOK ? code : NOTOK) {
1738 case RP_AOK:
1739 text = "AOK";
1740 break;
1741
1742 case RP_MOK:
1743 text = "MOK";
1744 break;
1745
1746 case RP_OK:
1747 text = "OK";
1748 break;
1749
1750 case RP_RPLY:
1751 text = "RPLY";
1752 break;
1753
1754 case RP_BHST:
1755 default:
1756 text = "BHST";
1757 snprintf (buffer, sizeof(buffer), "[%s] %s", text, sm_reply.text);
1758 return buffer;
1759
1760 case RP_PARM:
1761 text = "PARM";
1762 break;
1763
1764 case RP_NO:
1765 text = "NO";
1766 break;
1767
1768 case RP_USER:
1769 text = "USER";
1770 break;
1771
1772 case RP_NDEL:
1773 text = "NDEL";
1774 break;
1775 }
1776
1777 snprintf (buffer, sizeof(buffer), "[%s] %3d %s",
1778 text, sm_reply.code, sm_reply.text);
1779 return buffer;
1780 }
1781
1782 static char *
1783 EHLOset (char *s)
1784 {
1785 size_t len;
1786 char *ep, **ehlo;
1787
1788 len = strlen (s);
1789
1790 for (ehlo = EHLOkeys; *ehlo; ehlo++) {
1791 ep = *ehlo;
1792 if (strncmp (ep, s, len) == 0) {
1793 for (ep += len; *ep == ' '; ep++)
1794 continue;
1795 return ep;
1796 }
1797 }
1798
1799 return 0;
1800 }