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