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>
15 #include <sasl/sasl.h>
16 #include <sasl/saslutil.h>
17 # if SASL_VERSION_FULL < 0x020125
18 /* Cyrus SASL 2.1.25 introduced the sasl_callback_ft prototype,
19 which has an explicit void parameter list, according to best
20 practice. So we need to cast to avoid compile warnings.
21 Provide this prototype for earlier versions. */
22 typedef int (*sasl_callback_ft
)();
23 # endif /* SASL_VERSION_FULL < 0x020125 */
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
28 #endif /* CYRUS_SASL */
31 #include <openssl/ssl.h>
32 #include <openssl/err.h>
33 #endif /* TLS_SUPPORT */
36 * This module implements an interface to SendMail very similar
37 * to the MMDF mm_(3) routines. The sm_() routines herein talk
38 * SMTP to a sendmail process, mapping SMTP reply codes into
43 * On older 4.2BSD machines without the POSIX function `sigaction',
44 * the alarm handing stuff for time-outs will NOT work due to the way
45 * syscalls get restarted. This is not really crucial, since SendMail
46 * is generally well-behaved in this area.
51 * It appears that some versions of Sendmail will return Code 451
52 * when they don't really want to indicate a failure.
53 * "Code 451 almost always means sendmail has deferred; we don't
54 * really want bomb out at this point since sendmail will rectify
55 * things later." So, if you define SENDMAILBUG, Code 451 is
56 * considered the same as Code 250. Yuck!
63 #define NBITS ((sizeof (int)) * 8)
66 * these codes must all be different!
68 #define SM_OPEN 300 /* Changed to 5 minutes to comply with a SHOULD in RFC 1123 */
71 #define SM_MAIL 301 /* changed to 5 minutes and a second (for uniqueness), see above */
72 #define SM_RCPT 302 /* see above */
73 #define SM_DATA 120 /* see above */
74 #define SM_TEXT 180 /* see above */
75 #define SM_DOT 600 /* see above */
80 #endif /* CYRUS_SASL */
82 static int sm_addrs
= 0;
83 static int sm_alarmed
= 0;
84 static int sm_child
= NOTOK
;
85 static int sm_debug
= 0;
86 static int sm_nl
= TRUE
;
87 static int sm_verbose
= 0;
89 static FILE *sm_rfp
= NULL
;
90 static FILE *sm_wfp
= NULL
;
94 * Some globals needed by SASL
97 static sasl_conn_t
*conn
= NULL
; /* SASL connection state */
98 static int sasl_complete
= 0; /* Has authentication succeded? */
99 static sasl_ssf_t sasl_ssf
; /* Our security strength factor */
100 static char *sasl_pw_context
[3]; /* Context to pass into sm_get_pass */
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
= "; ";
146 struct smtp sm_reply
; /* global... */
150 static int doingEHLO
;
151 char *EHLOkeys
[MAXEHLO
+ 1];
156 static int smtp_init (char *, char *, char *, int, int, int, int, int, int,
157 char *, char *, int);
158 static int sendmail_init (char *, char *, int, int, int, int, int, int,
161 static int rclient (char *, char *);
162 static int sm_ierror (char *fmt
, ...);
163 static int smtalk (int time
, char *fmt
, ...);
164 static int sm_wrecord (char *, int);
165 static int sm_wstream (char *, int);
166 static int sm_werror (void);
167 static int smhear (void);
168 static int sm_rrecord (char *, int *);
169 static int sm_rerror (int);
170 static void alrmser (int);
171 static char *EHLOset (char *);
172 static int sm_fwrite(char *, int);
173 static int sm_fputs(char *);
174 static int sm_fputc(int);
175 static void sm_fflush(void);
176 static int sm_fgets(char *, int, FILE *);
180 * Function prototypes needed for SASL
183 static int sm_auth_sasl(char *, int, char *, char *);
184 #endif /* CYRUS_SASL */
187 sm_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
188 int debug
, int queued
, int sasl
, int saslssf
,
189 char *saslmech
, char *user
, int tls
)
191 if (sm_mts
== MTS_SMTP
)
192 return smtp_init (client
, server
, port
, watch
, verbose
,
193 debug
, queued
, sasl
, saslssf
, saslmech
,
196 return sendmail_init (client
, server
, watch
, verbose
,
197 debug
, queued
, sasl
, saslssf
, saslmech
,
202 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
203 int debug
, int queued
,
204 int sasl
, int saslssf
, char *saslmech
, char *user
, int tls
)
206 int result
, sd1
, sd2
;
209 #else /* CYRUS_SASL */
211 NMH_UNUSED (saslssf
);
212 NMH_UNUSED (saslmech
);
214 #endif /* CYRUS_SASL */
219 sm_verbose
= verbose
;
222 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
225 if (client
== NULL
|| *client
== '\0') {
229 client
= LocalName(1); /* no clientname -> LocalName */
234 * Last-ditch check just in case client still isn't set to anything
237 if (client
== NULL
|| *client
== '\0')
238 client
= "localhost";
240 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
241 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
243 return sm_ierror("Unable to allocate %d bytes for read buffer",
245 #endif /* CYRUS_SASL || TLS_SUPPORT */
247 if ((sd1
= rclient (server
, port
)) == NOTOK
)
250 if ((sd2
= dup (sd1
)) == NOTOK
) {
252 return sm_ierror ("unable to dup");
255 SIGNAL (SIGALRM
, alrmser
);
256 SIGNAL (SIGPIPE
, SIG_IGN
);
258 if ((sm_rfp
= fdopen (sd1
, "r")) == NULL
259 || (sm_wfp
= fdopen (sd2
, "w")) == NULL
) {
262 sm_rfp
= sm_wfp
= NULL
;
263 return sm_ierror ("unable to fdopen");
270 * If tls == 2, that means that the user requested "initial" TLS,
271 * which happens right after the connection has opened. Do that
276 result
= tls_negotiate();
279 * Note: if tls_negotiate() fails it will call sm_end() for us,
280 * which closes the connection.
285 #endif /* TLS_SUPPORT */
302 * Give EHLO or HELO command
306 result
= smtalk (SM_HELO
, "EHLO %s", client
);
309 if (result
>= 500 && result
<= 599)
310 result
= smtalk (SM_HELO
, "HELO %s", client
);
319 * If the user requested TLS support, then try to do the STARTTLS command
320 * as part of the initial dialog. Assuming this works, we then need to
321 * restart the EHLO dialog after TLS negotiation is complete.
325 if (! EHLOset("STARTTLS")) {
327 return sm_ierror("SMTP server does not support TLS");
330 result
= smtalk(SM_HELO
, "STARTTLS");
338 * Okay, the other side should be waiting for us to start TLS
339 * negotiation. Oblige them.
342 result
= tls_negotiate();
348 result
= smtalk (SM_HELO
, "EHLO %s", client
);
356 #else /* TLS_SUPPORT */
358 #endif /* TLS_SUPPORT */
362 * If the user asked for SASL, then check to see if the SMTP server
363 * supports it. Otherwise, error out (because the SMTP server
364 * might have been spoofed; we don't want to just silently not
369 if (! (server_mechs
= EHLOset("AUTH"))) {
371 return sm_ierror("SMTP server does not support SASL");
374 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
376 return sm_ierror("Requested SASL mech \"%s\" is not in the "
377 "list of supported mechanisms:\n%s",
378 saslmech
, server_mechs
);
381 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
387 #endif /* CYRUS_SASL */
390 if (watch
&& EHLOset ("XVRB"))
391 smtalk (SM_HELO
, "VERB on");
392 if (queued
&& EHLOset ("XQUE"))
393 smtalk (SM_HELO
, "QUED");
399 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
400 int debug
, int queued
,
401 int sasl
, int saslssf
, char *saslmech
, char *user
)
403 unsigned int i
, result
, vecp
;
408 #else /* CYRUS_SASL */
411 NMH_UNUSED (saslssf
);
412 NMH_UNUSED (saslmech
);
414 #endif /* CYRUS_SASL */
419 sm_verbose
= verbose
;
421 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
424 if (client
== NULL
|| *client
== '\0') {
428 client
= LocalName(1); /* no clientname -> LocalName */
432 * Last-ditch check just in case client still isn't set to anything
435 if (client
== NULL
|| *client
== '\0')
436 client
= "localhost";
438 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
439 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
441 return sm_ierror("Unable to allocate %d bytes for read buffer",
443 #endif /* CYRUS_SASL || TLS_SUPPORT */
445 if (pipe (pdi
) == NOTOK
)
446 return sm_ierror ("no pipes");
447 if (pipe (pdo
) == NOTOK
) {
450 return sm_ierror ("no pipes");
453 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
462 return sm_ierror ("unable to fork");
465 if (pdo
[0] != fileno (stdin
))
466 dup2 (pdo
[0], fileno (stdin
));
467 if (pdi
[1] != fileno (stdout
))
468 dup2 (pdi
[1], fileno (stdout
));
469 if (pdi
[1] != fileno (stderr
))
470 dup2 (pdi
[1], fileno (stderr
));
471 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
475 vec
[vecp
++] = r1bindex (sendmail
, '/');
477 vec
[vecp
++] = watch
? "-odi" : queued
? "-odq" : "-odb";
478 vec
[vecp
++] = "-oem";
484 execvp (sendmail
, vec
);
485 fprintf (stderr
, "unable to exec ");
487 _exit (-1); /* NOTREACHED */
490 SIGNAL (SIGALRM
, alrmser
);
491 SIGNAL (SIGPIPE
, SIG_IGN
);
495 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
496 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
499 sm_rfp
= sm_wfp
= NULL
;
500 return sm_ierror ("unable to fdopen");
516 result
= smtalk (SM_HELO
, "EHLO %s", client
);
519 if (500 <= result
&& result
<= 599)
520 result
= smtalk (SM_HELO
, "HELO %s", client
);
533 * If the user asked for SASL, then check to see if the SMTP server
534 * supports it. Otherwise, error out (because the SMTP server
535 * might have been spoofed; we don't want to just silently not
540 if (! (server_mechs
= EHLOset("AUTH"))) {
542 return sm_ierror("SMTP server does not support SASL");
545 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
547 return sm_ierror("Requested SASL mech \"%s\" is not in the "
548 "list of supported mechanisms:\n%s",
549 saslmech
, server_mechs
);
552 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
558 #endif /* CYRUS_SASL */
561 smtalk (SM_HELO
, "VERB on");
568 rclient (char *server
, char *service
)
571 char response
[BUFSIZ
];
573 if ((sd
= client (server
, service
, response
, sizeof(response
),
577 sm_ierror ("%s", response
);
582 sm_winit (char *from
)
584 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
601 sm_wadr (char *mbox
, char *host
, char *path
)
603 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
605 path
? path
: "", mbox
, host
)) {
615 #endif /* SENDMAILBUG */
640 switch (smtalk (SM_DATA
, "DATA")) {
649 #endif /* SENDMAILBUG */
666 sm_wtxt (char *buffer
, int len
)
672 result
= sm_wstream (buffer
, len
);
675 return (result
== NOTOK
? RP_BHST
: RP_OK
);
682 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
685 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
693 #endif /* SENDMAILBUG */
711 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
722 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
727 smtalk (SM_QUIT
, "QUIT");
731 sm_note
.code
= sm_reply
.code
;
732 sm_note
.length
= sm_reply
.length
;
733 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
735 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
737 if (sm_mts
== MTS_SMTP
)
738 smtalk (SM_QUIT
, "QUIT");
740 /* The SIGPIPE block replaces old calls to discard ().
741 We're not sure what the discard () calls were for,
742 maybe to prevent deadlock on old systems. In any
743 case, blocking SIGPIPE should be harmless.
744 Because the file handles are closed below, leave it
748 sigaddset (&set
, SIGPIPE
);
749 sigprocmask (SIG_BLOCK
, &set
, &oset
);
751 kill (sm_child
, SIGKILL
);
755 sm_reply
.code
= sm_note
.code
;
756 sm_reply
.length
= sm_note
.length
;
757 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
764 BIO_ssl_shutdown(io
);
767 #endif /* TLS_SUPPORT */
769 if (sm_rfp
!= NULL
) {
774 if (sm_wfp
!= NULL
) {
780 if (sm_mts
== MTS_SMTP
) {
785 if (sasl_outbuffer
) {
786 free(sasl_outbuffer
);
791 #endif /* CYRUS_SASL */
792 } else if (sm_child
!= NOTOK
) {
793 status
= pidwait (sm_child
, OK
);
799 sm_rfp
= sm_wfp
= NULL
;
800 return (status
? RP_BHST
: RP_OK
);
805 * This function implements SASL authentication for SMTP. If this function
806 * completes successfully, then authentication is successful and we've
807 * (optionally) negotiated a security layer.
810 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
813 unsigned int buflen
, outlen
;
814 char *buf
, outbuf
[BUFSIZ
], host
[NI_MAXHOST
];
815 const char *chosen_mech
;
816 sasl_security_properties_t secprops
;
819 struct nmh_creds creds
= { 0, 0, 0 };
822 * Initialize the callback contexts
826 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
827 * to us on the command line, then call getpeername and do a
828 * reverse-address lookup on the IP address to get the name.
831 memset(host
, 0, sizeof(host
));
834 struct sockaddr_storage sin
;
835 socklen_t len
= sizeof(sin
);
838 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
839 sm_ierror("getpeername on SMTP socket failed: %s",
844 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
845 NULL
, 0, NI_NAMEREQD
);
847 sm_ierror("Unable to look up name of connected host: %s",
848 gai_strerror(result
));
852 strncpy(host
, inhost
, sizeof(host
) - 1);
855 nmh_get_credentials (host
, user
, 0, &creds
);
857 /* It's OK to copy the creds pointers here. The callbacks that
858 use them will only be called before this function returns. */
859 callbacks
[SM_SASL_N_CB_USER
].context
= creds
.user
;
860 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= creds
.user
;
861 sasl_pw_context
[0] = host
;
862 sasl_pw_context
[1] = creds
.user
;
863 sasl_pw_context
[2] = creds
.password
;
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
);
964 if (result
!= SASL_OK
) {
965 smtalk(SM_AUTH
, "*");
966 sm_ierror("SASL base64 decode failed: %s",
967 sasl_errstring(result
, NULL
, NULL
));
972 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
973 (const char **) &buf
, &buflen
);
975 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
976 smtalk(SM_AUTH
, "*");
977 sm_ierror("SASL client negotiation failed: %s",
978 sasl_errstring(result
, NULL
, NULL
));
982 status
= sasl_encode64(buf
, buflen
, outbuf
, sizeof(outbuf
), NULL
);
984 if (status
!= SASL_OK
) {
985 smtalk(SM_AUTH
, "*");
986 sm_ierror("SASL base64 encode failed: %s",
987 sasl_errstring(status
, NULL
, NULL
));
991 status
= smtalk(SM_AUTH
, outbuf
);
995 * Make sure that we got the correct response
998 if (status
< 200 || status
> 299)
1002 * We _should_ have completed the authentication successfully.
1003 * Get a few properties from the authentication exchange.
1006 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
1008 if (result
!= SASL_OK
) {
1009 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1010 sasl_errstring(result
, NULL
, NULL
));
1014 maxoutbuf
= *outbufmax
;
1016 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
1020 if (result
!= SASL_OK
) {
1021 sm_ierror("Cannot retrieve SASL negotiated security strength "
1022 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
1027 sasl_outbuffer
= malloc(maxoutbuf
);
1029 if (sasl_outbuffer
== NULL
) {
1030 sm_ierror("Unable to allocate %d bytes for SASL output "
1031 "buffer", maxoutbuf
);
1036 sasl_inptr
= sasl_inbuffer
;
1038 sasl_outbuffer
= NULL
;
1039 /* Don't NULL out sasl_inbuffer because it could be used in
1049 * Our callback functions to feed data to the SASL library
1053 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1055 char *user
= (char *) context
;
1057 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1058 return SASL_BADPARAM
;
1062 *len
= strlen(user
);
1068 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1069 sasl_secret_t
**psecret
)
1071 char **pw_context
= (char **) context
;
1076 if (! psecret
|| id
!= SASL_CB_PASS
)
1077 return SASL_BADPARAM
;
1079 len
= strlen (pw_context
[2]);
1081 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1085 (*psecret
)->len
= len
;
1086 strcpy((char *) (*psecret
)->data
, pw_context
[2]);
1090 #endif /* CYRUS_SASL */
1093 sm_ierror (char *fmt
, ...)
1098 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1101 sm_reply
.length
= strlen (sm_reply
.text
);
1102 sm_reply
.code
= NOTOK
;
1108 smtalk (int time
, char *fmt
, ...)
1112 char buffer
[BUFSIZ
];
1115 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
1120 printf("(sasl-encrypted) ");
1122 printf("(tls-encrypted) ");
1123 printf ("=> %s\n", buffer
);
1128 alarm ((unsigned) time
);
1129 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
1138 * write the buffer to the open SMTP channel
1142 sm_wrecord (char *buffer
, int len
)
1145 return sm_werror ();
1147 sm_fwrite (buffer
, len
);
1151 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1156 sm_wstream (char *buffer
, int len
)
1159 static char lc
= '\0';
1162 return sm_werror ();
1164 if (buffer
== NULL
&& len
== 0) {
1168 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1171 for (bp
= buffer
; len
> 0; bp
++, len
--) {
1180 sm_fputc ('.');/* FALL THROUGH */
1185 if (ferror (sm_wfp
))
1186 return sm_werror ();
1191 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1195 * Write out to the network, but do buffering for SASL (if enabled)
1199 sm_fwrite(char *buffer
, int len
)
1203 unsigned int outputlen
;
1205 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1206 #endif /* CYRUS_SASL */
1211 ret
= BIO_write(io
, buffer
, len
);
1214 sm_ierror("TLS error during write: %s",
1215 ERR_error_string(ERR_get_error(), NULL
));
1219 #endif /* TLS_SUPPORT */
1220 fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
);
1223 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1224 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1225 maxoutbuf
- sasl_outbuflen
);
1226 len
-= maxoutbuf
- sasl_outbuflen
;
1229 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1230 &output
, &outputlen
) != SASL_OK
) {
1231 sm_ierror("Unable to SASL encode connection data: %s",
1232 sasl_errdetail(conn
));
1236 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1240 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1241 sasl_outbuflen
+= len
;
1244 #endif /* CYRUS_SASL */
1245 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1250 * Negotiate Transport Layer Security
1259 const SSL_METHOD
*method
;
1262 SSL_load_error_strings();
1264 method
= TLSv1_client_method(); /* Not sure about this */
1266 /* Older ssl takes a non-const arg. */
1267 sslctx
= SSL_CTX_new((SSL_METHOD
*) method
);
1271 return sm_ierror("Unable to initialize OpenSSL context: %s",
1272 ERR_error_string(ERR_get_error(), NULL
));
1276 ssl
= SSL_new(sslctx
);
1280 return sm_ierror("Unable to create SSL connection: %s",
1281 ERR_error_string(ERR_get_error(), NULL
));
1284 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
1285 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
1287 if (sbior
== NULL
|| sbiow
== NULL
) {
1289 return sm_ierror("Unable to create BIO endpoints: %s",
1290 ERR_error_string(ERR_get_error(), NULL
));
1293 SSL_set_bio(ssl
, sbior
, sbiow
);
1294 SSL_set_connect_state(ssl
);
1297 * Set up a BIO to handle buffering for us
1300 io
= BIO_new(BIO_f_buffer());
1304 return sm_ierror("Unable to create a buffer BIO: %s",
1305 ERR_error_string(ERR_get_error(), NULL
));
1308 ssl_bio
= BIO_new(BIO_f_ssl());
1312 return sm_ierror("Unable to create a SSL BIO: %s",
1313 ERR_error_string(ERR_get_error(), NULL
));
1316 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1317 BIO_push(io
, ssl_bio
);
1320 * Try doing the handshake now
1323 if (BIO_do_handshake(io
) < 1) {
1325 return sm_ierror("Unable to negotiate SSL connection: %s",
1326 ERR_error_string(ERR_get_error(), NULL
));
1330 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1331 printf("SSL negotiation successful: %s(%d) %s\n",
1332 SSL_CIPHER_get_name(cipher
),
1333 SSL_CIPHER_get_bits(cipher
, NULL
),
1334 SSL_CIPHER_get_version(cipher
));
1342 #endif /* TLS_SUPPORT */
1345 * Convenience functions to replace occurences of fputs() and fputc()
1349 sm_fputs(char *buffer
)
1351 return sm_fwrite(buffer
, strlen(buffer
));
1359 return sm_fwrite(&h
, 1);
1363 * Flush out any pending data on the connection
1371 unsigned int outputlen
;
1374 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1375 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1376 &output
, &outputlen
);
1377 if (result
!= SASL_OK
) {
1378 sm_ierror("Unable to SASL encode connection data: %s",
1379 sasl_errdetail(conn
));
1383 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1386 #endif /* CYRUS_SASL */
1390 (void) BIO_flush(io
);
1392 #endif /* TLS_SUPPORT */
1401 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1402 : sm_alarmed
? "write to socket timed out"
1403 : "error writing to socket"));
1405 return (sm_reply
.code
= NOTOK
);
1412 int i
, code
, cont
, bc
= 0, rc
, more
;
1415 char **ehlo
= NULL
, buffer
[BUFSIZ
];
1418 static int at_least_once
= 0;
1420 if (at_least_once
) {
1423 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1437 sm_reply
.length
= 0;
1438 sm_reply
.text
[0] = 0;
1440 rc
= sizeof(sm_reply
.text
) - 1;
1442 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1446 printf("(sasl-decrypted) ");
1448 printf("(tls-decrypted) ");
1449 printf ("<= %s\n", buffer
);
1454 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1455 && (buffer
[3] == '-' || doingEHLO
== 2)
1457 if (doingEHLO
== 2) {
1458 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1459 strcpy (*ehlo
++, buffer
+ 4);
1461 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1471 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1475 code
= atoi ((char *) bp
);
1477 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1479 if (bc
> 0 && *bp
== '-') {
1482 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1487 if (code
!= sm_reply
.code
|| cont
)
1491 sm_reply
.code
= code
;
1494 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1495 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1496 bp
= (unsigned char *) buffer
;
1497 bc
= strlen (sm_noreply
);
1501 if ((i
= min (bc
, rc
)) > 0) {
1505 i
= strlen(sm_moreply
);
1506 if (more
&& rc
> i
+ 1) {
1507 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1514 if (sm_reply
.code
< 100) {
1516 printf ("%s\n", sm_reply
.text
);
1522 sm_reply
.length
= rp
- sm_reply
.text
;
1523 sm_reply
.text
[sm_reply
.length
] = 0;
1524 return sm_reply
.code
;
1531 sm_rrecord (char *buffer
, int *len
)
1536 return sm_rerror(0);
1538 buffer
[*len
= 0] = 0;
1540 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1541 return sm_rerror (retval
);
1542 *len
= strlen (buffer
);
1543 /* *len should be >0 except on EOF, but check for safety's sake */
1545 return sm_rerror (RP_EOF
);
1546 if (buffer
[*len
- 1] != '\n')
1547 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1551 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1560 * Our version of fgets, which calls our private fgetc function
1564 sm_fgets(char *buffer
, int size
, FILE *f
)
1578 } while (size
> 1 && c
!= '\n');
1586 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1588 * Read from the network, but do SASL or TLS encryption
1594 char tmpbuf
[BUFSIZ
], *retbuf
;
1595 unsigned int retbufsize
= 0;
1599 * If we have leftover data, return it
1602 if (sasl_inbuflen
) {
1604 return (int) *sasl_inptr
++;
1608 * If not, read from the network until we have some data to return
1611 while (retbufsize
== 0) {
1615 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1618 result
= SSL_get_error(ssl
, cc
);
1620 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1621 sm_ierror("TLS peer aborted connection");
1628 sm_ierror("SSL_read failed: %s",
1629 ERR_error_string(ERR_get_error(), NULL
));
1633 #endif /* TLS_SUPPORT */
1635 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1641 sm_ierror("Unable to read from network: %s", strerror(errno
));
1646 * Don't call sasl_decode unless sasl is complete and we have
1647 * encryption working
1651 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1655 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1658 if (result
!= SASL_OK
) {
1659 sm_ierror("Unable to decode SASL network data: %s",
1660 sasl_errdetail(conn
));
1664 #else /* ! CYRUS_SASL */
1667 #endif /* CYRUS_SASL */
1670 if (retbufsize
> SASL_MAXRECVBUF
) {
1671 sm_ierror("Received data (%d bytes) is larger than the buffer "
1672 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1676 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1677 sasl_inptr
= sasl_inbuffer
+ 1;
1678 sasl_inbuflen
= retbufsize
- 1;
1680 return (int) sasl_inbuffer
[0];
1682 #endif /* CYRUS_SASL || TLS_SUPPORT */
1687 if (sm_mts
== MTS_SMTP
)
1689 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1690 : sm_alarmed
? "read from socket timed out"
1691 : rc
== RP_EOF
? "premature end-of-file on socket"
1692 : "error reading from socket"));
1695 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1696 : sm_alarmed
? "read from pipe timed out"
1697 : rc
== RP_EOF
? "premature end-of-file on pipe"
1698 : "error reading from pipe"));
1700 return (sm_reply
.code
= NOTOK
);
1709 #ifndef RELIABLE_SIGNALS
1710 SIGNAL (SIGALRM
, alrmser
);
1715 printf ("timed out...\n");
1722 rp_string (int code
)
1725 static char buffer
[BUFSIZ
];
1727 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1747 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1767 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1768 text
, sm_reply
.code
, sm_reply
.text
);
1780 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1782 if (strncmp (ep
, s
, len
) == 0) {
1783 for (ep
+= len
; *ep
== ' '; ep
++)