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