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
= "; ";
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, int,
156 char *, char *, int);
157 static int sendmail_init (char *, char *, int, 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 queued
, int sasl
, int saslssf
,
188 char *saslmech
, char *user
, int tls
)
190 if (sm_mts
== MTS_SMTP
)
191 return smtp_init (client
, server
, port
, watch
, verbose
,
192 debug
, queued
, sasl
, saslssf
, saslmech
,
195 return sendmail_init (client
, server
, watch
, verbose
,
196 debug
, queued
, sasl
, saslssf
, saslmech
,
201 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
202 int debug
, int queued
,
203 int sasl
, int saslssf
, char *saslmech
, char *user
, int tls
)
205 int result
, sd1
, sd2
;
208 #else /* CYRUS_SASL */
210 NMH_UNUSED (saslssf
);
211 NMH_UNUSED (saslmech
);
213 #endif /* CYRUS_SASL */
218 sm_verbose
= verbose
;
221 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
224 if (client
== NULL
|| *client
== '\0') {
228 client
= LocalName(1); /* no clientname -> LocalName */
233 * Last-ditch check just in case client still isn't set to anything
236 if (client
== NULL
|| *client
== '\0')
237 client
= "localhost";
239 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
240 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
242 return sm_ierror("Unable to allocate %d bytes for read buffer",
244 #endif /* CYRUS_SASL || TLS_SUPPORT */
246 if ((sd1
= rclient (server
, port
)) == NOTOK
)
249 if ((sd2
= dup (sd1
)) == NOTOK
) {
251 return sm_ierror ("unable to dup");
254 SIGNAL (SIGALRM
, alrmser
);
255 SIGNAL (SIGPIPE
, SIG_IGN
);
257 if ((sm_rfp
= fdopen (sd1
, "r")) == NULL
258 || (sm_wfp
= fdopen (sd2
, "w")) == NULL
) {
261 sm_rfp
= sm_wfp
= NULL
;
262 return sm_ierror ("unable to fdopen");
269 * If tls == 2, that means that the user requested "initial" TLS,
270 * which happens right after the connection has opened. Do that
275 result
= tls_negotiate();
278 * Note: if tls_negotiate() fails it will call sm_end() for us,
279 * which closes the connection.
284 #endif /* TLS_SUPPORT */
301 * Give EHLO or HELO command
305 result
= smtalk (SM_HELO
, "EHLO %s", client
);
308 if (result
>= 500 && result
<= 599)
309 result
= smtalk (SM_HELO
, "HELO %s", client
);
318 * If the user requested TLS support, then try to do the STARTTLS command
319 * as part of the initial dialog. Assuming this works, we then need to
320 * restart the EHLO dialog after TLS negotiation is complete.
324 if (! EHLOset("STARTTLS")) {
326 return sm_ierror("SMTP server does not support TLS");
329 result
= smtalk(SM_HELO
, "STARTTLS");
337 * Okay, the other side should be waiting for us to start TLS
338 * negotiation. Oblige them.
341 result
= tls_negotiate();
347 result
= smtalk (SM_HELO
, "EHLO %s", client
);
355 #else /* TLS_SUPPORT */
357 #endif /* TLS_SUPPORT */
361 * If the user asked for SASL, then check to see if the SMTP server
362 * supports it. Otherwise, error out (because the SMTP server
363 * might have been spoofed; we don't want to just silently not
368 if (! (server_mechs
= EHLOset("AUTH"))) {
370 return sm_ierror("SMTP server does not support SASL");
373 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
375 return sm_ierror("Requested SASL mech \"%s\" is not in the "
376 "list of supported mechanisms:\n%s",
377 saslmech
, server_mechs
);
380 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
386 #endif /* CYRUS_SASL */
389 if (watch
&& EHLOset ("XVRB"))
390 smtalk (SM_HELO
, "VERB on");
391 if (queued
&& EHLOset ("XQUE"))
392 smtalk (SM_HELO
, "QUED");
398 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
399 int debug
, int queued
,
400 int sasl
, int saslssf
, char *saslmech
, char *user
)
402 unsigned int i
, result
, vecp
;
407 #else /* CYRUS_SASL */
410 NMH_UNUSED (saslssf
);
411 NMH_UNUSED (saslmech
);
413 #endif /* CYRUS_SASL */
418 sm_verbose
= verbose
;
420 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
423 if (client
== NULL
|| *client
== '\0') {
427 client
= LocalName(1); /* no clientname -> LocalName */
431 * Last-ditch check just in case client still isn't set to anything
434 if (client
== NULL
|| *client
== '\0')
435 client
= "localhost";
437 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
438 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
440 return sm_ierror("Unable to allocate %d bytes for read buffer",
442 #endif /* CYRUS_SASL || TLS_SUPPORT */
444 if (pipe (pdi
) == NOTOK
)
445 return sm_ierror ("no pipes");
446 if (pipe (pdo
) == NOTOK
) {
449 return sm_ierror ("no pipes");
452 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
461 return sm_ierror ("unable to fork");
464 if (pdo
[0] != fileno (stdin
))
465 dup2 (pdo
[0], fileno (stdin
));
466 if (pdi
[1] != fileno (stdout
))
467 dup2 (pdi
[1], fileno (stdout
));
468 if (pdi
[1] != fileno (stderr
))
469 dup2 (pdi
[1], fileno (stderr
));
470 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
474 vec
[vecp
++] = r1bindex (sendmail
, '/');
476 vec
[vecp
++] = watch
? "-odi" : queued
? "-odq" : "-odb";
477 vec
[vecp
++] = "-oem";
483 execvp (sendmail
, vec
);
484 fprintf (stderr
, "unable to exec ");
486 _exit (-1); /* NOTREACHED */
489 SIGNAL (SIGALRM
, alrmser
);
490 SIGNAL (SIGPIPE
, SIG_IGN
);
494 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
495 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
498 sm_rfp
= sm_wfp
= NULL
;
499 return sm_ierror ("unable to fdopen");
515 result
= smtalk (SM_HELO
, "EHLO %s", client
);
518 if (500 <= result
&& result
<= 599)
519 result
= smtalk (SM_HELO
, "HELO %s", client
);
532 * If the user asked for SASL, then check to see if the SMTP server
533 * supports it. Otherwise, error out (because the SMTP server
534 * might have been spoofed; we don't want to just silently not
539 if (! (server_mechs
= EHLOset("AUTH"))) {
541 return sm_ierror("SMTP server does not support SASL");
544 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
546 return sm_ierror("Requested SASL mech \"%s\" is not in the "
547 "list of supported mechanisms:\n%s",
548 saslmech
, server_mechs
);
551 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
557 #endif /* CYRUS_SASL */
560 smtalk (SM_HELO
, "VERB on");
567 rclient (char *server
, char *service
)
570 char response
[BUFSIZ
];
572 if ((sd
= client (server
, service
, response
, sizeof(response
),
576 sm_ierror ("%s", response
);
581 sm_winit (char *from
)
583 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
600 sm_wadr (char *mbox
, char *host
, char *path
)
602 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
604 path
? path
: "", mbox
, host
)) {
614 #endif /* SENDMAILBUG */
639 switch (smtalk (SM_DATA
, "DATA")) {
648 #endif /* SENDMAILBUG */
665 sm_wtxt (char *buffer
, int len
)
671 result
= sm_wstream (buffer
, len
);
674 return (result
== NOTOK
? RP_BHST
: RP_OK
);
681 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
684 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
692 #endif /* SENDMAILBUG */
710 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
721 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
726 smtalk (SM_QUIT
, "QUIT");
730 sm_note
.code
= sm_reply
.code
;
731 sm_note
.length
= sm_reply
.length
;
732 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
734 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
736 if (sm_mts
== MTS_SMTP
)
737 smtalk (SM_QUIT
, "QUIT");
739 /* The SIGPIPE block replaces old calls to discard ().
740 We're not sure what the discard () calls were for,
741 maybe to prevent deadlock on old systems. In any
742 case, blocking SIGPIPE should be harmless.
743 Because the file handles are closed below, leave it
747 sigaddset (&set
, SIGPIPE
);
748 sigprocmask (SIG_BLOCK
, &set
, &oset
);
750 kill (sm_child
, SIGKILL
);
754 sm_reply
.code
= sm_note
.code
;
755 sm_reply
.length
= sm_note
.length
;
756 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
763 BIO_ssl_shutdown(io
);
766 #endif /* TLS_SUPPORT */
768 if (sm_rfp
!= NULL
) {
773 if (sm_wfp
!= NULL
) {
779 if (sm_mts
== MTS_SMTP
) {
784 if (sasl_outbuffer
) {
785 free(sasl_outbuffer
);
790 #endif /* CYRUS_SASL */
791 } else if (sm_child
!= NOTOK
) {
792 status
= pidwait (sm_child
, OK
);
798 sm_rfp
= sm_wfp
= NULL
;
799 return (status
? RP_BHST
: RP_OK
);
804 * This function implements SASL authentication for SMTP. If this function
805 * completes successfully, then authentication is successful and we've
806 * (optionally) negotiated a security layer.
809 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
812 unsigned int buflen
, outlen
;
813 char *buf
, outbuf
[BUFSIZ
], host
[NI_MAXHOST
];
814 const char *chosen_mech
;
815 sasl_security_properties_t secprops
;
818 struct nmh_creds creds
= { 0, 0, 0 };
821 * Initialize the callback contexts
825 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
826 * to us on the command line, then call getpeername and do a
827 * reverse-address lookup on the IP address to get the name.
830 memset(host
, 0, sizeof(host
));
833 struct sockaddr_storage sin
;
834 socklen_t len
= sizeof(sin
);
837 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
838 sm_ierror("getpeername on SMTP socket failed: %s",
843 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
844 NULL
, 0, NI_NAMEREQD
);
846 sm_ierror("Unable to look up name of connected host: %s",
847 gai_strerror(result
));
851 strncpy(host
, inhost
, sizeof(host
) - 1);
854 nmh_get_credentials (host
, user
, 0, &creds
);
856 /* It's OK to copy the creds pointers here. The callbacks that
857 use them will only be called before this function returns. */
858 callbacks
[SM_SASL_N_CB_USER
].context
= creds
.user
;
859 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= creds
.user
;
860 sasl_pw_context
[0] = host
;
861 sasl_pw_context
[1] = creds
.user
;
862 sasl_pw_context
[2] = creds
.password
;
864 callbacks
[SM_SASL_N_CB_PASS
].context
= sasl_pw_context
;
866 result
= sasl_client_init(callbacks
);
868 if (result
!= SASL_OK
) {
869 sm_ierror("SASL library initialization failed: %s",
870 sasl_errstring(result
, NULL
, NULL
));
874 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
876 if (result
!= SASL_OK
) {
877 sm_ierror("SASL client initialization failed: %s",
878 sasl_errstring(result
, NULL
, NULL
));
883 * Initialize the security properties. But if TLS is active, then
884 * don't negotiate encryption here.
887 memset(&secprops
, 0, sizeof(secprops
));
888 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
890 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
892 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
894 if (result
!= SASL_OK
) {
895 sm_ierror("SASL security property initialization failed: %s",
896 sasl_errstring(result
, NULL
, NULL
));
901 * Start the actual protocol. Feed the mech list into the library
902 * and get out a possible initial challenge
905 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
906 &buflen
, (const char **) &chosen_mech
);
908 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
909 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
914 * If we got an initial challenge, send it as part of the AUTH
915 * command; otherwise, just send a plain AUTH command.
919 status
= sasl_encode64(buf
, buflen
, outbuf
, sizeof(outbuf
), NULL
);
920 if (status
!= SASL_OK
) {
921 sm_ierror("SASL base64 encode failed: %s",
922 sasl_errstring(status
, NULL
, NULL
));
926 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
928 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
931 * Now we loop until we either fail, get a SASL_OK, or a 235
932 * response code. Receive the challenges and process them until
936 while (result
== SASL_CONTINUE
) {
939 * If we get a 235 response, that means authentication has
940 * succeeded and we need to break out of the loop (yes, even if
941 * we still get SASL_CONTINUE from sasl_client_step()).
943 * Otherwise, if we get a message that doesn't seem to be a
944 * valid response, then abort
949 else if (status
< 300 || status
> 399)
953 * Special case; a zero-length response from the SMTP server
954 * is returned as a single =. If we get that, then set buflen
955 * to be zero. Otherwise, just decode the response.
958 if (strcmp("=", sm_reply
.text
) == 0) {
961 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
962 outbuf
, sizeof(outbuf
), &outlen
);
963 if (result
!= SASL_OK
) {
964 smtalk(SM_AUTH
, "*");
965 sm_ierror("SASL base64 decode failed: %s",
966 sasl_errstring(result
, NULL
, NULL
));
971 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
972 (const char **) &buf
, &buflen
);
974 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
975 smtalk(SM_AUTH
, "*");
976 sm_ierror("SASL client negotiation failed: %s",
977 sasl_errstring(result
, NULL
, NULL
));
981 status
= sasl_encode64(buf
, buflen
, outbuf
, sizeof(outbuf
), NULL
);
983 if (status
!= SASL_OK
) {
984 smtalk(SM_AUTH
, "*");
985 sm_ierror("SASL base64 encode failed: %s",
986 sasl_errstring(status
, NULL
, NULL
));
990 status
= smtalk(SM_AUTH
, outbuf
);
994 * Make sure that we got the correct response
997 if (status
< 200 || status
> 299)
1001 * We _should_ have completed the authentication successfully.
1002 * Get a few properties from the authentication exchange.
1005 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
1007 if (result
!= SASL_OK
) {
1008 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1009 sasl_errstring(result
, NULL
, NULL
));
1013 maxoutbuf
= *outbufmax
;
1015 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
1019 if (result
!= SASL_OK
) {
1020 sm_ierror("Cannot retrieve SASL negotiated security strength "
1021 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
1026 sasl_outbuffer
= malloc(maxoutbuf
);
1028 if (sasl_outbuffer
== NULL
) {
1029 sm_ierror("Unable to allocate %d bytes for SASL output "
1030 "buffer", maxoutbuf
);
1035 sasl_inptr
= sasl_inbuffer
;
1037 sasl_outbuffer
= NULL
;
1038 /* Don't NULL out sasl_inbuffer because it could be used in
1048 * Our callback functions to feed data to the SASL library
1052 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1054 char *user
= (char *) context
;
1056 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1057 return SASL_BADPARAM
;
1061 *len
= strlen(user
);
1067 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1068 sasl_secret_t
**psecret
)
1070 char **pw_context
= (char **) context
;
1075 if (! psecret
|| id
!= SASL_CB_PASS
)
1076 return SASL_BADPARAM
;
1078 len
= strlen (pw_context
[2]);
1080 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1084 (*psecret
)->len
= len
;
1085 strcpy((char *) (*psecret
)->data
, pw_context
[2]);
1089 #endif /* CYRUS_SASL */
1092 sm_ierror (char *fmt
, ...)
1097 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1100 sm_reply
.length
= strlen (sm_reply
.text
);
1101 sm_reply
.code
= NOTOK
;
1107 smtalk (int time
, char *fmt
, ...)
1111 char buffer
[BUFSIZ
];
1114 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
1119 printf("(sasl-encrypted) ");
1121 printf("(tls-encrypted) ");
1122 printf ("=> %s\n", buffer
);
1127 alarm ((unsigned) time
);
1128 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
1137 * write the buffer to the open SMTP channel
1141 sm_wrecord (char *buffer
, int len
)
1144 return sm_werror ();
1146 sm_fwrite (buffer
, len
);
1150 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1155 sm_wstream (char *buffer
, int len
)
1158 static char lc
= '\0';
1161 return sm_werror ();
1163 if (buffer
== NULL
&& len
== 0) {
1167 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1170 for (bp
= buffer
; len
> 0; bp
++, len
--) {
1179 sm_fputc ('.');/* FALL THROUGH */
1184 if (ferror (sm_wfp
))
1185 return sm_werror ();
1190 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1194 * Write out to the network, but do buffering for SASL (if enabled)
1198 sm_fwrite(char *buffer
, int len
)
1202 unsigned int outputlen
;
1204 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1205 #endif /* CYRUS_SASL */
1210 ret
= BIO_write(io
, buffer
, len
);
1213 sm_ierror("TLS error during write: %s",
1214 ERR_error_string(ERR_get_error(), NULL
));
1218 #endif /* TLS_SUPPORT */
1219 fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
);
1222 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1223 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1224 maxoutbuf
- sasl_outbuflen
);
1225 len
-= maxoutbuf
- sasl_outbuflen
;
1228 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1229 &output
, &outputlen
) != SASL_OK
) {
1230 sm_ierror("Unable to SASL encode connection data: %s",
1231 sasl_errdetail(conn
));
1235 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1239 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1240 sasl_outbuflen
+= len
;
1243 #endif /* CYRUS_SASL */
1244 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1249 * Negotiate Transport Layer Security
1258 const SSL_METHOD
*method
;
1261 SSL_load_error_strings();
1263 method
= TLSv1_client_method(); /* Not sure about this */
1265 /* Older ssl takes a non-const arg. */
1266 sslctx
= SSL_CTX_new((SSL_METHOD
*) method
);
1270 return sm_ierror("Unable to initialize OpenSSL context: %s",
1271 ERR_error_string(ERR_get_error(), NULL
));
1275 ssl
= SSL_new(sslctx
);
1279 return sm_ierror("Unable to create SSL connection: %s",
1280 ERR_error_string(ERR_get_error(), NULL
));
1283 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
1284 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
1286 if (sbior
== NULL
|| sbiow
== NULL
) {
1288 return sm_ierror("Unable to create BIO endpoints: %s",
1289 ERR_error_string(ERR_get_error(), NULL
));
1292 SSL_set_bio(ssl
, sbior
, sbiow
);
1293 SSL_set_connect_state(ssl
);
1296 * Set up a BIO to handle buffering for us
1299 io
= BIO_new(BIO_f_buffer());
1303 return sm_ierror("Unable to create a buffer BIO: %s",
1304 ERR_error_string(ERR_get_error(), NULL
));
1307 ssl_bio
= BIO_new(BIO_f_ssl());
1311 return sm_ierror("Unable to create a SSL BIO: %s",
1312 ERR_error_string(ERR_get_error(), NULL
));
1315 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1316 BIO_push(io
, ssl_bio
);
1319 * Try doing the handshake now
1322 if (BIO_do_handshake(io
) < 1) {
1324 return sm_ierror("Unable to negotiate SSL connection: %s",
1325 ERR_error_string(ERR_get_error(), NULL
));
1329 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1330 printf("SSL negotiation successful: %s(%d) %s\n",
1331 SSL_CIPHER_get_name(cipher
),
1332 SSL_CIPHER_get_bits(cipher
, NULL
),
1333 SSL_CIPHER_get_version(cipher
));
1341 #endif /* TLS_SUPPORT */
1344 * Convenience functions to replace occurences of fputs() and fputc()
1348 sm_fputs(char *buffer
)
1350 return sm_fwrite(buffer
, strlen(buffer
));
1358 return sm_fwrite(&h
, 1);
1362 * Flush out any pending data on the connection
1370 unsigned int outputlen
;
1373 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1374 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1375 &output
, &outputlen
);
1376 if (result
!= SASL_OK
) {
1377 sm_ierror("Unable to SASL encode connection data: %s",
1378 sasl_errdetail(conn
));
1382 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1385 #endif /* CYRUS_SASL */
1389 (void) BIO_flush(io
);
1391 #endif /* TLS_SUPPORT */
1400 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1401 : sm_alarmed
? "write to socket timed out"
1402 : "error writing to socket"));
1404 return (sm_reply
.code
= NOTOK
);
1411 int i
, code
, cont
, bc
= 0, rc
, more
;
1414 char **ehlo
= NULL
, buffer
[BUFSIZ
];
1417 static int at_least_once
= 0;
1419 if (at_least_once
) {
1422 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1436 sm_reply
.length
= 0;
1437 sm_reply
.text
[0] = 0;
1439 rc
= sizeof(sm_reply
.text
) - 1;
1441 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1445 printf("(sasl-decrypted) ");
1447 printf("(tls-decrypted) ");
1448 printf ("<= %s\n", buffer
);
1453 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1454 && (buffer
[3] == '-' || doingEHLO
== 2)
1456 if (doingEHLO
== 2) {
1457 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1458 strcpy (*ehlo
++, buffer
+ 4);
1460 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1470 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1474 code
= atoi ((char *) bp
);
1476 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1478 if (bc
> 0 && *bp
== '-') {
1481 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1486 if (code
!= sm_reply
.code
|| cont
)
1490 sm_reply
.code
= code
;
1493 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1494 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1495 bp
= (unsigned char *) buffer
;
1496 bc
= strlen (sm_noreply
);
1500 if ((i
= min (bc
, rc
)) > 0) {
1504 i
= strlen(sm_moreply
);
1505 if (more
&& rc
> i
+ 1) {
1506 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1513 if (sm_reply
.code
< 100) {
1515 printf ("%s\n", sm_reply
.text
);
1521 sm_reply
.length
= rp
- sm_reply
.text
;
1522 sm_reply
.text
[sm_reply
.length
] = 0;
1523 return sm_reply
.code
;
1530 sm_rrecord (char *buffer
, int *len
)
1535 return sm_rerror(0);
1537 buffer
[*len
= 0] = 0;
1539 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1540 return sm_rerror (retval
);
1541 *len
= strlen (buffer
);
1542 /* *len should be >0 except on EOF, but check for safety's sake */
1544 return sm_rerror (RP_EOF
);
1545 if (buffer
[*len
- 1] != '\n')
1546 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1550 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1559 * Our version of fgets, which calls our private fgetc function
1563 sm_fgets(char *buffer
, int size
, FILE *f
)
1577 } while (size
> 1 && c
!= '\n');
1585 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1587 * Read from the network, but do SASL or TLS encryption
1593 char tmpbuf
[BUFSIZ
], *retbuf
;
1594 unsigned int retbufsize
= 0;
1598 * If we have leftover data, return it
1601 if (sasl_inbuflen
) {
1603 return (int) *sasl_inptr
++;
1607 * If not, read from the network until we have some data to return
1610 while (retbufsize
== 0) {
1614 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1617 result
= SSL_get_error(ssl
, cc
);
1619 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1620 sm_ierror("TLS peer aborted connection");
1627 sm_ierror("SSL_read failed: %s",
1628 ERR_error_string(ERR_get_error(), NULL
));
1632 #endif /* TLS_SUPPORT */
1634 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1640 sm_ierror("Unable to read from network: %s", strerror(errno
));
1645 * Don't call sasl_decode unless sasl is complete and we have
1646 * encryption working
1650 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1654 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1657 if (result
!= SASL_OK
) {
1658 sm_ierror("Unable to decode SASL network data: %s",
1659 sasl_errdetail(conn
));
1663 #else /* ! CYRUS_SASL */
1666 #endif /* CYRUS_SASL */
1669 if (retbufsize
> SASL_MAXRECVBUF
) {
1670 sm_ierror("Received data (%d bytes) is larger than the buffer "
1671 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1675 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1676 sasl_inptr
= sasl_inbuffer
+ 1;
1677 sasl_inbuflen
= retbufsize
- 1;
1679 return (int) sasl_inbuffer
[0];
1681 #endif /* CYRUS_SASL || TLS_SUPPORT */
1686 if (sm_mts
== MTS_SMTP
)
1688 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1689 : sm_alarmed
? "read from socket timed out"
1690 : rc
== RP_EOF
? "premature end-of-file on socket"
1691 : "error reading from socket"));
1694 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1695 : sm_alarmed
? "read from pipe timed out"
1696 : rc
== RP_EOF
? "premature end-of-file on pipe"
1697 : "error reading from pipe"));
1699 return (sm_reply
.code
= NOTOK
);
1708 #ifndef RELIABLE_SIGNALS
1709 SIGNAL (SIGALRM
, alrmser
);
1714 printf ("timed out...\n");
1721 rp_string (int code
)
1724 static char buffer
[BUFSIZ
];
1726 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1746 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1766 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1767 text
, sm_reply
.code
, sm_reply
.text
);
1779 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1781 if (strncmp (ep
, s
, len
) == 0) {
1782 for (ep
+= len
; *ep
== ' '; ep
++)