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