2 * smtp.c -- nmh SMTP interface
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.
12 #include <h/signals.h>
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>
29 #endif /* CYRUS_SASL */
32 #include <openssl/ssl.h>
33 #include <openssl/err.h>
34 #endif /* TLS_SUPPORT */
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
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.
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!
64 #define NBITS ((sizeof (int)) * 8)
67 * these codes must all be different!
69 #define SM_OPEN 300 /* Changed to 5 minutes to comply with a SHOULD in RFC 1123 */
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 */
81 #endif /* CYRUS_SASL */
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;
90 static FILE *sm_rfp
= NULL
;
91 static FILE *sm_wfp
= NULL
;
95 * Some globals needed by SASL
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 int maxoutbuf
; /* Maximum crypto output buffer */
102 static char *sasl_outbuffer
; /* SASL output buffer for encryption */
103 static int sasl_outbuflen
; /* Current length of data in outbuf */
104 static int sm_get_user(void *, int, const char **, unsigned *);
105 static int sm_get_pass(sasl_conn_t
*, void *, int, sasl_secret_t
**);
107 static sasl_callback_t callbacks
[] = {
108 { SASL_CB_USER
, (sasl_callback_ft
) sm_get_user
, NULL
},
109 #define SM_SASL_N_CB_USER 0
110 { SASL_CB_AUTHNAME
, (sasl_callback_ft
) sm_get_user
, NULL
},
111 #define SM_SASL_N_CB_AUTHNAME 1
112 { SASL_CB_PASS
, (sasl_callback_ft
) sm_get_pass
, NULL
},
113 #define SM_SASL_N_CB_PASS 2
114 { SASL_CB_LIST_END
, NULL
, NULL
},
117 #else /* CYRUS_SASL */
119 #endif /* CYRUS_SASL */
122 static SSL_CTX
*sslctx
= NULL
;
123 static SSL
*ssl
= NULL
;
124 static BIO
*sbior
= NULL
;
125 static BIO
*sbiow
= NULL
;
126 static BIO
*io
= NULL
;
128 static int tls_negotiate(void);
129 #endif /* TLS_SUPPORT */
131 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
132 #define SASL_MAXRECVBUF 65536
133 static int sm_fgetc(FILE *);
134 static char *sasl_inbuffer
; /* SASL input buffer for encryption */
135 static char *sasl_inptr
; /* Pointer to current inbuf position */
136 static int sasl_inbuflen
; /* Current length of data in inbuf */
138 #define sm_fgetc fgetc
141 static int tls_active
= 0;
143 static char *sm_noreply
= "No reply text given";
144 static char *sm_moreply
= "; ";
145 static struct smtp sm_reply
;
149 static int doingEHLO
;
150 static char *EHLOkeys
[MAXEHLO
+ 1];
155 static int smtp_init (char *, char *, char *, int, int, int, int, int,
156 char *, char *, int);
157 static int sendmail_init (char *, char *, int, int, int, int, int,
160 static int rclient (char *, char *);
161 static int sm_ierror (char *fmt
, ...);
162 static int smtalk (int time
, char *fmt
, ...);
163 static int sm_wrecord (char *, int);
164 static int sm_wstream (char *, int);
165 static int sm_werror (void);
166 static int smhear (void);
167 static int sm_rrecord (char *, int *);
168 static int sm_rerror (int);
169 static void alrmser (int);
170 static char *EHLOset (char *);
171 static int sm_fwrite(char *, int);
172 static int sm_fputs(char *);
173 static int sm_fputc(int);
174 static void sm_fflush(void);
175 static int sm_fgets(char *, int, FILE *);
179 * Function prototypes needed for SASL
182 static int sm_auth_sasl(char *, int, char *, char *);
183 #endif /* CYRUS_SASL */
186 sm_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
187 int debug
, int sasl
, int saslssf
, char *saslmech
, char *user
, int tls
)
189 if (sm_mts
== MTS_SMTP
)
190 return smtp_init (client
, server
, port
, watch
, verbose
,
191 debug
, sasl
, saslssf
, saslmech
, user
, tls
);
193 return sendmail_init (client
, server
, watch
, verbose
,
194 debug
, sasl
, saslssf
, saslmech
, user
);
198 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
200 int sasl
, int saslssf
, char *saslmech
, char *user
, int tls
)
202 int result
, sd1
, sd2
;
205 #else /* CYRUS_SASL */
207 NMH_UNUSED (saslssf
);
208 NMH_UNUSED (saslmech
);
210 #endif /* CYRUS_SASL */
215 sm_verbose
= verbose
;
218 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
221 if (client
== NULL
|| *client
== '\0') {
225 client
= LocalName(1); /* no clientname -> LocalName */
230 * Last-ditch check just in case client still isn't set to anything
233 if (client
== NULL
|| *client
== '\0')
234 client
= "localhost";
236 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
237 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
239 return sm_ierror("Unable to allocate %d bytes for read buffer",
241 #endif /* CYRUS_SASL || TLS_SUPPORT */
243 if ((sd1
= rclient (server
, port
)) == NOTOK
)
246 if ((sd2
= dup (sd1
)) == NOTOK
) {
248 return sm_ierror ("unable to dup");
251 SIGNAL (SIGALRM
, alrmser
);
252 SIGNAL (SIGPIPE
, SIG_IGN
);
254 if ((sm_rfp
= fdopen (sd1
, "r")) == NULL
255 || (sm_wfp
= fdopen (sd2
, "w")) == NULL
) {
258 sm_rfp
= sm_wfp
= NULL
;
259 return sm_ierror ("unable to fdopen");
266 * If tls == 2, that means that the user requested "initial" TLS,
267 * which happens right after the connection has opened. Do that
272 result
= tls_negotiate();
275 * Note: if tls_negotiate() fails it will call sm_end() for us,
276 * which closes the connection.
281 #endif /* TLS_SUPPORT */
298 * Give EHLO or HELO command
302 result
= smtalk (SM_HELO
, "EHLO %s", client
);
305 if (result
>= 500 && result
<= 599)
306 result
= smtalk (SM_HELO
, "HELO %s", client
);
315 * If the user requested TLS support, then try to do the STARTTLS command
316 * as part of the initial dialog. Assuming this works, we then need to
317 * restart the EHLO dialog after TLS negotiation is complete.
321 if (! EHLOset("STARTTLS")) {
323 return sm_ierror("SMTP server does not support TLS");
326 result
= smtalk(SM_HELO
, "STARTTLS");
334 * Okay, the other side should be waiting for us to start TLS
335 * negotiation. Oblige them.
338 result
= tls_negotiate();
344 result
= smtalk (SM_HELO
, "EHLO %s", client
);
352 #else /* TLS_SUPPORT */
354 #endif /* TLS_SUPPORT */
358 * If the user asked for SASL, then check to see if the SMTP server
359 * supports it. Otherwise, error out (because the SMTP server
360 * might have been spoofed; we don't want to just silently not
365 if (! (server_mechs
= EHLOset("AUTH"))) {
367 return sm_ierror("SMTP server does not support SASL");
370 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
372 return sm_ierror("Requested SASL mech \"%s\" is not in the "
373 "list of supported mechanisms:\n%s",
374 saslmech
, server_mechs
);
377 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
383 #endif /* CYRUS_SASL */
386 if (watch
&& EHLOset ("XVRB"))
387 smtalk (SM_HELO
, "VERB on");
393 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
394 int debug
, int sasl
, int saslssf
, char *saslmech
, char *user
)
396 unsigned int i
, result
, vecp
;
401 #else /* CYRUS_SASL */
404 NMH_UNUSED (saslssf
);
405 NMH_UNUSED (saslmech
);
407 #endif /* CYRUS_SASL */
412 sm_verbose
= verbose
;
414 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
417 if (client
== NULL
|| *client
== '\0') {
421 client
= LocalName(1); /* no clientname -> LocalName */
425 * Last-ditch check just in case client still isn't set to anything
428 if (client
== NULL
|| *client
== '\0')
429 client
= "localhost";
431 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
432 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
434 return sm_ierror("Unable to allocate %d bytes for read buffer",
436 #endif /* CYRUS_SASL || TLS_SUPPORT */
438 if (pipe (pdi
) == NOTOK
)
439 return sm_ierror ("no pipes");
440 if (pipe (pdo
) == NOTOK
) {
443 return sm_ierror ("no pipes");
446 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
455 return sm_ierror ("unable to fork");
458 if (pdo
[0] != fileno (stdin
))
459 dup2 (pdo
[0], fileno (stdin
));
460 if (pdi
[1] != fileno (stdout
))
461 dup2 (pdi
[1], fileno (stdout
));
462 if (pdi
[1] != fileno (stderr
))
463 dup2 (pdi
[1], fileno (stderr
));
464 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
468 vec
[vecp
++] = r1bindex (sendmail
, '/');
470 vec
[vecp
++] = watch
? "-odi" : "-odb";
471 vec
[vecp
++] = "-oem";
477 execvp (sendmail
, vec
);
478 fprintf (stderr
, "unable to exec ");
480 _exit (-1); /* NOTREACHED */
483 SIGNAL (SIGALRM
, alrmser
);
484 SIGNAL (SIGPIPE
, SIG_IGN
);
488 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
489 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
492 sm_rfp
= sm_wfp
= NULL
;
493 return sm_ierror ("unable to fdopen");
509 result
= smtalk (SM_HELO
, "EHLO %s", client
);
512 if (500 <= result
&& result
<= 599)
513 result
= smtalk (SM_HELO
, "HELO %s", client
);
526 * If the user asked for SASL, then check to see if the SMTP server
527 * supports it. Otherwise, error out (because the SMTP server
528 * might have been spoofed; we don't want to just silently not
533 if (! (server_mechs
= EHLOset("AUTH"))) {
535 return sm_ierror("SMTP server does not support SASL");
538 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
540 return sm_ierror("Requested SASL mech \"%s\" is not in the "
541 "list of supported mechanisms:\n%s",
542 saslmech
, server_mechs
);
545 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
551 #endif /* CYRUS_SASL */
554 smtalk (SM_HELO
, "VERB on");
561 rclient (char *server
, char *service
)
564 char response
[BUFSIZ
];
566 if ((sd
= client (server
, service
, response
, sizeof(response
),
570 sm_ierror ("%s", response
);
575 sm_winit (char *from
)
577 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
594 sm_wadr (char *mbox
, char *host
, char *path
)
596 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
598 path
? path
: "", mbox
, host
)) {
608 #endif /* SENDMAILBUG */
633 switch (smtalk (SM_DATA
, "DATA")) {
642 #endif /* SENDMAILBUG */
659 sm_wtxt (char *buffer
, int len
)
665 result
= sm_wstream (buffer
, len
);
668 return (result
== NOTOK
? RP_BHST
: RP_OK
);
675 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
678 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
686 #endif /* SENDMAILBUG */
704 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
715 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
720 smtalk (SM_QUIT
, "QUIT");
724 sm_note
.code
= sm_reply
.code
;
725 sm_note
.length
= sm_reply
.length
;
726 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
728 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
730 if (sm_mts
== MTS_SMTP
)
731 smtalk (SM_QUIT
, "QUIT");
733 /* The SIGPIPE block replaces old calls to discard ().
734 We're not sure what the discard () calls were for,
735 maybe to prevent deadlock on old systems. In any
736 case, blocking SIGPIPE should be harmless.
737 Because the file handles are closed below, leave it
741 sigaddset (&set
, SIGPIPE
);
742 sigprocmask (SIG_BLOCK
, &set
, &oset
);
744 kill (sm_child
, SIGKILL
);
748 sm_reply
.code
= sm_note
.code
;
749 sm_reply
.length
= sm_note
.length
;
750 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
757 BIO_ssl_shutdown(io
);
760 #endif /* TLS_SUPPORT */
762 if (sm_rfp
!= NULL
) {
767 if (sm_wfp
!= NULL
) {
773 if (sm_mts
== MTS_SMTP
) {
778 if (sasl_outbuffer
) {
779 free(sasl_outbuffer
);
784 #endif /* CYRUS_SASL */
785 } else if (sm_child
!= NOTOK
) {
786 status
= pidwait (sm_child
, OK
);
792 sm_rfp
= sm_wfp
= NULL
;
793 return (status
? RP_BHST
: RP_OK
);
798 * This function implements SASL authentication for SMTP. If this function
799 * completes successfully, then authentication is successful and we've
800 * (optionally) negotiated a security layer.
803 #define CHECKB64SIZE(insize, outbuf, outsize) \
804 { size_t wantout = (((insize + 2) / 3) * 4) + 32; \
805 if (wantout > outsize) { \
806 outbuf = mh_xrealloc(outbuf, outsize = wantout); \
811 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
814 unsigned int buflen
, outlen
;
815 char *buf
, *outbuf
= NULL
, host
[NI_MAXHOST
];
816 const char *chosen_mech
;
817 sasl_security_properties_t secprops
;
820 struct nmh_creds creds
= { 0, 0, 0 };
821 size_t outbufsize
= 0;
824 * Initialize the callback contexts
828 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
829 * to us on the command line, then call getpeername and do a
830 * reverse-address lookup on the IP address to get the name.
833 memset(host
, 0, sizeof(host
));
836 struct sockaddr_storage sin
;
837 socklen_t len
= sizeof(sin
);
840 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
841 sm_ierror("getpeername on SMTP socket failed: %s",
846 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
847 NULL
, 0, NI_NAMEREQD
);
849 sm_ierror("Unable to look up name of connected host: %s",
850 gai_strerror(result
));
854 strncpy(host
, inhost
, sizeof(host
) - 1);
857 /* It's OK to copy the addresses here. The callbacks that use
858 them will only be called before this function returns. */
861 callbacks
[SM_SASL_N_CB_USER
].context
= &creds
;
862 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= &creds
;
863 callbacks
[SM_SASL_N_CB_PASS
].context
= &creds
;
865 result
= sasl_client_init(callbacks
);
867 if (result
!= SASL_OK
) {
868 sm_ierror("SASL library initialization failed: %s",
869 sasl_errstring(result
, NULL
, NULL
));
873 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
875 if (result
!= SASL_OK
) {
876 sm_ierror("SASL client initialization failed: %s",
877 sasl_errstring(result
, NULL
, NULL
));
882 * Initialize the security properties. But if TLS is active, then
883 * don't negotiate encryption here.
886 memset(&secprops
, 0, sizeof(secprops
));
887 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
889 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
891 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
893 if (result
!= SASL_OK
) {
894 sm_ierror("SASL security property initialization failed: %s",
895 sasl_errstring(result
, NULL
, NULL
));
900 * Start the actual protocol. Feed the mech list into the library
901 * and get out a possible initial challenge
904 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
905 &buflen
, (const char **) &chosen_mech
);
907 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
908 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
913 * If we got an initial challenge, send it as part of the AUTH
914 * command; otherwise, just send a plain AUTH command.
918 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
919 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
920 if (status
!= SASL_OK
) {
921 sm_ierror("SASL base64 encode failed: %s",
922 sasl_errstring(status
, NULL
, NULL
));
928 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
930 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
933 * Now we loop until we either fail, get a SASL_OK, or a 235
934 * response code. Receive the challenges and process them until
938 while (result
== SASL_CONTINUE
) {
941 * If we get a 235 response, that means authentication has
942 * succeeded and we need to break out of the loop (yes, even if
943 * we still get SASL_CONTINUE from sasl_client_step()).
945 * Otherwise, if we get a message that doesn't seem to be a
946 * valid response, then abort
951 else if (status
< 300 || status
> 399) {
958 * Special case; a zero-length response from the SMTP server
959 * is returned as a single =. If we get that, then set buflen
960 * to be zero. Otherwise, just decode the response.
963 if (strcmp("=", sm_reply
.text
) == 0) {
966 if (sm_reply
.length
> (int) outbufsize
) {
967 outbuf
= mh_xrealloc(outbuf
, outbufsize
= sm_reply
.length
);
970 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
971 outbuf
, outbufsize
, &outlen
);
972 if (result
!= SASL_OK
) {
973 smtalk(SM_AUTH
, "*");
974 sm_ierror("SASL base64 decode failed: %s",
975 sasl_errstring(result
, NULL
, NULL
));
982 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
983 (const char **) &buf
, &buflen
);
985 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
986 smtalk(SM_AUTH
, "*");
987 sm_ierror("SASL client negotiation failed: %s",
988 sasl_errstring(result
, NULL
, NULL
));
994 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
995 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
997 if (status
!= SASL_OK
) {
998 smtalk(SM_AUTH
, "*");
999 sm_ierror("SASL base64 encode failed: %s",
1000 sasl_errstring(status
, NULL
, NULL
));
1006 status
= smtalk(SM_AUTH
, outbuf
);
1013 * Make sure that we got the correct response
1016 if (status
< 200 || status
> 299)
1020 * We _should_ have completed the authentication successfully.
1021 * Get a few properties from the authentication exchange.
1024 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
1026 if (result
!= SASL_OK
) {
1027 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1028 sasl_errstring(result
, NULL
, NULL
));
1032 maxoutbuf
= *outbufmax
;
1034 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
1038 if (result
!= SASL_OK
) {
1039 sm_ierror("Cannot retrieve SASL negotiated security strength "
1040 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
1045 sasl_outbuffer
= malloc(maxoutbuf
);
1047 if (sasl_outbuffer
== NULL
) {
1048 sm_ierror("Unable to allocate %d bytes for SASL output "
1049 "buffer", maxoutbuf
);
1054 sasl_inptr
= sasl_inbuffer
;
1056 sasl_outbuffer
= NULL
;
1057 /* Don't NULL out sasl_inbuffer because it could be used in
1067 * Our callback functions to feed data to the SASL library
1071 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1073 nmh_creds_t creds
= (nmh_creds_t
) context
;
1075 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1076 return SASL_BADPARAM
;
1078 if (creds
->user
== NULL
) {
1080 * Pass the 1 third argument to nmh_get_credentials() so
1081 * that a default user if the -user switch to send(1)/post(8)
1082 * wasn't used, and so that a default password will be supplied.
1083 * That's used when those values really don't matter, and only
1084 * with legacy/.netrc, i.e., with a credentials profile entry.
1086 if (nmh_get_credentials (creds
->host
, creds
->user
, 1, creds
) != OK
) {
1087 return SASL_BADPARAM
;
1091 *result
= creds
->user
;
1093 *len
= strlen(creds
->user
);
1099 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1100 sasl_secret_t
**psecret
)
1102 nmh_creds_t creds
= (nmh_creds_t
) context
;
1107 if (! psecret
|| id
!= SASL_CB_PASS
)
1108 return SASL_BADPARAM
;
1110 if (creds
->password
== NULL
) {
1112 * Pass the 0 third argument to nmh_get_credentials() so
1113 * that the default password isn't used. With legacy/.netrc
1114 * credentials support, we'll only get here if the -user
1115 * switch to send(1)/post(8) wasn't used.
1117 if (nmh_get_credentials (creds
->host
, creds
->user
, 0, creds
) != OK
) {
1118 return SASL_BADPARAM
;
1122 len
= strlen (creds
->password
);
1124 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1128 (*psecret
)->len
= len
;
1129 strcpy((char *) (*psecret
)->data
, creds
->password
);
1133 #endif /* CYRUS_SASL */
1136 sm_ierror (char *fmt
, ...)
1141 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1144 sm_reply
.length
= strlen (sm_reply
.text
);
1145 sm_reply
.code
= NOTOK
;
1151 smtalk (int time
, char *fmt
, ...)
1156 size_t bufsize
= BUFSIZ
;
1158 buffer
= mh_xmalloc(bufsize
);
1161 result
= vsnprintf (buffer
, bufsize
, fmt
, ap
);
1164 if (result
> (int) bufsize
) {
1165 buffer
= mh_xrealloc(buffer
, bufsize
= result
+ 1);
1167 vsnprintf (buffer
, bufsize
, fmt
, ap
);
1173 printf("(sasl-encrypted) ");
1175 printf("(tls-encrypted) ");
1176 printf ("=> %s\n", buffer
);
1181 alarm ((unsigned) time
);
1182 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
1193 * write the buffer to the open SMTP channel
1197 sm_wrecord (char *buffer
, int len
)
1200 return sm_werror ();
1202 sm_fwrite (buffer
, len
);
1206 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1211 sm_wstream (char *buffer
, int len
)
1214 static char lc
= '\0';
1217 return sm_werror ();
1219 if (buffer
== NULL
&& len
== 0) {
1223 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1226 for (bp
= buffer
; bp
&& len
> 0; bp
++, len
--) {
1235 sm_fputc ('.');/* FALL THROUGH */
1240 if (ferror (sm_wfp
))
1241 return sm_werror ();
1246 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1250 * Write out to the network, but do buffering for SASL (if enabled)
1254 sm_fwrite(char *buffer
, int len
)
1258 unsigned int outputlen
;
1260 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1261 #endif /* CYRUS_SASL */
1266 ret
= BIO_write(io
, buffer
, len
);
1269 sm_ierror("TLS error during write: %s",
1270 ERR_error_string(ERR_get_error(), NULL
));
1274 #endif /* TLS_SUPPORT */
1275 if ((int) fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
) < len
) {
1276 advise ("sm_fwrite", "fwrite");
1280 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1281 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1282 maxoutbuf
- sasl_outbuflen
);
1283 len
-= maxoutbuf
- sasl_outbuflen
;
1286 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1287 &output
, &outputlen
) != SASL_OK
) {
1288 sm_ierror("Unable to SASL encode connection data: %s",
1289 sasl_errdetail(conn
));
1293 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) <
1295 advise ("sm_fwrite", "fwrite");
1300 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1301 sasl_outbuflen
+= len
;
1304 #endif /* CYRUS_SASL */
1305 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1310 * Negotiate Transport Layer Security
1319 const SSL_METHOD
*method
;
1322 SSL_load_error_strings();
1324 method
= TLSv1_client_method(); /* Not sure about this */
1326 /* Older ssl takes a non-const arg. */
1327 sslctx
= SSL_CTX_new((SSL_METHOD
*) method
);
1331 return sm_ierror("Unable to initialize OpenSSL context: %s",
1332 ERR_error_string(ERR_get_error(), NULL
));
1336 ssl
= SSL_new(sslctx
);
1340 return sm_ierror("Unable to create SSL connection: %s",
1341 ERR_error_string(ERR_get_error(), NULL
));
1344 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
1345 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
1347 if (sbior
== NULL
|| sbiow
== NULL
) {
1349 return sm_ierror("Unable to create BIO endpoints: %s",
1350 ERR_error_string(ERR_get_error(), NULL
));
1353 SSL_set_bio(ssl
, sbior
, sbiow
);
1354 SSL_set_connect_state(ssl
);
1357 * Set up a BIO to handle buffering for us
1360 io
= BIO_new(BIO_f_buffer());
1364 return sm_ierror("Unable to create a buffer BIO: %s",
1365 ERR_error_string(ERR_get_error(), NULL
));
1368 ssl_bio
= BIO_new(BIO_f_ssl());
1372 return sm_ierror("Unable to create a SSL BIO: %s",
1373 ERR_error_string(ERR_get_error(), NULL
));
1376 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1377 BIO_push(io
, ssl_bio
);
1380 * Try doing the handshake now
1383 if (BIO_do_handshake(io
) < 1) {
1385 return sm_ierror("Unable to negotiate SSL connection: %s",
1386 ERR_error_string(ERR_get_error(), NULL
));
1390 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1391 printf("SSL negotiation successful: %s(%d) %s\n",
1392 SSL_CIPHER_get_name(cipher
),
1393 SSL_CIPHER_get_bits(cipher
, NULL
),
1394 SSL_CIPHER_get_version(cipher
));
1402 #endif /* TLS_SUPPORT */
1405 * Convenience functions to replace occurences of fputs() and fputc()
1409 sm_fputs(char *buffer
)
1411 return sm_fwrite(buffer
, strlen(buffer
));
1419 return sm_fwrite(&h
, 1);
1423 * Flush out any pending data on the connection
1431 unsigned int outputlen
;
1434 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1435 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1436 &output
, &outputlen
);
1437 if (result
!= SASL_OK
) {
1438 sm_ierror("Unable to SASL encode connection data: %s",
1439 sasl_errdetail(conn
));
1443 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) < outputlen
) {
1444 advise ("sm_fflush", "fwrite");
1448 #endif /* CYRUS_SASL */
1452 (void) BIO_flush(io
);
1454 #endif /* TLS_SUPPORT */
1463 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1464 : sm_alarmed
? "write to socket timed out"
1465 : "error writing to socket"));
1467 return (sm_reply
.code
= NOTOK
);
1474 int i
, code
, cont
, bc
= 0, rc
, more
;
1477 char **ehlo
= EHLOkeys
, buffer
[BUFSIZ
];
1480 static int at_least_once
= 0;
1482 if (at_least_once
) {
1485 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1499 sm_reply
.length
= 0;
1500 sm_reply
.text
[0] = 0;
1502 rc
= sizeof(sm_reply
.text
) - 1;
1504 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1508 printf("(sasl-decrypted) ");
1510 printf("(tls-decrypted) ");
1511 printf ("<= %s\n", buffer
);
1516 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1517 && (buffer
[3] == '-' || doingEHLO
== 2)
1519 if (doingEHLO
== 2) {
1520 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1521 strcpy (*ehlo
++, buffer
+ 4);
1523 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1533 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1537 code
= atoi ((char *) bp
);
1539 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1541 if (bc
> 0 && *bp
== '-') {
1544 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1549 if (code
!= sm_reply
.code
|| cont
)
1553 sm_reply
.code
= code
;
1556 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1557 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1558 bp
= (unsigned char *) buffer
;
1559 bc
= strlen (sm_noreply
);
1563 if ((i
= min (bc
, rc
)) > 0) {
1567 i
= strlen(sm_moreply
);
1568 if (more
&& rc
> i
+ 1) {
1569 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1576 if (sm_reply
.code
< 100) {
1578 printf ("%s\n", sm_reply
.text
);
1584 sm_reply
.length
= rp
- sm_reply
.text
;
1585 sm_reply
.text
[sm_reply
.length
] = 0;
1586 return sm_reply
.code
;
1593 sm_rrecord (char *buffer
, int *len
)
1598 return sm_rerror(0);
1600 buffer
[*len
= 0] = 0;
1602 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1603 return sm_rerror (retval
);
1604 *len
= strlen (buffer
);
1605 /* *len should be >0 except on EOF, but check for safety's sake */
1607 return sm_rerror (RP_EOF
);
1608 if (buffer
[*len
- 1] != '\n')
1609 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1613 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1622 * Our version of fgets, which calls our private fgetc function
1626 sm_fgets(char *buffer
, int size
, FILE *f
)
1640 } while (size
> 1 && c
!= '\n');
1648 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1650 * Read from the network, but do SASL or TLS encryption
1656 char tmpbuf
[BUFSIZ
], *retbuf
;
1657 unsigned int retbufsize
= 0;
1661 * If we have leftover data, return it
1664 if (sasl_inbuflen
) {
1666 return (int) *sasl_inptr
++;
1670 * If not, read from the network until we have some data to return
1673 while (retbufsize
== 0) {
1677 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1680 result
= SSL_get_error(ssl
, cc
);
1682 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1683 sm_ierror("TLS peer aborted connection");
1690 sm_ierror("SSL_read failed: %s",
1691 ERR_error_string(ERR_get_error(), NULL
));
1695 #endif /* TLS_SUPPORT */
1697 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1703 sm_ierror("Unable to read from network: %s", strerror(errno
));
1708 * Don't call sasl_decode unless sasl is complete and we have
1709 * encryption working
1713 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1717 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1720 if (result
!= SASL_OK
) {
1721 sm_ierror("Unable to decode SASL network data: %s",
1722 sasl_errdetail(conn
));
1726 #else /* ! CYRUS_SASL */
1729 #endif /* CYRUS_SASL */
1732 if (retbufsize
> SASL_MAXRECVBUF
) {
1733 sm_ierror("Received data (%d bytes) is larger than the buffer "
1734 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1738 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1739 sasl_inptr
= sasl_inbuffer
+ 1;
1740 sasl_inbuflen
= retbufsize
- 1;
1742 return (int) sasl_inbuffer
[0];
1744 #endif /* CYRUS_SASL || TLS_SUPPORT */
1749 if (sm_mts
== MTS_SMTP
)
1751 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1752 : sm_alarmed
? "read from socket timed out"
1753 : rc
== RP_EOF
? "premature end-of-file on socket"
1754 : "error reading from socket"));
1757 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1758 : sm_alarmed
? "read from pipe timed out"
1759 : rc
== RP_EOF
? "premature end-of-file on pipe"
1760 : "error reading from pipe"));
1762 return (sm_reply
.code
= NOTOK
);
1771 #ifndef RELIABLE_SIGNALS
1772 SIGNAL (SIGALRM
, alrmser
);
1777 printf ("timed out...\n");
1784 rp_string (int code
)
1787 static char buffer
[BUFSIZ
];
1789 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1809 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1829 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1830 text
, sm_reply
.code
, sm_reply
.text
);
1842 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1844 if (strncmp (ep
, s
, len
) == 0) {
1845 for (ep
+= len
; *ep
== ' '; ep
++)