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.
13 #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 char *sasl_pw_context
[3]; /* Context to pass into sm_get_pass */
102 static int maxoutbuf
; /* Maximum crypto output buffer */
103 static char *sasl_outbuffer
; /* SASL output buffer for encryption */
104 static int sasl_outbuflen
; /* Current length of data in outbuf */
105 static int sm_get_user(void *, int, const char **, unsigned *);
106 static int sm_get_pass(sasl_conn_t
*, void *, int, sasl_secret_t
**);
108 static sasl_callback_t callbacks
[] = {
109 { SASL_CB_USER
, (sasl_callback_ft
) sm_get_user
, NULL
},
110 #define SM_SASL_N_CB_USER 0
111 { SASL_CB_AUTHNAME
, (sasl_callback_ft
) sm_get_user
, NULL
},
112 #define SM_SASL_N_CB_AUTHNAME 1
113 { SASL_CB_PASS
, (sasl_callback_ft
) sm_get_pass
, NULL
},
114 #define SM_SASL_N_CB_PASS 2
115 { SASL_CB_LIST_END
, NULL
, NULL
},
118 #else /* CYRUS_SASL */
120 #endif /* CYRUS_SASL */
123 static SSL_CTX
*sslctx
= NULL
;
124 static SSL
*ssl
= NULL
;
125 static BIO
*sbior
= NULL
;
126 static BIO
*sbiow
= NULL
;
127 static BIO
*io
= NULL
;
129 static int tls_negotiate(void);
130 #endif /* TLS_SUPPORT */
132 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
133 #define SASL_MAXRECVBUF 65536
134 static int sm_fgetc(FILE *);
135 static char *sasl_inbuffer
; /* SASL input buffer for encryption */
136 static char *sasl_inptr
; /* Pointer to current inbuf position */
137 static int sasl_inbuflen
; /* Current length of data in inbuf */
139 #define sm_fgetc fgetc
142 static int tls_active
= 0;
144 static char *sm_noreply
= "No reply text given";
145 static char *sm_moreply
= "; ";
147 struct smtp sm_reply
; /* global... */
151 static int doingEHLO
;
152 char *EHLOkeys
[MAXEHLO
+ 1];
157 static int smtp_init (char *, char *, char *, int, int, int, int, int, int,
158 char *, char *, int);
159 static int sendmail_init (char *, char *, int, int, int, int, int, int,
162 static int rclient (char *, char *);
163 static int sm_ierror (char *fmt
, ...);
164 static int smtalk (int time
, char *fmt
, ...);
165 static int sm_wrecord (char *, int);
166 static int sm_wstream (char *, int);
167 static int sm_werror (void);
168 static int smhear (void);
169 static int sm_rrecord (char *, int *);
170 static int sm_rerror (int);
171 static void alrmser (int);
172 static char *EHLOset (char *);
173 static int sm_fwrite(char *, int);
174 static int sm_fputs(char *);
175 static int sm_fputc(int);
176 static void sm_fflush(void);
177 static int sm_fgets(char *, int, FILE *);
181 * Function prototypes needed for SASL
184 static int sm_auth_sasl(char *, int, char *, char *);
185 #endif /* CYRUS_SASL */
188 sm_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
189 int debug
, int queued
, int sasl
, int saslssf
,
190 char *saslmech
, char *user
, int tls
)
192 if (sm_mts
== MTS_SMTP
)
193 return smtp_init (client
, server
, port
, watch
, verbose
,
194 debug
, queued
, sasl
, saslssf
, saslmech
,
197 return sendmail_init (client
, server
, watch
, verbose
,
198 debug
, queued
, sasl
, saslssf
, saslmech
,
203 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
204 int debug
, int queued
,
205 int sasl
, int saslssf
, char *saslmech
, char *user
, int tls
)
207 int result
, sd1
, sd2
;
210 #else /* CYRUS_SASL */
212 NMH_UNUSED (saslssf
);
213 NMH_UNUSED (saslmech
);
215 #endif /* CYRUS_SASL */
220 sm_verbose
= verbose
;
223 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
226 if (client
== NULL
|| *client
== '\0') {
230 client
= LocalName(1); /* no clientname -> LocalName */
235 * Last-ditch check just in case client still isn't set to anything
238 if (client
== NULL
|| *client
== '\0')
239 client
= "localhost";
241 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
242 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
244 return sm_ierror("Unable to allocate %d bytes for read buffer",
246 #endif /* CYRUS_SASL || TLS_SUPPORT */
248 if ((sd1
= rclient (server
, port
)) == NOTOK
)
251 if ((sd2
= dup (sd1
)) == NOTOK
) {
253 return sm_ierror ("unable to dup");
256 SIGNAL (SIGALRM
, alrmser
);
257 SIGNAL (SIGPIPE
, SIG_IGN
);
259 if ((sm_rfp
= fdopen (sd1
, "r")) == NULL
260 || (sm_wfp
= fdopen (sd2
, "w")) == NULL
) {
263 sm_rfp
= sm_wfp
= NULL
;
264 return sm_ierror ("unable to fdopen");
271 * If tls == 2, that means that the user requested "initial" TLS,
272 * which happens right after the connection has opened. Do that
277 result
= tls_negotiate();
280 * Note: if tls_negotiate() fails it will call sm_end() for us,
281 * which closes the connection.
286 #endif /* TLS_SUPPORT */
303 * Give EHLO or HELO command
307 result
= smtalk (SM_HELO
, "EHLO %s", client
);
310 if (result
>= 500 && result
<= 599)
311 result
= smtalk (SM_HELO
, "HELO %s", client
);
320 * If the user requested TLS support, then try to do the STARTTLS command
321 * as part of the initial dialog. Assuming this works, we then need to
322 * restart the EHLO dialog after TLS negotiation is complete.
326 if (! EHLOset("STARTTLS")) {
328 return sm_ierror("SMTP server does not support TLS");
331 result
= smtalk(SM_HELO
, "STARTTLS");
339 * Okay, the other side should be waiting for us to start TLS
340 * negotiation. Oblige them.
343 result
= tls_negotiate();
349 result
= smtalk (SM_HELO
, "EHLO %s", client
);
357 #else /* TLS_SUPPORT */
359 #endif /* TLS_SUPPORT */
363 * If the user asked for SASL, then check to see if the SMTP server
364 * supports it. Otherwise, error out (because the SMTP server
365 * might have been spoofed; we don't want to just silently not
370 if (! (server_mechs
= EHLOset("AUTH"))) {
372 return sm_ierror("SMTP server does not support SASL");
375 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
377 return sm_ierror("Requested SASL mech \"%s\" is not in the "
378 "list of supported mechanisms:\n%s",
379 saslmech
, server_mechs
);
382 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
388 #endif /* CYRUS_SASL */
391 if (watch
&& EHLOset ("XVRB"))
392 smtalk (SM_HELO
, "VERB on");
393 if (queued
&& EHLOset ("XQUE"))
394 smtalk (SM_HELO
, "QUED");
400 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
401 int debug
, int queued
,
402 int sasl
, int saslssf
, char *saslmech
, char *user
)
404 unsigned int i
, result
, vecp
;
409 #else /* CYRUS_SASL */
412 NMH_UNUSED (saslssf
);
413 NMH_UNUSED (saslmech
);
415 #endif /* CYRUS_SASL */
420 sm_verbose
= verbose
;
422 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
425 if (client
== NULL
|| *client
== '\0') {
429 client
= LocalName(1); /* no clientname -> LocalName */
433 * Last-ditch check just in case client still isn't set to anything
436 if (client
== NULL
|| *client
== '\0')
437 client
= "localhost";
439 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
440 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
442 return sm_ierror("Unable to allocate %d bytes for read buffer",
444 #endif /* CYRUS_SASL || TLS_SUPPORT */
446 if (pipe (pdi
) == NOTOK
)
447 return sm_ierror ("no pipes");
448 if (pipe (pdo
) == NOTOK
) {
451 return sm_ierror ("no pipes");
454 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
463 return sm_ierror ("unable to fork");
466 if (pdo
[0] != fileno (stdin
))
467 dup2 (pdo
[0], fileno (stdin
));
468 if (pdi
[1] != fileno (stdout
))
469 dup2 (pdi
[1], fileno (stdout
));
470 if (pdi
[1] != fileno (stderr
))
471 dup2 (pdi
[1], fileno (stderr
));
472 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
476 vec
[vecp
++] = r1bindex (sendmail
, '/');
478 vec
[vecp
++] = watch
? "-odi" : queued
? "-odq" : "-odb";
479 vec
[vecp
++] = "-oem";
487 execvp (sendmail
, vec
);
488 fprintf (stderr
, "unable to exec ");
490 _exit (-1); /* NOTREACHED */
493 SIGNAL (SIGALRM
, alrmser
);
494 SIGNAL (SIGPIPE
, SIG_IGN
);
498 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
499 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
502 sm_rfp
= sm_wfp
= NULL
;
503 return sm_ierror ("unable to fdopen");
519 result
= smtalk (SM_HELO
, "EHLO %s", client
);
522 if (500 <= result
&& result
<= 599)
523 result
= smtalk (SM_HELO
, "HELO %s", client
);
536 * If the user asked for SASL, then check to see if the SMTP server
537 * supports it. Otherwise, error out (because the SMTP server
538 * might have been spoofed; we don't want to just silently not
543 if (! (server_mechs
= EHLOset("AUTH"))) {
545 return sm_ierror("SMTP server does not support SASL");
548 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
550 return sm_ierror("Requested SASL mech \"%s\" is not in the "
551 "list of supported mechanisms:\n%s",
552 saslmech
, server_mechs
);
555 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
561 #endif /* CYRUS_SASL */
564 smtalk (SM_HELO
, "VERB on");
571 rclient (char *server
, char *service
)
574 char response
[BUFSIZ
];
576 if ((sd
= client (server
, service
, response
, sizeof(response
),
580 sm_ierror ("%s", response
);
585 sm_winit (char *from
)
587 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
604 sm_wadr (char *mbox
, char *host
, char *path
)
606 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
608 path
? path
: "", mbox
, host
)) {
618 #endif /* SENDMAILBUG */
643 switch (smtalk (SM_DATA
, "DATA")) {
652 #endif /* SENDMAILBUG */
669 sm_wtxt (char *buffer
, int len
)
675 result
= sm_wstream (buffer
, len
);
678 return (result
== NOTOK
? RP_BHST
: RP_OK
);
685 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
688 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
696 #endif /* SENDMAILBUG */
714 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
725 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
730 smtalk (SM_QUIT
, "QUIT");
734 sm_note
.code
= sm_reply
.code
;
735 sm_note
.length
= sm_reply
.length
;
736 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
738 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
740 if (sm_mts
== MTS_SMTP
)
741 smtalk (SM_QUIT
, "QUIT");
743 /* The SIGPIPE block replaces old calls to discard ().
744 We're not sure what the discard () calls were for,
745 maybe to prevent deadlock on old systems. In any
746 case, blocking SIGPIPE should be harmless.
747 Because the file handles are closed below, leave it
751 sigaddset (&set
, SIGPIPE
);
752 sigprocmask (SIG_BLOCK
, &set
, &oset
);
754 kill (sm_child
, SIGKILL
);
758 sm_reply
.code
= sm_note
.code
;
759 sm_reply
.length
= sm_note
.length
;
760 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
767 BIO_ssl_shutdown(io
);
770 #endif /* TLS_SUPPORT */
772 if (sm_rfp
!= NULL
) {
777 if (sm_wfp
!= NULL
) {
783 if (sm_mts
== MTS_SMTP
) {
788 if (sasl_outbuffer
) {
789 free(sasl_outbuffer
);
794 #endif /* CYRUS_SASL */
795 } else if (sm_child
!= NOTOK
) {
796 status
= pidwait (sm_child
, OK
);
802 sm_rfp
= sm_wfp
= NULL
;
803 return (status
? RP_BHST
: RP_OK
);
808 * This function implements SASL authentication for SMTP. If this function
809 * completes successfully, then authentication is successful and we've
810 * (optionally) negotiated a security layer.
813 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
816 unsigned int buflen
, outlen
;
817 char *buf
, outbuf
[BUFSIZ
], host
[NI_MAXHOST
];
818 const char *chosen_mech
;
819 sasl_security_properties_t secprops
;
825 * Initialize the callback contexts
829 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
830 * to us on the command line, then call getpeername and do a
831 * reverse-address lookup on the IP address to get the name.
834 memset(host
, 0, sizeof(host
));
837 struct sockaddr_storage sin
;
838 socklen_t len
= sizeof(sin
);
841 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
842 sm_ierror("getpeername on SMTP socket failed: %s",
847 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
848 NULL
, 0, NI_NAMEREQD
);
850 sm_ierror("Unable to look up name of connected host: %s",
851 gai_strerror(result
));
855 strncpy(host
, inhost
, sizeof(host
) - 1);
858 callbacks
[SM_SASL_N_CB_USER
].context
= user
;
859 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= user
;
861 sasl_pw_context
[0] = host
;
862 sasl_pw_context
[1] = user
;
863 sasl_pw_context
[2] = pass
;
865 callbacks
[SM_SASL_N_CB_PASS
].context
= sasl_pw_context
;
867 result
= sasl_client_init(callbacks
);
869 if (result
!= SASL_OK
) {
870 sm_ierror("SASL library initialization failed: %s",
871 sasl_errstring(result
, NULL
, NULL
));
875 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
877 if (result
!= SASL_OK
) {
878 sm_ierror("SASL client initialization failed: %s",
879 sasl_errstring(result
, NULL
, NULL
));
884 * Initialize the security properties. But if TLS is active, then
885 * don't negotiate encryption here.
888 memset(&secprops
, 0, sizeof(secprops
));
889 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
891 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
893 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
895 if (result
!= SASL_OK
) {
896 sm_ierror("SASL security property initialization failed: %s",
897 sasl_errstring(result
, NULL
, NULL
));
902 * Start the actual protocol. Feed the mech list into the library
903 * and get out a possible initial challenge
906 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
907 &buflen
, (const char **) &chosen_mech
);
909 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
910 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
915 * If we got an initial challenge, send it as part of the AUTH
916 * command; otherwise, just send a plain AUTH command.
920 status
= sasl_encode64(buf
, buflen
, outbuf
, sizeof(outbuf
), NULL
);
921 if (status
!= SASL_OK
) {
922 sm_ierror("SASL base64 encode failed: %s",
923 sasl_errstring(status
, NULL
, NULL
));
927 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
929 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
932 * Now we loop until we either fail, get a SASL_OK, or a 235
933 * response code. Receive the challenges and process them until
937 while (result
== SASL_CONTINUE
) {
940 * If we get a 235 response, that means authentication has
941 * succeeded and we need to break out of the loop (yes, even if
942 * we still get SASL_CONTINUE from sasl_client_step()).
944 * Otherwise, if we get a message that doesn't seem to be a
945 * valid response, then abort
950 else if (status
< 300 || status
> 399)
954 * Special case; a zero-length response from the SMTP server
955 * is returned as a single =. If we get that, then set buflen
956 * to be zero. Otherwise, just decode the response.
959 if (strcmp("=", sm_reply
.text
) == 0) {
962 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
963 outbuf
, sizeof(outbuf
), &outlen
);
965 if (result
!= SASL_OK
) {
966 smtalk(SM_AUTH
, "*");
967 sm_ierror("SASL base64 decode failed: %s",
968 sasl_errstring(result
, NULL
, NULL
));
973 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
974 (const char **) &buf
, &buflen
);
976 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
977 smtalk(SM_AUTH
, "*");
978 sm_ierror("SASL client negotiation failed: %s",
979 sasl_errstring(result
, NULL
, NULL
));
983 status
= sasl_encode64(buf
, buflen
, outbuf
, sizeof(outbuf
), NULL
);
985 if (status
!= SASL_OK
) {
986 smtalk(SM_AUTH
, "*");
987 sm_ierror("SASL base64 encode failed: %s",
988 sasl_errstring(status
, NULL
, NULL
));
992 status
= smtalk(SM_AUTH
, outbuf
);
996 * Make sure that we got the correct response
999 if (status
< 200 || status
> 299)
1003 * We _should_ have completed the authentication successfully.
1004 * Get a few properties from the authentication exchange.
1007 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
1009 if (result
!= SASL_OK
) {
1010 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1011 sasl_errstring(result
, NULL
, NULL
));
1015 maxoutbuf
= *outbufmax
;
1017 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
1021 if (result
!= SASL_OK
) {
1022 sm_ierror("Cannot retrieve SASL negotiated security strength "
1023 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
1028 sasl_outbuffer
= malloc(maxoutbuf
);
1030 if (sasl_outbuffer
== NULL
) {
1031 sm_ierror("Unable to allocate %d bytes for SASL output "
1032 "buffer", maxoutbuf
);
1037 sasl_inptr
= sasl_inbuffer
;
1039 sasl_outbuffer
= NULL
;
1040 /* Don't NULL out sasl_inbuffer because it could be used in
1050 * Our callback functions to feed data to the SASL library
1054 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1056 char *user
= (char *) context
;
1058 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1059 return SASL_BADPARAM
;
1063 *len
= strlen(user
);
1069 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1070 sasl_secret_t
**psecret
)
1072 char **pw_context
= (char **) context
;
1077 if (! psecret
|| id
!= SASL_CB_PASS
)
1078 return SASL_BADPARAM
;
1080 len
= strlen (pw_context
[2]);
1082 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1086 (*psecret
)->len
= len
;
1087 strcpy((char *) (*psecret
)->data
, pw_context
[2]);
1091 #endif /* CYRUS_SASL */
1094 sm_ierror (char *fmt
, ...)
1099 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1102 sm_reply
.length
= strlen (sm_reply
.text
);
1103 sm_reply
.code
= NOTOK
;
1109 smtalk (int time
, char *fmt
, ...)
1113 char buffer
[BUFSIZ
];
1116 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
1121 printf("(sasl-encrypted) ");
1123 printf("(tls-encrypted) ");
1124 printf ("=> %s\n", buffer
);
1129 alarm ((unsigned) time
);
1130 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
1139 * write the buffer to the open SMTP channel
1143 sm_wrecord (char *buffer
, int len
)
1146 return sm_werror ();
1148 sm_fwrite (buffer
, len
);
1152 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1157 sm_wstream (char *buffer
, int len
)
1160 static char lc
= '\0';
1163 return sm_werror ();
1165 if (buffer
== NULL
&& len
== 0) {
1169 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1172 for (bp
= buffer
; len
> 0; bp
++, len
--) {
1181 sm_fputc ('.');/* FALL THROUGH */
1186 if (ferror (sm_wfp
))
1187 return sm_werror ();
1192 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1196 * Write out to the network, but do buffering for SASL (if enabled)
1200 sm_fwrite(char *buffer
, int len
)
1204 unsigned int outputlen
;
1206 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1207 #endif /* CYRUS_SASL */
1212 ret
= BIO_write(io
, buffer
, len
);
1215 sm_ierror("TLS error during write: %s",
1216 ERR_error_string(ERR_get_error(), NULL
));
1220 #endif /* TLS_SUPPORT */
1221 fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
);
1224 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1225 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1226 maxoutbuf
- sasl_outbuflen
);
1227 len
-= maxoutbuf
- sasl_outbuflen
;
1230 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1231 &output
, &outputlen
) != SASL_OK
) {
1232 sm_ierror("Unable to SASL encode connection data: %s",
1233 sasl_errdetail(conn
));
1237 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1241 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1242 sasl_outbuflen
+= len
;
1245 #endif /* CYRUS_SASL */
1246 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1251 * Negotiate Transport Layer Security
1260 const SSL_METHOD
*method
;
1263 SSL_load_error_strings();
1265 method
= TLSv1_client_method(); /* Not sure about this */
1267 /* Older ssl takes a non-const arg. */
1268 sslctx
= SSL_CTX_new((SSL_METHOD
*) method
);
1272 return sm_ierror("Unable to initialize OpenSSL context: %s",
1273 ERR_error_string(ERR_get_error(), NULL
));
1277 ssl
= SSL_new(sslctx
);
1281 return sm_ierror("Unable to create SSL connection: %s",
1282 ERR_error_string(ERR_get_error(), NULL
));
1285 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
1286 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
1288 if (sbior
== NULL
|| sbiow
== NULL
) {
1290 return sm_ierror("Unable to create BIO endpoints: %s",
1291 ERR_error_string(ERR_get_error(), NULL
));
1294 SSL_set_bio(ssl
, sbior
, sbiow
);
1295 SSL_set_connect_state(ssl
);
1298 * Set up a BIO to handle buffering for us
1301 io
= BIO_new(BIO_f_buffer());
1305 return sm_ierror("Unable to create a buffer BIO: %s",
1306 ERR_error_string(ERR_get_error(), NULL
));
1309 ssl_bio
= BIO_new(BIO_f_ssl());
1313 return sm_ierror("Unable to create a SSL BIO: %s",
1314 ERR_error_string(ERR_get_error(), NULL
));
1317 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1318 BIO_push(io
, ssl_bio
);
1321 * Try doing the handshake now
1324 if (BIO_do_handshake(io
) < 1) {
1326 return sm_ierror("Unable to negotiate SSL connection: %s",
1327 ERR_error_string(ERR_get_error(), NULL
));
1331 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1332 printf("SSL negotiation successful: %s(%d) %s\n",
1333 SSL_CIPHER_get_name(cipher
),
1334 SSL_CIPHER_get_bits(cipher
, NULL
),
1335 SSL_CIPHER_get_version(cipher
));
1343 #endif /* TLS_SUPPORT */
1346 * Convenience functions to replace occurences of fputs() and fputc()
1350 sm_fputs(char *buffer
)
1352 return sm_fwrite(buffer
, strlen(buffer
));
1360 return sm_fwrite(&h
, 1);
1364 * Flush out any pending data on the connection
1372 unsigned int outputlen
;
1375 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1376 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1377 &output
, &outputlen
);
1378 if (result
!= SASL_OK
) {
1379 sm_ierror("Unable to SASL encode connection data: %s",
1380 sasl_errdetail(conn
));
1384 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1387 #endif /* CYRUS_SASL */
1391 (void) BIO_flush(io
);
1393 #endif /* TLS_SUPPORT */
1402 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1403 : sm_alarmed
? "write to socket timed out"
1404 : "error writing to socket"));
1406 return (sm_reply
.code
= NOTOK
);
1413 int i
, code
, cont
, bc
= 0, rc
, more
;
1416 char **ehlo
= NULL
, buffer
[BUFSIZ
];
1419 static int at_least_once
= 0;
1421 if (at_least_once
) {
1424 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1438 sm_reply
.length
= 0;
1439 sm_reply
.text
[0] = 0;
1441 rc
= sizeof(sm_reply
.text
) - 1;
1443 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1447 printf("(sasl-decrypted) ");
1449 printf("(tls-decrypted) ");
1450 printf ("<= %s\n", buffer
);
1455 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1456 && (buffer
[3] == '-' || doingEHLO
== 2)
1458 if (doingEHLO
== 2) {
1459 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1460 strcpy (*ehlo
++, buffer
+ 4);
1462 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1472 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1476 code
= atoi ((char *) bp
);
1478 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1480 if (bc
> 0 && *bp
== '-') {
1483 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1488 if (code
!= sm_reply
.code
|| cont
)
1492 sm_reply
.code
= code
;
1495 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1496 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1497 bp
= (unsigned char *) buffer
;
1498 bc
= strlen (sm_noreply
);
1502 if ((i
= min (bc
, rc
)) > 0) {
1506 i
= strlen(sm_moreply
);
1507 if (more
&& rc
> i
+ 1) {
1508 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1515 if (sm_reply
.code
< 100) {
1517 printf ("%s\n", sm_reply
.text
);
1523 sm_reply
.length
= rp
- sm_reply
.text
;
1524 sm_reply
.text
[sm_reply
.length
] = 0;
1525 return sm_reply
.code
;
1532 sm_rrecord (char *buffer
, int *len
)
1537 return sm_rerror(0);
1539 buffer
[*len
= 0] = 0;
1541 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1542 return sm_rerror (retval
);
1543 *len
= strlen (buffer
);
1544 /* *len should be >0 except on EOF, but check for safety's sake */
1546 return sm_rerror (RP_EOF
);
1547 if (buffer
[*len
- 1] != '\n')
1548 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1552 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1561 * Our version of fgets, which calls our private fgetc function
1565 sm_fgets(char *buffer
, int size
, FILE *f
)
1579 } while (size
> 1 && c
!= '\n');
1587 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1589 * Read from the network, but do SASL or TLS encryption
1595 char tmpbuf
[BUFSIZ
], *retbuf
;
1596 unsigned int retbufsize
= 0;
1600 * If we have leftover data, return it
1603 if (sasl_inbuflen
) {
1605 return (int) *sasl_inptr
++;
1609 * If not, read from the network until we have some data to return
1612 while (retbufsize
== 0) {
1616 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1619 result
= SSL_get_error(ssl
, cc
);
1621 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1622 sm_ierror("TLS peer aborted connection");
1629 sm_ierror("SSL_read failed: %s",
1630 ERR_error_string(ERR_get_error(), NULL
));
1634 #endif /* TLS_SUPPORT */
1636 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1642 sm_ierror("Unable to read from network: %s", strerror(errno
));
1647 * Don't call sasl_decode unless sasl is complete and we have
1648 * encryption working
1652 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1656 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1659 if (result
!= SASL_OK
) {
1660 sm_ierror("Unable to decode SASL network data: %s",
1661 sasl_errdetail(conn
));
1665 #else /* ! CYRUS_SASL */
1668 #endif /* CYRUS_SASL */
1671 if (retbufsize
> SASL_MAXRECVBUF
) {
1672 sm_ierror("Received data (%d bytes) is larger than the buffer "
1673 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1677 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1678 sasl_inptr
= sasl_inbuffer
+ 1;
1679 sasl_inbuflen
= retbufsize
- 1;
1681 return (int) sasl_inbuffer
[0];
1683 #endif /* CYRUS_SASL || TLS_SUPPORT */
1688 if (sm_mts
== MTS_SMTP
)
1690 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1691 : sm_alarmed
? "read from socket timed out"
1692 : rc
== RP_EOF
? "premature end-of-file on socket"
1693 : "error reading from socket"));
1696 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1697 : sm_alarmed
? "read from pipe timed out"
1698 : rc
== RP_EOF
? "premature end-of-file on pipe"
1699 : "error reading from pipe"));
1701 return (sm_reply
.code
= NOTOK
);
1710 #ifndef RELIABLE_SIGNALS
1711 SIGNAL (SIGALRM
, alrmser
);
1716 printf ("timed out...\n");
1723 rp_string (int code
)
1726 static char buffer
[BUFSIZ
];
1728 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1748 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1768 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1769 text
, sm_reply
.code
, sm_reply
.text
);
1781 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1783 if (strncmp (ep
, s
, len
) == 0) {
1784 for (ep
+= len
; *ep
== ' '; ep
++)