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