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