]> diplodocus.org Git - nmh/blob - mts/smtp/smtp.c
Add support for a -nosasl switch.
[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 kill (sm_child, SIGKILL);
802 discard (sm_rfp);
803 discard (sm_wfp);
804 }
805 if (type == NOTOK) {
806 sm_reply.code = sm_note.code;
807 sm_reply.length = sm_note.length;
808 memcpy (sm_reply.text, sm_note.text, sm_note.length + 1);
809 }
810 break;
811 }
812
813 #ifdef TLS_SUPPORT
814 if (tls_active) {
815 BIO_ssl_shutdown(io);
816 BIO_free_all(io);
817 }
818 #endif /* TLS_SUPPORT */
819
820 if (sm_rfp != NULL) {
821 alarm (SM_CLOS);
822 fclose (sm_rfp);
823 alarm (0);
824 }
825 if (sm_wfp != NULL) {
826 alarm (SM_CLOS);
827 fclose (sm_wfp);
828 alarm (0);
829 }
830
831 if (sm_mts == MTS_SMTP) {
832 status = 0;
833 #ifdef CYRUS_SASL
834 if (conn) {
835 sasl_dispose(&conn);
836 if (sasl_outbuffer) {
837 free(sasl_outbuffer);
838 }
839 }
840 if (sasl_inbuffer)
841 free(sasl_inbuffer);
842 #endif /* CYRUS_SASL */
843 } else {
844 status = pidwait (sm_child, OK);
845 sm_child = NOTOK;
846 }
847
848 sm_rfp = sm_wfp = NULL;
849 return (status ? RP_BHST : RP_OK);
850 }
851
852 #ifdef CYRUS_SASL
853 /*
854 * This function implements SASL authentication for SMTP. If this function
855 * completes successfully, then authentication is successful and we've
856 * (optionally) negotiated a security layer.
857 */
858 static int
859 sm_auth_sasl(char *user, int saslssf, char *mechlist, char *inhost)
860 {
861 int result, status;
862 unsigned int buflen, outlen;
863 char *buf, outbuf[BUFSIZ], host[NI_MAXHOST];
864 const char *chosen_mech;
865 sasl_security_properties_t secprops;
866 sasl_ssf_t *ssf;
867 int *outbufmax;
868
869 /*
870 * Initialize the callback contexts
871 */
872
873 if (user == NULL)
874 user = getusername();
875
876 callbacks[SM_SASL_N_CB_USER].context = user;
877 callbacks[SM_SASL_N_CB_AUTHNAME].context = user;
878
879 /*
880 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
881 * to us on the command line, then call getpeername and do a
882 * reverse-address lookup on the IP address to get the name.
883 */
884
885 memset(host, 0, sizeof(host));
886
887 if (!inhost) {
888 struct sockaddr_storage sin;
889 socklen_t len = sizeof(sin);
890 int result;
891
892 if (getpeername(fileno(sm_wfp), (struct sockaddr *) &sin, &len) < 0) {
893 sm_ierror("getpeername on SMTP socket failed: %s",
894 strerror(errno));
895 return NOTOK;
896 }
897
898 result = getnameinfo((struct sockaddr *) &sin, len, host, sizeof(host),
899 NULL, 0, NI_NAMEREQD);
900 if (result != 0) {
901 sm_ierror("Unable to look up name of connected host: %s",
902 gai_strerror(result));
903 return NOTOK;
904 }
905 } else {
906 strncpy(host, inhost, sizeof(host) - 1);
907 }
908
909 sasl_pw_context[0] = host;
910 sasl_pw_context[1] = user;
911
912 callbacks[SM_SASL_N_CB_PASS].context = sasl_pw_context;
913
914 result = sasl_client_init(callbacks);
915
916 if (result != SASL_OK) {
917 sm_ierror("SASL library initialization failed: %s",
918 sasl_errstring(result, NULL, NULL));
919 return NOTOK;
920 }
921
922 result = sasl_client_new("smtp", host, NULL, NULL, NULL, 0, &conn);
923
924 if (result != SASL_OK) {
925 sm_ierror("SASL client initialization failed: %s",
926 sasl_errstring(result, NULL, NULL));
927 return NOTOK;
928 }
929
930 /*
931 * Initialize the security properties. But if TLS is active, then
932 * don't negotiate encryption here.
933 */
934
935 memset(&secprops, 0, sizeof(secprops));
936 secprops.maxbufsize = SASL_MAXRECVBUF;
937 secprops.max_ssf =
938 tls_active ? 0 : (saslssf != -1 ? (unsigned int) saslssf : UINT_MAX);
939
940 result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
941
942 if (result != SASL_OK) {
943 sm_ierror("SASL security property initialization failed: %s",
944 sasl_errstring(result, NULL, NULL));
945 return NOTOK;
946 }
947
948 /*
949 * Start the actual protocol. Feed the mech list into the library
950 * and get out a possible initial challenge
951 */
952
953 result = sasl_client_start(conn, mechlist, NULL, (const char **) &buf,
954 &buflen, (const char **) &chosen_mech);
955
956 if (result != SASL_OK && result != SASL_CONTINUE) {
957 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn));
958 return NOTOK;
959 }
960
961 /*
962 * If we got an initial challenge, send it as part of the AUTH
963 * command; otherwise, just send a plain AUTH command.
964 */
965
966 if (buflen) {
967 status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
968 if (status != SASL_OK) {
969 sm_ierror("SASL base64 encode failed: %s",
970 sasl_errstring(status, NULL, NULL));
971 return NOTOK;
972 }
973
974 status = smtalk(SM_AUTH, "AUTH %s %s", chosen_mech, outbuf);
975 } else
976 status = smtalk(SM_AUTH, "AUTH %s", chosen_mech);
977
978 /*
979 * Now we loop until we either fail, get a SASL_OK, or a 235
980 * response code. Receive the challenges and process them until
981 * we're all done.
982 */
983
984 while (result == SASL_CONTINUE) {
985
986 /*
987 * If we get a 235 response, that means authentication has
988 * succeeded and we need to break out of the loop (yes, even if
989 * we still get SASL_CONTINUE from sasl_client_step()).
990 *
991 * Otherwise, if we get a message that doesn't seem to be a
992 * valid response, then abort
993 */
994
995 if (status == 235)
996 break;
997 else if (status < 300 || status > 399)
998 return RP_BHST;
999
1000 /*
1001 * Special case; a zero-length response from the SMTP server
1002 * is returned as a single =. If we get that, then set buflen
1003 * to be zero. Otherwise, just decode the response.
1004 */
1005
1006 if (strcmp("=", sm_reply.text) == 0) {
1007 outlen = 0;
1008 } else {
1009 result = sasl_decode64(sm_reply.text, sm_reply.length,
1010 outbuf, sizeof(outbuf), &outlen);
1011
1012 if (result != SASL_OK) {
1013 smtalk(SM_AUTH, "*");
1014 sm_ierror("SASL base64 decode failed: %s",
1015 sasl_errstring(result, NULL, NULL));
1016 return NOTOK;
1017 }
1018 }
1019
1020 result = sasl_client_step(conn, outbuf, outlen, NULL,
1021 (const char **) &buf, &buflen);
1022
1023 if (result != SASL_OK && result != SASL_CONTINUE) {
1024 smtalk(SM_AUTH, "*");
1025 sm_ierror("SASL client negotiation failed: %s",
1026 sasl_errstring(result, NULL, NULL));
1027 return NOTOK;
1028 }
1029
1030 status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
1031
1032 if (status != SASL_OK) {
1033 smtalk(SM_AUTH, "*");
1034 sm_ierror("SASL base64 encode failed: %s",
1035 sasl_errstring(status, NULL, NULL));
1036 return NOTOK;
1037 }
1038
1039 status = smtalk(SM_AUTH, outbuf);
1040 }
1041
1042 /*
1043 * Make sure that we got the correct response
1044 */
1045
1046 if (status < 200 || status > 299)
1047 return RP_BHST;
1048
1049 /*
1050 * We _should_ have completed the authentication successfully.
1051 * Get a few properties from the authentication exchange.
1052 */
1053
1054 result = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **) &outbufmax);
1055
1056 if (result != SASL_OK) {
1057 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1058 sasl_errstring(result, NULL, NULL));
1059 return NOTOK;
1060 }
1061
1062 maxoutbuf = *outbufmax;
1063
1064 result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf);
1065
1066 sasl_ssf = *ssf;
1067
1068 if (result != SASL_OK) {
1069 sm_ierror("Cannot retrieve SASL negotiated security strength "
1070 "factor: %s", sasl_errstring(result, NULL, NULL));
1071 return NOTOK;
1072 }
1073
1074 if (sasl_ssf > 0) {
1075 sasl_outbuffer = malloc(maxoutbuf);
1076
1077 if (sasl_outbuffer == NULL) {
1078 sm_ierror("Unable to allocate %d bytes for SASL output "
1079 "buffer", maxoutbuf);
1080 return NOTOK;
1081 }
1082 sasl_outbuflen = 0;
1083 sasl_inbuflen = 0;
1084 sasl_inptr = sasl_inbuffer;
1085 } else {
1086 sasl_outbuffer = NULL;
1087 /* Don't NULL out sasl_inbuffer because it could be used in
1088 sm_fgetc (). */
1089 }
1090
1091 sasl_complete = 1;
1092
1093 return RP_OK;
1094 }
1095
1096 /*
1097 * Our callback functions to feed data to the SASL library
1098 */
1099
1100 static int
1101 sm_get_user(void *context, int id, const char **result, unsigned *len)
1102 {
1103 char *user = (char *) context;
1104
1105 if (! result || ((id != SASL_CB_USER) && (id != SASL_CB_AUTHNAME)))
1106 return SASL_BADPARAM;
1107
1108 *result = user;
1109 if (len)
1110 *len = strlen(user);
1111
1112 return SASL_OK;
1113 }
1114
1115 static int
1116 sm_get_pass(sasl_conn_t *conn, void *context, int id,
1117 sasl_secret_t **psecret)
1118 {
1119 char **pw_context = (char **) context;
1120 char *pass = NULL;
1121 int len;
1122
1123 NMH_UNUSED (conn);
1124
1125 if (! psecret || id != SASL_CB_PASS)
1126 return SASL_BADPARAM;
1127
1128 ruserpass(pw_context[0], &(pw_context[1]), &pass);
1129
1130 len = strlen(pass);
1131
1132 *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len);
1133
1134 if (! *psecret) {
1135 free(pass);
1136 return SASL_NOMEM;
1137 }
1138
1139 (*psecret)->len = len;
1140 strcpy((char *) (*psecret)->data, pass);
1141 /* free(pass); */
1142
1143 return SASL_OK;
1144 }
1145 #endif /* CYRUS_SASL */
1146
1147 static int
1148 sm_ierror (char *fmt, ...)
1149 {
1150 va_list ap;
1151
1152 va_start(ap, fmt);
1153 vsnprintf (sm_reply.text, sizeof(sm_reply.text), fmt, ap);
1154 va_end(ap);
1155
1156 sm_reply.length = strlen (sm_reply.text);
1157 sm_reply.code = NOTOK;
1158
1159 return RP_BHST;
1160 }
1161
1162 static int
1163 smtalk (int time, char *fmt, ...)
1164 {
1165 va_list ap;
1166 int result;
1167 char buffer[BUFSIZ];
1168
1169 va_start(ap, fmt);
1170 vsnprintf (buffer, sizeof(buffer), fmt, ap);
1171 va_end(ap);
1172
1173 if (sm_debug) {
1174 if (sasl_ssf)
1175 printf("(sasl-encrypted) ");
1176 if (tls_active)
1177 printf("(tls-encrypted) ");
1178 printf ("=> %s\n", buffer);
1179 fflush (stdout);
1180 }
1181
1182 sm_alarmed = 0;
1183 alarm ((unsigned) time);
1184 if ((result = sm_wrecord (buffer, strlen (buffer))) != NOTOK)
1185 result = smhear ();
1186 alarm (0);
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; 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 fwrite(buffer, sizeof(*buffer), len, sm_wfp);
1276 #ifdef CYRUS_SASL
1277 } else {
1278 while (len >= maxoutbuf - sasl_outbuflen) {
1279 memcpy(sasl_outbuffer + sasl_outbuflen, buffer,
1280 maxoutbuf - sasl_outbuflen);
1281 len -= maxoutbuf - sasl_outbuflen;
1282 sasl_outbuflen = 0;
1283
1284 if (sasl_encode(conn, sasl_outbuffer, maxoutbuf,
1285 &output, &outputlen) != SASL_OK) {
1286 sm_ierror("Unable to SASL encode connection data: %s",
1287 sasl_errdetail(conn));
1288 return NOTOK;
1289 }
1290
1291 fwrite(output, sizeof(*output), outputlen, sm_wfp);
1292 }
1293
1294 if (len > 0) {
1295 memcpy(sasl_outbuffer + sasl_outbuflen, buffer, len);
1296 sasl_outbuflen += len;
1297 }
1298 }
1299 #endif /* CYRUS_SASL */
1300 return ferror(sm_wfp) ? NOTOK : RP_OK;
1301 }
1302
1303 /*
1304 * Convenience functions to replace occurences of fputs() and fputc()
1305 */
1306
1307 static int
1308 sm_fputs(char *buffer)
1309 {
1310 return sm_fwrite(buffer, strlen(buffer));
1311 }
1312
1313 static int
1314 sm_fputc(int c)
1315 {
1316 char h = c;
1317
1318 return sm_fwrite(&h, 1);
1319 }
1320
1321 /*
1322 * Flush out any pending data on the connection
1323 */
1324
1325 static void
1326 sm_fflush(void)
1327 {
1328 #ifdef CYRUS_SASL
1329 const char *output;
1330 unsigned int outputlen;
1331 int result;
1332
1333 if (sasl_complete == 1 && sasl_ssf > 0 && sasl_outbuflen > 0) {
1334 result = sasl_encode(conn, sasl_outbuffer, sasl_outbuflen,
1335 &output, &outputlen);
1336 if (result != SASL_OK) {
1337 sm_ierror("Unable to SASL encode connection data: %s",
1338 sasl_errdetail(conn));
1339 return;
1340 }
1341
1342 fwrite(output, sizeof(*output), outputlen, sm_wfp);
1343 sasl_outbuflen = 0;
1344 }
1345 #endif /* CYRUS_SASL */
1346
1347 #ifdef TLS_SUPPORT
1348 if (tls_active) {
1349 (void) BIO_flush(io);
1350 }
1351 #endif /* TLS_SUPPORT */
1352
1353 fflush(sm_wfp);
1354 }
1355
1356 static int
1357 sm_werror (void)
1358 {
1359 sm_reply.length =
1360 strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no socket opened"
1361 : sm_alarmed ? "write to socket timed out"
1362 : "error writing to socket"));
1363
1364 return (sm_reply.code = NOTOK);
1365 }
1366
1367
1368 static int
1369 smhear (void)
1370 {
1371 int i, code, cont, bc = 0, rc, more;
1372 unsigned char *bp;
1373 char *rp;
1374 char **ehlo = NULL, buffer[BUFSIZ];
1375
1376 if (doingEHLO) {
1377 static int at_least_once = 0;
1378
1379 if (at_least_once) {
1380 char *ep;
1381
1382 for (ehlo = EHLOkeys; *ehlo; ehlo++) {
1383 ep = *ehlo;
1384 free (ep);
1385 }
1386 } else {
1387 at_least_once = 1;
1388 }
1389
1390 ehlo = EHLOkeys;
1391 *ehlo = NULL;
1392 }
1393
1394 again: ;
1395
1396 sm_reply.length = 0;
1397 sm_reply.text[0] = 0;
1398 rp = sm_reply.text;
1399 rc = sizeof(sm_reply.text) - 1;
1400
1401 for (more = FALSE; sm_rrecord ((char *) (bp = (unsigned char *) buffer),
1402 &bc) != NOTOK ; ) {
1403 if (sm_debug) {
1404 if (sasl_ssf > 0)
1405 printf("(sasl-decrypted) ");
1406 if (tls_active)
1407 printf("(tls-decrypted) ");
1408 printf ("<= %s\n", buffer);
1409 fflush (stdout);
1410 }
1411
1412 if (doingEHLO
1413 && strncmp (buffer, "250", sizeof("250") - 1) == 0
1414 && (buffer[3] == '-' || doingEHLO == 2)
1415 && buffer[4]) {
1416 if (doingEHLO == 2) {
1417 if ((*ehlo = malloc ((size_t) (strlen (buffer + 4) + 1)))) {
1418 strcpy (*ehlo++, buffer + 4);
1419 *ehlo = NULL;
1420 if (ehlo >= EHLOkeys + MAXEHLO)
1421 doingEHLO = 0;
1422 }
1423 else
1424 doingEHLO = 0;
1425 }
1426 else
1427 doingEHLO = 2;
1428 }
1429
1430 for (; bc > 0 && (!isascii (*bp) || !isdigit (*bp)); bp++, bc--)
1431 continue;
1432
1433 cont = FALSE;
1434 code = atoi ((char *) bp);
1435 bp += 3, bc -= 3;
1436 for (; bc > 0 && isspace (*bp); bp++, bc--)
1437 continue;
1438 if (bc > 0 && *bp == '-') {
1439 cont = TRUE;
1440 bp++, bc--;
1441 for (; bc > 0 && isspace (*bp); bp++, bc--)
1442 continue;
1443 }
1444
1445 if (more) {
1446 if (code != sm_reply.code || cont)
1447 continue;
1448 more = FALSE;
1449 } else {
1450 sm_reply.code = code;
1451 more = cont;
1452 if (bc <= 0) {
1453 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1454 strncpy (buffer, sm_noreply, sizeof(buffer));
1455 bp = (unsigned char *) buffer;
1456 bc = strlen (sm_noreply);
1457 }
1458 }
1459
1460 if ((i = min (bc, rc)) > 0) {
1461 memcpy (rp, bp, i);
1462 rp += i;
1463 rc -= i;
1464 i = strlen(sm_moreply);
1465 if (more && rc > i + 1) {
1466 memcpy (rp, sm_moreply, i); /* safe because of check in if() */
1467 rp += i;
1468 rc -= i;
1469 }
1470 }
1471 if (more)
1472 continue;
1473 if (sm_reply.code < 100) {
1474 if (sm_verbose) {
1475 printf ("%s\n", sm_reply.text);
1476 fflush (stdout);
1477 }
1478 goto again;
1479 }
1480
1481 sm_reply.length = rp - sm_reply.text;
1482 sm_reply.text[sm_reply.length] = 0;
1483 return sm_reply.code;
1484 }
1485 return NOTOK;
1486 }
1487
1488
1489 static int
1490 sm_rrecord (char *buffer, int *len)
1491 {
1492 int retval;
1493
1494 if (sm_rfp == NULL)
1495 return sm_rerror(0);
1496
1497 buffer[*len = 0] = 0;
1498
1499 if ((retval = sm_fgets (buffer, BUFSIZ, sm_rfp)) != RP_OK)
1500 return sm_rerror (retval);
1501 *len = strlen (buffer);
1502 /* *len should be >0 except on EOF, but check for safety's sake */
1503 if (*len == 0)
1504 return sm_rerror (RP_EOF);
1505 if (buffer[*len - 1] != '\n')
1506 while ((retval = sm_fgetc (sm_rfp)) != '\n' && retval != EOF &&
1507 retval != -2)
1508 continue;
1509 else
1510 if ((*len > 1) && (buffer[*len - 2] == '\r'))
1511 *len -= 1;
1512 *len -= 1;
1513 buffer[*len] = 0;
1514
1515 return OK;
1516 }
1517
1518 /*
1519 * Our version of fgets, which calls our private fgetc function
1520 */
1521
1522 static int
1523 sm_fgets(char *buffer, int size, FILE *f)
1524 {
1525 int c;
1526
1527 do {
1528 c = sm_fgetc(f);
1529
1530 if (c == EOF)
1531 return RP_EOF;
1532
1533 if (c == -2)
1534 return NOTOK;
1535
1536 *buffer++ = c;
1537 } while (size > 1 && c != '\n');
1538
1539 *buffer = '\0';
1540
1541 return RP_OK;
1542 }
1543
1544
1545 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1546 /*
1547 * Read from the network, but do SASL or TLS encryption
1548 */
1549
1550 static int
1551 sm_fgetc(FILE *f)
1552 {
1553 char tmpbuf[BUFSIZ], *retbuf;
1554 unsigned int retbufsize = 0;
1555 int cc, result;
1556
1557 /*
1558 * If we have leftover data, return it
1559 */
1560
1561 if (sasl_inbuflen) {
1562 sasl_inbuflen--;
1563 return (int) *sasl_inptr++;
1564 }
1565
1566 /*
1567 * If not, read from the network until we have some data to return
1568 */
1569
1570 while (retbufsize == 0) {
1571
1572 #ifdef TLS_SUPPORT
1573 if (tls_active) {
1574 cc = SSL_read(ssl, tmpbuf, sizeof(tmpbuf));
1575
1576 if (cc == 0) {
1577 result = SSL_get_error(ssl, cc);
1578
1579 if (result != SSL_ERROR_ZERO_RETURN) {
1580 sm_ierror("TLS peer aborted connection");
1581 }
1582
1583 return EOF;
1584 }
1585
1586 if (cc < 0) {
1587 sm_ierror("SSL_read failed: %s",
1588 ERR_error_string(ERR_get_error(), NULL));
1589 return -2;
1590 }
1591 } else
1592 #endif /* TLS_SUPPORT */
1593
1594 cc = read(fileno(f), tmpbuf, sizeof(tmpbuf));
1595
1596 if (cc == 0)
1597 return EOF;
1598
1599 if (cc < 0) {
1600 sm_ierror("Unable to read from network: %s", strerror(errno));
1601 return -2;
1602 }
1603
1604 /*
1605 * Don't call sasl_decode unless sasl is complete and we have
1606 * encryption working
1607 */
1608
1609 #ifdef CYRUS_SASL
1610 if (sasl_complete == 0 || sasl_ssf == 0) {
1611 retbuf = tmpbuf;
1612 retbufsize = cc;
1613 } else {
1614 result = sasl_decode(conn, tmpbuf, cc, (const char **) &retbuf,
1615 &retbufsize);
1616
1617 if (result != SASL_OK) {
1618 sm_ierror("Unable to decode SASL network data: %s",
1619 sasl_errdetail(conn));
1620 return -2;
1621 }
1622 }
1623 #else /* ! CYRUS_SASL */
1624 retbuf = tmpbuf;
1625 retbufsize = cc;
1626 #endif /* CYRUS_SASL */
1627 }
1628
1629 if (retbufsize > SASL_MAXRECVBUF) {
1630 sm_ierror("Received data (%d bytes) is larger than the buffer "
1631 "size (%d bytes)", retbufsize, SASL_MAXRECVBUF);
1632 return -2;
1633 }
1634
1635 memcpy(sasl_inbuffer, retbuf, retbufsize);
1636 sasl_inptr = sasl_inbuffer + 1;
1637 sasl_inbuflen = retbufsize - 1;
1638
1639 return (int) sasl_inbuffer[0];
1640 }
1641 #endif /* CYRUS_SASL || TLS_SUPPORT */
1642
1643 static int
1644 sm_rerror (int rc)
1645 {
1646 if (sm_mts == MTS_SMTP)
1647 sm_reply.length =
1648 strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened"
1649 : sm_alarmed ? "read from socket timed out"
1650 : rc == RP_EOF ? "premature end-of-file on socket"
1651 : "error reading from socket"));
1652 else
1653 sm_reply.length =
1654 strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no pipe opened"
1655 : sm_alarmed ? "read from pipe timed out"
1656 : rc == RP_EOF ? "premature end-of-file on pipe"
1657 : "error reading from pipe"));
1658
1659 return (sm_reply.code = NOTOK);
1660 }
1661
1662
1663 static void
1664 alrmser (int i)
1665 {
1666 NMH_UNUSED (i);
1667
1668 #ifndef RELIABLE_SIGNALS
1669 SIGNAL (SIGALRM, alrmser);
1670 #endif
1671
1672 sm_alarmed++;
1673 if (sm_debug) {
1674 printf ("timed out...\n");
1675 fflush (stdout);
1676 }
1677 }
1678
1679
1680 char *
1681 rp_string (int code)
1682 {
1683 char *text;
1684 static char buffer[BUFSIZ];
1685
1686 switch (sm_reply.code != NOTOK ? code : NOTOK) {
1687 case RP_AOK:
1688 text = "AOK";
1689 break;
1690
1691 case RP_MOK:
1692 text = "MOK";
1693 break;
1694
1695 case RP_OK:
1696 text = "OK";
1697 break;
1698
1699 case RP_RPLY:
1700 text = "RPLY";
1701 break;
1702
1703 case RP_BHST:
1704 default:
1705 text = "BHST";
1706 snprintf (buffer, sizeof(buffer), "[%s] %s", text, sm_reply.text);
1707 return buffer;
1708
1709 case RP_PARM:
1710 text = "PARM";
1711 break;
1712
1713 case RP_NO:
1714 text = "NO";
1715 break;
1716
1717 case RP_USER:
1718 text = "USER";
1719 break;
1720
1721 case RP_NDEL:
1722 text = "NDEL";
1723 break;
1724 }
1725
1726 snprintf (buffer, sizeof(buffer), "[%s] %3d %s",
1727 text, sm_reply.code, sm_reply.text);
1728 return buffer;
1729 }
1730
1731 static char *
1732 EHLOset (char *s)
1733 {
1734 size_t len;
1735 char *ep, **ehlo;
1736
1737 len = strlen (s);
1738
1739 for (ehlo = EHLOkeys; *ehlo; ehlo++) {
1740 ep = *ehlo;
1741 if (strncmp (ep, s, len) == 0) {
1742 for (ep += len; *ep == ' '; ep++)
1743 continue;
1744 return ep;
1745 }
1746 }
1747
1748 return 0;
1749 }