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