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