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