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