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
; 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 fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
);
1278 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1279 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1280 maxoutbuf
- sasl_outbuflen
);
1281 len
-= maxoutbuf
- sasl_outbuflen
;
1284 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1285 &output
, &outputlen
) != SASL_OK
) {
1286 sm_ierror("Unable to SASL encode connection data: %s",
1287 sasl_errdetail(conn
));
1291 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1295 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1296 sasl_outbuflen
+= len
;
1299 #endif /* CYRUS_SASL */
1300 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1305 * Negotiate Transport Layer Security
1314 const SSL_METHOD
*method
;
1317 SSL_load_error_strings();
1319 method
= TLSv1_client_method(); /* Not sure about this */
1321 /* Older ssl takes a non-const arg. */
1322 sslctx
= SSL_CTX_new((SSL_METHOD
*) method
);
1326 return sm_ierror("Unable to initialize OpenSSL context: %s",
1327 ERR_error_string(ERR_get_error(), NULL
));
1331 ssl
= SSL_new(sslctx
);
1335 return sm_ierror("Unable to create SSL connection: %s",
1336 ERR_error_string(ERR_get_error(), NULL
));
1339 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
1340 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
1342 if (sbior
== NULL
|| sbiow
== NULL
) {
1344 return sm_ierror("Unable to create BIO endpoints: %s",
1345 ERR_error_string(ERR_get_error(), NULL
));
1348 SSL_set_bio(ssl
, sbior
, sbiow
);
1349 SSL_set_connect_state(ssl
);
1352 * Set up a BIO to handle buffering for us
1355 io
= BIO_new(BIO_f_buffer());
1359 return sm_ierror("Unable to create a buffer BIO: %s",
1360 ERR_error_string(ERR_get_error(), NULL
));
1363 ssl_bio
= BIO_new(BIO_f_ssl());
1367 return sm_ierror("Unable to create a SSL BIO: %s",
1368 ERR_error_string(ERR_get_error(), NULL
));
1371 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1372 BIO_push(io
, ssl_bio
);
1375 * Try doing the handshake now
1378 if (BIO_do_handshake(io
) < 1) {
1380 return sm_ierror("Unable to negotiate SSL connection: %s",
1381 ERR_error_string(ERR_get_error(), NULL
));
1385 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1386 printf("SSL negotiation successful: %s(%d) %s\n",
1387 SSL_CIPHER_get_name(cipher
),
1388 SSL_CIPHER_get_bits(cipher
, NULL
),
1389 SSL_CIPHER_get_version(cipher
));
1397 #endif /* TLS_SUPPORT */
1400 * Convenience functions to replace occurences of fputs() and fputc()
1404 sm_fputs(char *buffer
)
1406 return sm_fwrite(buffer
, strlen(buffer
));
1414 return sm_fwrite(&h
, 1);
1418 * Flush out any pending data on the connection
1426 unsigned int outputlen
;
1429 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1430 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1431 &output
, &outputlen
);
1432 if (result
!= SASL_OK
) {
1433 sm_ierror("Unable to SASL encode connection data: %s",
1434 sasl_errdetail(conn
));
1438 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1441 #endif /* CYRUS_SASL */
1445 (void) BIO_flush(io
);
1447 #endif /* TLS_SUPPORT */
1456 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1457 : sm_alarmed
? "write to socket timed out"
1458 : "error writing to socket"));
1460 return (sm_reply
.code
= NOTOK
);
1467 int i
, code
, cont
, bc
= 0, rc
, more
;
1470 char **ehlo
= NULL
, buffer
[BUFSIZ
];
1473 static int at_least_once
= 0;
1475 if (at_least_once
) {
1478 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1492 sm_reply
.length
= 0;
1493 sm_reply
.text
[0] = 0;
1495 rc
= sizeof(sm_reply
.text
) - 1;
1497 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1501 printf("(sasl-decrypted) ");
1503 printf("(tls-decrypted) ");
1504 printf ("<= %s\n", buffer
);
1509 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1510 && (buffer
[3] == '-' || doingEHLO
== 2)
1512 if (doingEHLO
== 2) {
1513 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1514 strcpy (*ehlo
++, buffer
+ 4);
1516 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1526 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1530 code
= atoi ((char *) bp
);
1532 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1534 if (bc
> 0 && *bp
== '-') {
1537 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1542 if (code
!= sm_reply
.code
|| cont
)
1546 sm_reply
.code
= code
;
1549 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1550 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1551 bp
= (unsigned char *) buffer
;
1552 bc
= strlen (sm_noreply
);
1556 if ((i
= min (bc
, rc
)) > 0) {
1560 i
= strlen(sm_moreply
);
1561 if (more
&& rc
> i
+ 1) {
1562 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1569 if (sm_reply
.code
< 100) {
1571 printf ("%s\n", sm_reply
.text
);
1577 sm_reply
.length
= rp
- sm_reply
.text
;
1578 sm_reply
.text
[sm_reply
.length
] = 0;
1579 return sm_reply
.code
;
1586 sm_rrecord (char *buffer
, int *len
)
1591 return sm_rerror(0);
1593 buffer
[*len
= 0] = 0;
1595 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1596 return sm_rerror (retval
);
1597 *len
= strlen (buffer
);
1598 /* *len should be >0 except on EOF, but check for safety's sake */
1600 return sm_rerror (RP_EOF
);
1601 if (buffer
[*len
- 1] != '\n')
1602 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1606 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1615 * Our version of fgets, which calls our private fgetc function
1619 sm_fgets(char *buffer
, int size
, FILE *f
)
1633 } while (size
> 1 && c
!= '\n');
1641 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1643 * Read from the network, but do SASL or TLS encryption
1649 char tmpbuf
[BUFSIZ
], *retbuf
;
1650 unsigned int retbufsize
= 0;
1654 * If we have leftover data, return it
1657 if (sasl_inbuflen
) {
1659 return (int) *sasl_inptr
++;
1663 * If not, read from the network until we have some data to return
1666 while (retbufsize
== 0) {
1670 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1673 result
= SSL_get_error(ssl
, cc
);
1675 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1676 sm_ierror("TLS peer aborted connection");
1683 sm_ierror("SSL_read failed: %s",
1684 ERR_error_string(ERR_get_error(), NULL
));
1688 #endif /* TLS_SUPPORT */
1690 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1696 sm_ierror("Unable to read from network: %s", strerror(errno
));
1701 * Don't call sasl_decode unless sasl is complete and we have
1702 * encryption working
1706 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1710 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1713 if (result
!= SASL_OK
) {
1714 sm_ierror("Unable to decode SASL network data: %s",
1715 sasl_errdetail(conn
));
1719 #else /* ! CYRUS_SASL */
1722 #endif /* CYRUS_SASL */
1725 if (retbufsize
> SASL_MAXRECVBUF
) {
1726 sm_ierror("Received data (%d bytes) is larger than the buffer "
1727 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1731 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1732 sasl_inptr
= sasl_inbuffer
+ 1;
1733 sasl_inbuflen
= retbufsize
- 1;
1735 return (int) sasl_inbuffer
[0];
1737 #endif /* CYRUS_SASL || TLS_SUPPORT */
1742 if (sm_mts
== MTS_SMTP
)
1744 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1745 : sm_alarmed
? "read from socket timed out"
1746 : rc
== RP_EOF
? "premature end-of-file on socket"
1747 : "error reading from socket"));
1750 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1751 : sm_alarmed
? "read from pipe timed out"
1752 : rc
== RP_EOF
? "premature end-of-file on pipe"
1753 : "error reading from pipe"));
1755 return (sm_reply
.code
= NOTOK
);
1764 #ifndef RELIABLE_SIGNALS
1765 SIGNAL (SIGALRM
, alrmser
);
1770 printf ("timed out...\n");
1777 rp_string (int code
)
1780 static char buffer
[BUFSIZ
];
1782 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1802 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1822 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1823 text
, sm_reply
.code
, sm_reply
.text
);
1835 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1837 if (strncmp (ep
, s
, len
) == 0) {
1838 for (ep
+= len
; *ep
== ' '; ep
++)