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>
30 #endif /* CYRUS_SASL */
33 #include <openssl/ssl.h>
34 #include <openssl/err.h>
35 #endif /* TLS_SUPPORT */
38 * This module implements an interface to SendMail very similar
39 * to the MMDF mm_(3) routines. The sm_() routines herein talk
40 * SMTP to a sendmail process, mapping SMTP reply codes into
45 * On older 4.2BSD machines without the POSIX function `sigaction',
46 * the alarm handing stuff for time-outs will NOT work due to the way
47 * syscalls get restarted. This is not really crucial, since SendMail
48 * is generally well-behaved in this area.
53 * It appears that some versions of Sendmail will return Code 451
54 * when they don't really want to indicate a failure.
55 * "Code 451 almost always means sendmail has deferred; we don't
56 * really want bomb out at this point since sendmail will rectify
57 * things later." So, if you define SENDMAILBUG, Code 451 is
58 * considered the same as Code 250. Yuck!
65 #define NBITS ((sizeof (int)) * 8)
68 * these codes must all be different!
70 #define SM_OPEN 300 /* Changed to 5 minutes to comply with a SHOULD in RFC 1123 */
73 #define SM_MAIL 301 /* changed to 5 minutes and a second (for uniqueness), see above */
74 #define SM_RCPT 302 /* see above */
75 #define SM_DATA 120 /* see above */
76 #define SM_TEXT 180 /* see above */
77 #define SM_DOT 600 /* see above */
82 #endif /* CYRUS_SASL */
84 static int sm_addrs
= 0;
85 static int sm_alarmed
= 0;
86 static int sm_child
= NOTOK
;
87 static int sm_debug
= 0;
88 static int sm_nl
= TRUE
;
89 static int sm_verbose
= 0;
91 static FILE *sm_rfp
= NULL
;
92 static FILE *sm_wfp
= NULL
;
96 * Some globals needed by SASL
99 static sasl_conn_t
*conn
= NULL
; /* SASL connection state */
100 static int sasl_complete
= 0; /* Has authentication succeded? */
101 static sasl_ssf_t sasl_ssf
; /* Our security strength factor */
102 static char *sasl_pw_context
[2]; /* Context to pass into sm_get_pass */
103 static int maxoutbuf
; /* Maximum crypto output buffer */
104 static char *sasl_outbuffer
; /* SASL output buffer for encryption */
105 static int sasl_outbuflen
; /* Current length of data in outbuf */
106 static int sm_get_user(void *, int, const char **, unsigned *);
107 static int sm_get_pass(sasl_conn_t
*, void *, int, sasl_secret_t
**);
109 static sasl_callback_t callbacks
[] = {
110 { SASL_CB_USER
, (sasl_callback_ft
) sm_get_user
, NULL
},
111 #define SM_SASL_N_CB_USER 0
112 { SASL_CB_PASS
, (sasl_callback_ft
) sm_get_pass
, NULL
},
113 #define SM_SASL_N_CB_PASS 1
114 { SASL_CB_AUTHNAME
, (sasl_callback_ft
) sm_get_user
, NULL
},
115 #define SM_SASL_N_CB_AUTHNAME 2
116 { SASL_CB_LIST_END
, NULL
, NULL
},
119 #else /* CYRUS_SASL */
121 #endif /* CYRUS_SASL */
124 static SSL_CTX
*sslctx
= NULL
;
125 static SSL
*ssl
= NULL
;
126 static BIO
*sbior
= NULL
;
127 static BIO
*sbiow
= NULL
;
128 static BIO
*io
= NULL
;
130 static int tls_negotiate(void);
131 #endif /* TLS_SUPPORT */
133 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
134 #define SASL_MAXRECVBUF 65536
135 static int sm_fgetc(FILE *);
136 static char *sasl_inbuffer
; /* SASL input buffer for encryption */
137 static char *sasl_inptr
; /* Pointer to current inbuf position */
138 static int sasl_inbuflen
; /* Current length of data in inbuf */
140 #define sm_fgetc fgetc
143 static int tls_active
= 0;
145 static char *sm_noreply
= "No reply text given";
146 static char *sm_moreply
= "; ";
148 struct smtp sm_reply
; /* global... */
152 static int doingEHLO
;
153 char *EHLOkeys
[MAXEHLO
+ 1];
158 static int smtp_init (char *, char *, char *, int, int, int, int, int, int,
159 char *, char *, int);
160 static int sendmail_init (char *, char *, int, int, int, int, int, int,
163 static int rclient (char *, char *);
164 static int sm_ierror (char *fmt
, ...);
165 static int smtalk (int time
, char *fmt
, ...);
166 static int sm_wrecord (char *, int);
167 static int sm_wstream (char *, int);
168 static int sm_werror (void);
169 static int smhear (void);
170 static int sm_rrecord (char *, int *);
171 static int sm_rerror (int);
172 static void alrmser (int);
173 static char *EHLOset (char *);
174 static int sm_fwrite(char *, int);
175 static int sm_fputs(char *);
176 static int sm_fputc(int);
177 static void sm_fflush(void);
178 static int sm_fgets(char *, int, FILE *);
182 * Function prototypes needed for SASL
185 static int sm_auth_sasl(char *, int, char *, char *);
186 #endif /* CYRUS_SASL */
189 sm_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
190 int debug
, int queued
, int sasl
, int saslssf
,
191 char *saslmech
, char *user
, int tls
)
193 if (sm_mts
== MTS_SMTP
)
194 return smtp_init (client
, server
, port
, watch
, verbose
,
195 debug
, queued
, sasl
, saslssf
, saslmech
,
198 return sendmail_init (client
, server
, watch
, verbose
,
199 debug
, queued
, sasl
, saslssf
, saslmech
,
204 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
205 int debug
, int queued
,
206 int sasl
, int saslssf
, char *saslmech
, char *user
, int tls
)
208 int result
, sd1
, sd2
;
211 #else /* CYRUS_SASL */
213 NMH_UNUSED (saslssf
);
214 NMH_UNUSED (saslmech
);
216 #endif /* CYRUS_SASL */
221 sm_verbose
= verbose
;
224 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
227 if (client
== NULL
|| *client
== '\0') {
231 client
= LocalName(1); /* no clientname -> LocalName */
236 * Last-ditch check just in case client still isn't set to anything
239 if (client
== NULL
|| *client
== '\0')
240 client
= "localhost";
242 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
243 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
245 return sm_ierror("Unable to allocate %d bytes for read buffer",
247 #endif /* CYRUS_SASL || TLS_SUPPORT */
249 if ((sd1
= rclient (server
, port
)) == NOTOK
)
252 if ((sd2
= dup (sd1
)) == NOTOK
) {
254 return sm_ierror ("unable to dup");
257 SIGNAL (SIGALRM
, alrmser
);
258 SIGNAL (SIGPIPE
, SIG_IGN
);
260 if ((sm_rfp
= fdopen (sd1
, "r")) == NULL
261 || (sm_wfp
= fdopen (sd2
, "w")) == NULL
) {
264 sm_rfp
= sm_wfp
= NULL
;
265 return sm_ierror ("unable to fdopen");
272 * If tls == 2, that means that the user requested "initial" TLS,
273 * which happens right after the connection has opened. Do that
278 result
= tls_negotiate();
281 * Note: if tls_negotiate() fails it will call sm_end() for us,
282 * which closes the connection.
287 #endif /* TLS_SUPPORT */
304 * Give EHLO or HELO command
308 result
= smtalk (SM_HELO
, "EHLO %s", client
);
311 if (result
>= 500 && result
<= 599)
312 result
= smtalk (SM_HELO
, "HELO %s", client
);
321 * If the user requested TLS support, then try to do the STARTTLS command
322 * as part of the initial dialog. Assuming this works, we then need to
323 * restart the EHLO dialog after TLS negotiation is complete.
327 if (! EHLOset("STARTTLS")) {
329 return sm_ierror("SMTP server does not support TLS");
332 result
= smtalk(SM_HELO
, "STARTTLS");
340 * Okay, the other side should be waiting for us to start TLS
341 * negotiation. Oblige them.
344 result
= tls_negotiate();
350 result
= smtalk (SM_HELO
, "EHLO %s", client
);
358 #else /* TLS_SUPPORT */
360 #endif /* TLS_SUPPORT */
364 * If the user asked for SASL, then check to see if the SMTP server
365 * supports it. Otherwise, error out (because the SMTP server
366 * might have been spoofed; we don't want to just silently not
371 if (! (server_mechs
= EHLOset("AUTH"))) {
373 return sm_ierror("SMTP server does not support SASL");
376 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
378 return sm_ierror("Requested SASL mech \"%s\" is not in the "
379 "list of supported mechanisms:\n%s",
380 saslmech
, server_mechs
);
383 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
389 #endif /* CYRUS_SASL */
392 if (watch
&& EHLOset ("XVRB"))
393 smtalk (SM_HELO
, "VERB on");
394 if (queued
&& EHLOset ("XQUE"))
395 smtalk (SM_HELO
, "QUED");
401 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
402 int debug
, int queued
,
403 int sasl
, int saslssf
, char *saslmech
, char *user
)
405 unsigned int i
, result
, vecp
;
410 #else /* CYRUS_SASL */
413 NMH_UNUSED (saslssf
);
414 NMH_UNUSED (saslmech
);
416 #endif /* CYRUS_SASL */
421 sm_verbose
= verbose
;
423 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
426 if (client
== NULL
|| *client
== '\0') {
430 client
= LocalName(1); /* no clientname -> LocalName */
434 * Last-ditch check just in case client still isn't set to anything
437 if (client
== NULL
|| *client
== '\0')
438 client
= "localhost";
440 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
441 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
443 return sm_ierror("Unable to allocate %d bytes for read buffer",
445 #endif /* CYRUS_SASL || TLS_SUPPORT */
447 if (pipe (pdi
) == NOTOK
)
448 return sm_ierror ("no pipes");
449 if (pipe (pdo
) == NOTOK
) {
452 return sm_ierror ("no pipes");
455 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
464 return sm_ierror ("unable to fork");
467 if (pdo
[0] != fileno (stdin
))
468 dup2 (pdo
[0], fileno (stdin
));
469 if (pdi
[1] != fileno (stdout
))
470 dup2 (pdi
[1], fileno (stdout
));
471 if (pdi
[1] != fileno (stderr
))
472 dup2 (pdi
[1], fileno (stderr
));
473 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
477 vec
[vecp
++] = r1bindex (sendmail
, '/');
479 vec
[vecp
++] = watch
? "-odi" : queued
? "-odq" : "-odb";
480 vec
[vecp
++] = "-oem";
488 execvp (sendmail
, vec
);
489 fprintf (stderr
, "unable to exec ");
491 _exit (-1); /* NOTREACHED */
494 SIGNAL (SIGALRM
, alrmser
);
495 SIGNAL (SIGPIPE
, SIG_IGN
);
499 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
500 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
503 sm_rfp
= sm_wfp
= NULL
;
504 return sm_ierror ("unable to fdopen");
520 result
= smtalk (SM_HELO
, "EHLO %s", client
);
523 if (500 <= result
&& result
<= 599)
524 result
= smtalk (SM_HELO
, "HELO %s", client
);
537 * If the user asked for SASL, then check to see if the SMTP server
538 * supports it. Otherwise, error out (because the SMTP server
539 * might have been spoofed; we don't want to just silently not
544 if (! (server_mechs
= EHLOset("AUTH"))) {
546 return sm_ierror("SMTP server does not support SASL");
549 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
551 return sm_ierror("Requested SASL mech \"%s\" is not in the "
552 "list of supported mechanisms:\n%s",
553 saslmech
, server_mechs
);
556 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
562 #endif /* CYRUS_SASL */
565 smtalk (SM_HELO
, "VERB on");
572 rclient (char *server
, char *service
)
575 char response
[BUFSIZ
];
577 if ((sd
= client (server
, service
, response
, sizeof(response
),
581 sm_ierror ("%s", response
);
586 sm_winit (char *from
)
588 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
605 sm_wadr (char *mbox
, char *host
, char *path
)
607 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
609 path
? path
: "", mbox
, host
)) {
619 #endif /* SENDMAILBUG */
644 switch (smtalk (SM_DATA
, "DATA")) {
653 #endif /* SENDMAILBUG */
670 sm_wtxt (char *buffer
, int len
)
676 result
= sm_wstream (buffer
, len
);
679 return (result
== NOTOK
? RP_BHST
: RP_OK
);
686 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
689 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
697 #endif /* SENDMAILBUG */
715 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
726 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
731 smtalk (SM_QUIT
, "QUIT");
735 sm_note
.code
= sm_reply
.code
;
736 sm_note
.length
= sm_reply
.length
;
737 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
739 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
741 if (sm_mts
== MTS_SMTP
)
742 smtalk (SM_QUIT
, "QUIT");
744 /* The SIGPIPE block replaces old calls to discard ().
745 We're not sure what the discard () calls were for,
746 maybe to prevent deadlock on old systems. In any
747 case, blocking SIGPIPE should be harmless.
748 Because the file handles are closed below, leave it
752 sigaddset (&set
, SIGPIPE
);
753 sigprocmask (SIG_BLOCK
, &set
, &oset
);
755 kill (sm_child
, SIGKILL
);
759 sm_reply
.code
= sm_note
.code
;
760 sm_reply
.length
= sm_note
.length
;
761 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
768 BIO_ssl_shutdown(io
);
771 #endif /* TLS_SUPPORT */
773 if (sm_rfp
!= NULL
) {
778 if (sm_wfp
!= NULL
) {
784 if (sm_mts
== MTS_SMTP
) {
789 if (sasl_outbuffer
) {
790 free(sasl_outbuffer
);
795 #endif /* CYRUS_SASL */
796 } else if (sm_child
!= NOTOK
) {
797 status
= pidwait (sm_child
, OK
);
803 sm_rfp
= sm_wfp
= NULL
;
804 return (status
? RP_BHST
: RP_OK
);
809 * This function implements SASL authentication for SMTP. If this function
810 * completes successfully, then authentication is successful and we've
811 * (optionally) negotiated a security layer.
814 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
817 unsigned int buflen
, outlen
;
818 char *buf
, outbuf
[BUFSIZ
], host
[NI_MAXHOST
];
819 const char *chosen_mech
;
820 sasl_security_properties_t secprops
;
825 * Initialize the callback contexts
829 user
= getusername();
831 callbacks
[SM_SASL_N_CB_USER
].context
= user
;
832 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= user
;
835 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
836 * to us on the command line, then call getpeername and do a
837 * reverse-address lookup on the IP address to get the name.
840 memset(host
, 0, sizeof(host
));
843 struct sockaddr_storage sin
;
844 socklen_t len
= sizeof(sin
);
847 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
848 sm_ierror("getpeername on SMTP socket failed: %s",
853 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
854 NULL
, 0, NI_NAMEREQD
);
856 sm_ierror("Unable to look up name of connected host: %s",
857 gai_strerror(result
));
861 strncpy(host
, inhost
, sizeof(host
) - 1);
864 sasl_pw_context
[0] = host
;
865 sasl_pw_context
[1] = user
;
867 callbacks
[SM_SASL_N_CB_PASS
].context
= sasl_pw_context
;
869 result
= sasl_client_init(callbacks
);
871 if (result
!= SASL_OK
) {
872 sm_ierror("SASL library initialization failed: %s",
873 sasl_errstring(result
, NULL
, NULL
));
877 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
879 if (result
!= SASL_OK
) {
880 sm_ierror("SASL client initialization failed: %s",
881 sasl_errstring(result
, NULL
, NULL
));
886 * Initialize the security properties. But if TLS is active, then
887 * don't negotiate encryption here.
890 memset(&secprops
, 0, sizeof(secprops
));
891 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
893 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
895 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
897 if (result
!= SASL_OK
) {
898 sm_ierror("SASL security property initialization failed: %s",
899 sasl_errstring(result
, NULL
, NULL
));
904 * Start the actual protocol. Feed the mech list into the library
905 * and get out a possible initial challenge
908 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
909 &buflen
, (const char **) &chosen_mech
);
911 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
912 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
917 * If we got an initial challenge, send it as part of the AUTH
918 * command; otherwise, just send a plain AUTH command.
922 status
= sasl_encode64(buf
, buflen
, outbuf
, sizeof(outbuf
), NULL
);
923 if (status
!= SASL_OK
) {
924 sm_ierror("SASL base64 encode failed: %s",
925 sasl_errstring(status
, NULL
, NULL
));
929 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
931 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
934 * Now we loop until we either fail, get a SASL_OK, or a 235
935 * response code. Receive the challenges and process them until
939 while (result
== SASL_CONTINUE
) {
942 * If we get a 235 response, that means authentication has
943 * succeeded and we need to break out of the loop (yes, even if
944 * we still get SASL_CONTINUE from sasl_client_step()).
946 * Otherwise, if we get a message that doesn't seem to be a
947 * valid response, then abort
952 else if (status
< 300 || status
> 399)
956 * Special case; a zero-length response from the SMTP server
957 * is returned as a single =. If we get that, then set buflen
958 * to be zero. Otherwise, just decode the response.
961 if (strcmp("=", sm_reply
.text
) == 0) {
964 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
965 outbuf
, sizeof(outbuf
), &outlen
);
967 if (result
!= SASL_OK
) {
968 smtalk(SM_AUTH
, "*");
969 sm_ierror("SASL base64 decode failed: %s",
970 sasl_errstring(result
, NULL
, NULL
));
975 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
976 (const char **) &buf
, &buflen
);
978 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
979 smtalk(SM_AUTH
, "*");
980 sm_ierror("SASL client negotiation failed: %s",
981 sasl_errstring(result
, NULL
, NULL
));
985 status
= sasl_encode64(buf
, buflen
, outbuf
, sizeof(outbuf
), NULL
);
987 if (status
!= SASL_OK
) {
988 smtalk(SM_AUTH
, "*");
989 sm_ierror("SASL base64 encode failed: %s",
990 sasl_errstring(status
, NULL
, NULL
));
994 status
= smtalk(SM_AUTH
, outbuf
);
998 * Make sure that we got the correct response
1001 if (status
< 200 || status
> 299)
1005 * We _should_ have completed the authentication successfully.
1006 * Get a few properties from the authentication exchange.
1009 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
1011 if (result
!= SASL_OK
) {
1012 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1013 sasl_errstring(result
, NULL
, NULL
));
1017 maxoutbuf
= *outbufmax
;
1019 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
1023 if (result
!= SASL_OK
) {
1024 sm_ierror("Cannot retrieve SASL negotiated security strength "
1025 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
1030 sasl_outbuffer
= malloc(maxoutbuf
);
1032 if (sasl_outbuffer
== NULL
) {
1033 sm_ierror("Unable to allocate %d bytes for SASL output "
1034 "buffer", maxoutbuf
);
1039 sasl_inptr
= sasl_inbuffer
;
1041 sasl_outbuffer
= NULL
;
1042 /* Don't NULL out sasl_inbuffer because it could be used in
1052 * Our callback functions to feed data to the SASL library
1056 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1058 char *user
= (char *) context
;
1060 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1061 return SASL_BADPARAM
;
1065 *len
= strlen(user
);
1071 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1072 sasl_secret_t
**psecret
)
1074 char **pw_context
= (char **) context
;
1080 if (! psecret
|| id
!= SASL_CB_PASS
)
1081 return SASL_BADPARAM
;
1083 ruserpass(pw_context
[0], &(pw_context
[1]), &pass
);
1087 *psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
);
1094 (*psecret
)->len
= len
;
1095 strcpy((char *) (*psecret
)->data
, pass
);
1100 #endif /* CYRUS_SASL */
1103 sm_ierror (char *fmt
, ...)
1108 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1111 sm_reply
.length
= strlen (sm_reply
.text
);
1112 sm_reply
.code
= NOTOK
;
1118 smtalk (int time
, char *fmt
, ...)
1122 char buffer
[BUFSIZ
];
1125 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
1130 printf("(sasl-encrypted) ");
1132 printf("(tls-encrypted) ");
1133 printf ("=> %s\n", buffer
);
1138 alarm ((unsigned) time
);
1139 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
1148 * write the buffer to the open SMTP channel
1152 sm_wrecord (char *buffer
, int len
)
1155 return sm_werror ();
1157 sm_fwrite (buffer
, len
);
1161 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1166 sm_wstream (char *buffer
, int len
)
1169 static char lc
= '\0';
1172 return sm_werror ();
1174 if (buffer
== NULL
&& len
== 0) {
1178 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1181 for (bp
= buffer
; len
> 0; bp
++, len
--) {
1190 sm_fputc ('.');/* FALL THROUGH */
1195 if (ferror (sm_wfp
))
1196 return sm_werror ();
1201 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1205 * Write out to the network, but do buffering for SASL (if enabled)
1209 sm_fwrite(char *buffer
, int len
)
1213 unsigned int outputlen
;
1215 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1216 #endif /* CYRUS_SASL */
1221 ret
= BIO_write(io
, buffer
, len
);
1224 sm_ierror("TLS error during write: %s",
1225 ERR_error_string(ERR_get_error(), NULL
));
1229 #endif /* TLS_SUPPORT */
1230 fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
);
1233 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1234 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1235 maxoutbuf
- sasl_outbuflen
);
1236 len
-= maxoutbuf
- sasl_outbuflen
;
1239 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1240 &output
, &outputlen
) != SASL_OK
) {
1241 sm_ierror("Unable to SASL encode connection data: %s",
1242 sasl_errdetail(conn
));
1246 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1250 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1251 sasl_outbuflen
+= len
;
1254 #endif /* CYRUS_SASL */
1255 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1260 * Negotiate Transport Layer Security
1269 const SSL_METHOD
*method
;
1272 SSL_load_error_strings();
1274 method
= TLSv1_client_method(); /* Not sure about this */
1276 sslctx
= SSL_CTX_new(method
);
1280 return sm_ierror("Unable to initialize OpenSSL context: %s",
1281 ERR_error_string(ERR_get_error(), NULL
));
1285 ssl
= SSL_new(sslctx
);
1289 return sm_ierror("Unable to create SSL connection: %s",
1290 ERR_error_string(ERR_get_error(), NULL
));
1293 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
1294 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
1296 if (sbior
== NULL
|| sbiow
== NULL
) {
1298 return sm_ierror("Unable to create BIO endpoints: %s",
1299 ERR_error_string(ERR_get_error(), NULL
));
1302 SSL_set_bio(ssl
, sbior
, sbiow
);
1303 SSL_set_connect_state(ssl
);
1306 * Set up a BIO to handle buffering for us
1309 io
= BIO_new(BIO_f_buffer());
1313 return sm_ierror("Unable to create a buffer BIO: %s",
1314 ERR_error_string(ERR_get_error(), NULL
));
1317 ssl_bio
= BIO_new(BIO_f_ssl());
1321 return sm_ierror("Unable to create a SSL BIO: %s",
1322 ERR_error_string(ERR_get_error(), NULL
));
1325 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1326 BIO_push(io
, ssl_bio
);
1329 * Try doing the handshake now
1332 if (BIO_do_handshake(io
) < 1) {
1334 return sm_ierror("Unable to negotiate SSL connection: %s",
1335 ERR_error_string(ERR_get_error(), NULL
));
1339 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1340 printf("SSL negotiation successful: %s(%d) %s\n",
1341 SSL_CIPHER_get_name(cipher
),
1342 SSL_CIPHER_get_bits(cipher
, NULL
),
1343 SSL_CIPHER_get_version(cipher
));
1351 #endif /* TLS_SUPPORT */
1354 * Convenience functions to replace occurences of fputs() and fputc()
1358 sm_fputs(char *buffer
)
1360 return sm_fwrite(buffer
, strlen(buffer
));
1368 return sm_fwrite(&h
, 1);
1372 * Flush out any pending data on the connection
1380 unsigned int outputlen
;
1383 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1384 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1385 &output
, &outputlen
);
1386 if (result
!= SASL_OK
) {
1387 sm_ierror("Unable to SASL encode connection data: %s",
1388 sasl_errdetail(conn
));
1392 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1395 #endif /* CYRUS_SASL */
1399 (void) BIO_flush(io
);
1401 #endif /* TLS_SUPPORT */
1410 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1411 : sm_alarmed
? "write to socket timed out"
1412 : "error writing to socket"));
1414 return (sm_reply
.code
= NOTOK
);
1421 int i
, code
, cont
, bc
= 0, rc
, more
;
1424 char **ehlo
= NULL
, buffer
[BUFSIZ
];
1427 static int at_least_once
= 0;
1429 if (at_least_once
) {
1432 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1446 sm_reply
.length
= 0;
1447 sm_reply
.text
[0] = 0;
1449 rc
= sizeof(sm_reply
.text
) - 1;
1451 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1455 printf("(sasl-decrypted) ");
1457 printf("(tls-decrypted) ");
1458 printf ("<= %s\n", buffer
);
1463 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1464 && (buffer
[3] == '-' || doingEHLO
== 2)
1466 if (doingEHLO
== 2) {
1467 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1468 strcpy (*ehlo
++, buffer
+ 4);
1470 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1480 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1484 code
= atoi ((char *) bp
);
1486 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1488 if (bc
> 0 && *bp
== '-') {
1491 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1496 if (code
!= sm_reply
.code
|| cont
)
1500 sm_reply
.code
= code
;
1503 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1504 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1505 bp
= (unsigned char *) buffer
;
1506 bc
= strlen (sm_noreply
);
1510 if ((i
= min (bc
, rc
)) > 0) {
1514 i
= strlen(sm_moreply
);
1515 if (more
&& rc
> i
+ 1) {
1516 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1523 if (sm_reply
.code
< 100) {
1525 printf ("%s\n", sm_reply
.text
);
1531 sm_reply
.length
= rp
- sm_reply
.text
;
1532 sm_reply
.text
[sm_reply
.length
] = 0;
1533 return sm_reply
.code
;
1540 sm_rrecord (char *buffer
, int *len
)
1545 return sm_rerror(0);
1547 buffer
[*len
= 0] = 0;
1549 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1550 return sm_rerror (retval
);
1551 *len
= strlen (buffer
);
1552 /* *len should be >0 except on EOF, but check for safety's sake */
1554 return sm_rerror (RP_EOF
);
1555 if (buffer
[*len
- 1] != '\n')
1556 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1560 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1569 * Our version of fgets, which calls our private fgetc function
1573 sm_fgets(char *buffer
, int size
, FILE *f
)
1587 } while (size
> 1 && c
!= '\n');
1595 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1597 * Read from the network, but do SASL or TLS encryption
1603 char tmpbuf
[BUFSIZ
], *retbuf
;
1604 unsigned int retbufsize
= 0;
1608 * If we have leftover data, return it
1611 if (sasl_inbuflen
) {
1613 return (int) *sasl_inptr
++;
1617 * If not, read from the network until we have some data to return
1620 while (retbufsize
== 0) {
1624 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1627 result
= SSL_get_error(ssl
, cc
);
1629 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1630 sm_ierror("TLS peer aborted connection");
1637 sm_ierror("SSL_read failed: %s",
1638 ERR_error_string(ERR_get_error(), NULL
));
1642 #endif /* TLS_SUPPORT */
1644 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1650 sm_ierror("Unable to read from network: %s", strerror(errno
));
1655 * Don't call sasl_decode unless sasl is complete and we have
1656 * encryption working
1660 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1664 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1667 if (result
!= SASL_OK
) {
1668 sm_ierror("Unable to decode SASL network data: %s",
1669 sasl_errdetail(conn
));
1673 #else /* ! CYRUS_SASL */
1676 #endif /* CYRUS_SASL */
1679 if (retbufsize
> SASL_MAXRECVBUF
) {
1680 sm_ierror("Received data (%d bytes) is larger than the buffer "
1681 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1685 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1686 sasl_inptr
= sasl_inbuffer
+ 1;
1687 sasl_inbuflen
= retbufsize
- 1;
1689 return (int) sasl_inbuffer
[0];
1691 #endif /* CYRUS_SASL || TLS_SUPPORT */
1696 if (sm_mts
== MTS_SMTP
)
1698 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1699 : sm_alarmed
? "read from socket timed out"
1700 : rc
== RP_EOF
? "premature end-of-file on socket"
1701 : "error reading from socket"));
1704 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1705 : sm_alarmed
? "read from pipe timed out"
1706 : rc
== RP_EOF
? "premature end-of-file on pipe"
1707 : "error reading from pipe"));
1709 return (sm_reply
.code
= NOTOK
);
1718 #ifndef RELIABLE_SIGNALS
1719 SIGNAL (SIGALRM
, alrmser
);
1724 printf ("timed out...\n");
1731 rp_string (int code
)
1734 static char buffer
[BUFSIZ
];
1736 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1756 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1776 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1777 text
, sm_reply
.code
, sm_reply
.text
);
1789 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1791 if (strncmp (ep
, s
, len
) == 0) {
1792 for (ep
+= len
; *ep
== ' '; ep
++)