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