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