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";
486 execvp (sendmail
, vec
);
487 fprintf (stderr
, "unable to exec ");
489 _exit (-1); /* NOTREACHED */
492 SIGNAL (SIGALRM
, alrmser
);
493 SIGNAL (SIGPIPE
, SIG_IGN
);
497 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
498 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
501 sm_rfp
= sm_wfp
= NULL
;
502 return sm_ierror ("unable to fdopen");
518 result
= smtalk (SM_HELO
, "EHLO %s", client
);
521 if (500 <= result
&& result
<= 599)
522 result
= smtalk (SM_HELO
, "HELO %s", client
);
535 * If the user asked for SASL, then check to see if the SMTP server
536 * supports it. Otherwise, error out (because the SMTP server
537 * might have been spoofed; we don't want to just silently not
542 if (! (server_mechs
= EHLOset("AUTH"))) {
544 return sm_ierror("SMTP server does not support SASL");
547 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
549 return sm_ierror("Requested SASL mech \"%s\" is not in the "
550 "list of supported mechanisms:\n%s",
551 saslmech
, server_mechs
);
554 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
560 #endif /* CYRUS_SASL */
563 smtalk (SM_HELO
, "VERB on");
570 rclient (char *server
, char *service
)
573 char response
[BUFSIZ
];
575 if ((sd
= client (server
, service
, response
, sizeof(response
),
579 sm_ierror ("%s", response
);
584 sm_winit (char *from
)
586 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
603 sm_wadr (char *mbox
, char *host
, char *path
)
605 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
607 path
? path
: "", mbox
, host
)) {
617 #endif /* SENDMAILBUG */
642 switch (smtalk (SM_DATA
, "DATA")) {
651 #endif /* SENDMAILBUG */
668 sm_wtxt (char *buffer
, int len
)
674 result
= sm_wstream (buffer
, len
);
677 return (result
== NOTOK
? RP_BHST
: RP_OK
);
684 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
687 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
695 #endif /* SENDMAILBUG */
713 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
724 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
729 smtalk (SM_QUIT
, "QUIT");
733 sm_note
.code
= sm_reply
.code
;
734 sm_note
.length
= sm_reply
.length
;
735 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
737 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
739 if (sm_mts
== MTS_SMTP
)
740 smtalk (SM_QUIT
, "QUIT");
742 /* The SIGPIPE block replaces old calls to discard ().
743 We're not sure what the discard () calls were for,
744 maybe to prevent deadlock on old systems. In any
745 case, blocking SIGPIPE should be harmless.
746 Because the file handles are closed below, leave it
750 sigaddset (&set
, SIGPIPE
);
751 sigprocmask (SIG_BLOCK
, &set
, &oset
);
753 kill (sm_child
, SIGKILL
);
757 sm_reply
.code
= sm_note
.code
;
758 sm_reply
.length
= sm_note
.length
;
759 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
766 BIO_ssl_shutdown(io
);
769 #endif /* TLS_SUPPORT */
771 if (sm_rfp
!= NULL
) {
776 if (sm_wfp
!= NULL
) {
782 if (sm_mts
== MTS_SMTP
) {
787 if (sasl_outbuffer
) {
788 free(sasl_outbuffer
);
793 #endif /* CYRUS_SASL */
794 } else if (sm_child
!= NOTOK
) {
795 status
= pidwait (sm_child
, OK
);
801 sm_rfp
= sm_wfp
= NULL
;
802 return (status
? RP_BHST
: RP_OK
);
807 * This function implements SASL authentication for SMTP. If this function
808 * completes successfully, then authentication is successful and we've
809 * (optionally) negotiated a security layer.
812 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
815 unsigned int buflen
, outlen
;
816 char *buf
, outbuf
[BUFSIZ
], host
[NI_MAXHOST
];
817 const char *chosen_mech
;
818 sasl_security_properties_t secprops
;
821 struct nmh_creds creds
= { 0, 0, 0 };
824 * Initialize the callback contexts
828 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
829 * to us on the command line, then call getpeername and do a
830 * reverse-address lookup on the IP address to get the name.
833 memset(host
, 0, sizeof(host
));
836 struct sockaddr_storage sin
;
837 socklen_t len
= sizeof(sin
);
840 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
841 sm_ierror("getpeername on SMTP socket failed: %s",
846 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
847 NULL
, 0, NI_NAMEREQD
);
849 sm_ierror("Unable to look up name of connected host: %s",
850 gai_strerror(result
));
854 strncpy(host
, inhost
, sizeof(host
) - 1);
857 nmh_get_credentials (host
, user
, 0, &creds
);
859 /* It's OK to copy the creds pointers here. The callbacks that
860 use them will only be called before this function returns. */
861 callbacks
[SM_SASL_N_CB_USER
].context
= creds
.user
;
862 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= creds
.user
;
863 sasl_pw_context
[0] = host
;
864 sasl_pw_context
[1] = creds
.user
;
865 sasl_pw_context
[2] = creds
.password
;
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
);
966 if (result
!= SASL_OK
) {
967 smtalk(SM_AUTH
, "*");
968 sm_ierror("SASL base64 decode failed: %s",
969 sasl_errstring(result
, NULL
, NULL
));
974 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
975 (const char **) &buf
, &buflen
);
977 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
978 smtalk(SM_AUTH
, "*");
979 sm_ierror("SASL client negotiation failed: %s",
980 sasl_errstring(result
, NULL
, NULL
));
984 status
= sasl_encode64(buf
, buflen
, outbuf
, sizeof(outbuf
), NULL
);
986 if (status
!= SASL_OK
) {
987 smtalk(SM_AUTH
, "*");
988 sm_ierror("SASL base64 encode failed: %s",
989 sasl_errstring(status
, NULL
, NULL
));
993 status
= smtalk(SM_AUTH
, outbuf
);
997 * Make sure that we got the correct response
1000 if (status
< 200 || status
> 299)
1004 * We _should_ have completed the authentication successfully.
1005 * Get a few properties from the authentication exchange.
1008 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
1010 if (result
!= SASL_OK
) {
1011 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1012 sasl_errstring(result
, NULL
, NULL
));
1016 maxoutbuf
= *outbufmax
;
1018 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
1022 if (result
!= SASL_OK
) {
1023 sm_ierror("Cannot retrieve SASL negotiated security strength "
1024 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
1029 sasl_outbuffer
= malloc(maxoutbuf
);
1031 if (sasl_outbuffer
== NULL
) {
1032 sm_ierror("Unable to allocate %d bytes for SASL output "
1033 "buffer", maxoutbuf
);
1038 sasl_inptr
= sasl_inbuffer
;
1040 sasl_outbuffer
= NULL
;
1041 /* Don't NULL out sasl_inbuffer because it could be used in
1051 * Our callback functions to feed data to the SASL library
1055 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1057 char *user
= (char *) context
;
1059 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1060 return SASL_BADPARAM
;
1064 *len
= strlen(user
);
1070 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1071 sasl_secret_t
**psecret
)
1073 char **pw_context
= (char **) context
;
1078 if (! psecret
|| id
!= SASL_CB_PASS
)
1079 return SASL_BADPARAM
;
1081 len
= strlen (pw_context
[2]);
1083 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1087 (*psecret
)->len
= len
;
1088 strcpy((char *) (*psecret
)->data
, pw_context
[2]);
1092 #endif /* CYRUS_SASL */
1095 sm_ierror (char *fmt
, ...)
1100 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1103 sm_reply
.length
= strlen (sm_reply
.text
);
1104 sm_reply
.code
= NOTOK
;
1110 smtalk (int time
, char *fmt
, ...)
1114 char buffer
[BUFSIZ
];
1117 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
1122 printf("(sasl-encrypted) ");
1124 printf("(tls-encrypted) ");
1125 printf ("=> %s\n", buffer
);
1130 alarm ((unsigned) time
);
1131 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
1140 * write the buffer to the open SMTP channel
1144 sm_wrecord (char *buffer
, int len
)
1147 return sm_werror ();
1149 sm_fwrite (buffer
, len
);
1153 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1158 sm_wstream (char *buffer
, int len
)
1161 static char lc
= '\0';
1164 return sm_werror ();
1166 if (buffer
== NULL
&& len
== 0) {
1170 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1173 for (bp
= buffer
; len
> 0; bp
++, len
--) {
1182 sm_fputc ('.');/* FALL THROUGH */
1187 if (ferror (sm_wfp
))
1188 return sm_werror ();
1193 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1197 * Write out to the network, but do buffering for SASL (if enabled)
1201 sm_fwrite(char *buffer
, int len
)
1205 unsigned int outputlen
;
1207 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1208 #endif /* CYRUS_SASL */
1213 ret
= BIO_write(io
, buffer
, len
);
1216 sm_ierror("TLS error during write: %s",
1217 ERR_error_string(ERR_get_error(), NULL
));
1221 #endif /* TLS_SUPPORT */
1222 fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
);
1225 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1226 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1227 maxoutbuf
- sasl_outbuflen
);
1228 len
-= maxoutbuf
- sasl_outbuflen
;
1231 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1232 &output
, &outputlen
) != SASL_OK
) {
1233 sm_ierror("Unable to SASL encode connection data: %s",
1234 sasl_errdetail(conn
));
1238 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1242 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1243 sasl_outbuflen
+= len
;
1246 #endif /* CYRUS_SASL */
1247 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1252 * Negotiate Transport Layer Security
1261 const SSL_METHOD
*method
;
1264 SSL_load_error_strings();
1266 method
= TLSv1_client_method(); /* Not sure about this */
1268 /* Older ssl takes a non-const arg. */
1269 sslctx
= SSL_CTX_new((SSL_METHOD
*) method
);
1273 return sm_ierror("Unable to initialize OpenSSL context: %s",
1274 ERR_error_string(ERR_get_error(), NULL
));
1278 ssl
= SSL_new(sslctx
);
1282 return sm_ierror("Unable to create SSL connection: %s",
1283 ERR_error_string(ERR_get_error(), NULL
));
1286 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
1287 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
1289 if (sbior
== NULL
|| sbiow
== NULL
) {
1291 return sm_ierror("Unable to create BIO endpoints: %s",
1292 ERR_error_string(ERR_get_error(), NULL
));
1295 SSL_set_bio(ssl
, sbior
, sbiow
);
1296 SSL_set_connect_state(ssl
);
1299 * Set up a BIO to handle buffering for us
1302 io
= BIO_new(BIO_f_buffer());
1306 return sm_ierror("Unable to create a buffer BIO: %s",
1307 ERR_error_string(ERR_get_error(), NULL
));
1310 ssl_bio
= BIO_new(BIO_f_ssl());
1314 return sm_ierror("Unable to create a SSL BIO: %s",
1315 ERR_error_string(ERR_get_error(), NULL
));
1318 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1319 BIO_push(io
, ssl_bio
);
1322 * Try doing the handshake now
1325 if (BIO_do_handshake(io
) < 1) {
1327 return sm_ierror("Unable to negotiate SSL connection: %s",
1328 ERR_error_string(ERR_get_error(), NULL
));
1332 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1333 printf("SSL negotiation successful: %s(%d) %s\n",
1334 SSL_CIPHER_get_name(cipher
),
1335 SSL_CIPHER_get_bits(cipher
, NULL
),
1336 SSL_CIPHER_get_version(cipher
));
1344 #endif /* TLS_SUPPORT */
1347 * Convenience functions to replace occurences of fputs() and fputc()
1351 sm_fputs(char *buffer
)
1353 return sm_fwrite(buffer
, strlen(buffer
));
1361 return sm_fwrite(&h
, 1);
1365 * Flush out any pending data on the connection
1373 unsigned int outputlen
;
1376 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1377 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1378 &output
, &outputlen
);
1379 if (result
!= SASL_OK
) {
1380 sm_ierror("Unable to SASL encode connection data: %s",
1381 sasl_errdetail(conn
));
1385 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1388 #endif /* CYRUS_SASL */
1392 (void) BIO_flush(io
);
1394 #endif /* TLS_SUPPORT */
1403 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1404 : sm_alarmed
? "write to socket timed out"
1405 : "error writing to socket"));
1407 return (sm_reply
.code
= NOTOK
);
1414 int i
, code
, cont
, bc
= 0, rc
, more
;
1417 char **ehlo
= NULL
, buffer
[BUFSIZ
];
1420 static int at_least_once
= 0;
1422 if (at_least_once
) {
1425 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1439 sm_reply
.length
= 0;
1440 sm_reply
.text
[0] = 0;
1442 rc
= sizeof(sm_reply
.text
) - 1;
1444 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1448 printf("(sasl-decrypted) ");
1450 printf("(tls-decrypted) ");
1451 printf ("<= %s\n", buffer
);
1456 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1457 && (buffer
[3] == '-' || doingEHLO
== 2)
1459 if (doingEHLO
== 2) {
1460 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1461 strcpy (*ehlo
++, buffer
+ 4);
1463 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1473 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1477 code
= atoi ((char *) bp
);
1479 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1481 if (bc
> 0 && *bp
== '-') {
1484 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1489 if (code
!= sm_reply
.code
|| cont
)
1493 sm_reply
.code
= code
;
1496 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1497 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1498 bp
= (unsigned char *) buffer
;
1499 bc
= strlen (sm_noreply
);
1503 if ((i
= min (bc
, rc
)) > 0) {
1507 i
= strlen(sm_moreply
);
1508 if (more
&& rc
> i
+ 1) {
1509 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1516 if (sm_reply
.code
< 100) {
1518 printf ("%s\n", sm_reply
.text
);
1524 sm_reply
.length
= rp
- sm_reply
.text
;
1525 sm_reply
.text
[sm_reply
.length
] = 0;
1526 return sm_reply
.code
;
1533 sm_rrecord (char *buffer
, int *len
)
1538 return sm_rerror(0);
1540 buffer
[*len
= 0] = 0;
1542 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1543 return sm_rerror (retval
);
1544 *len
= strlen (buffer
);
1545 /* *len should be >0 except on EOF, but check for safety's sake */
1547 return sm_rerror (RP_EOF
);
1548 if (buffer
[*len
- 1] != '\n')
1549 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1553 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1562 * Our version of fgets, which calls our private fgetc function
1566 sm_fgets(char *buffer
, int size
, FILE *f
)
1580 } while (size
> 1 && c
!= '\n');
1588 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1590 * Read from the network, but do SASL or TLS encryption
1596 char tmpbuf
[BUFSIZ
], *retbuf
;
1597 unsigned int retbufsize
= 0;
1601 * If we have leftover data, return it
1604 if (sasl_inbuflen
) {
1606 return (int) *sasl_inptr
++;
1610 * If not, read from the network until we have some data to return
1613 while (retbufsize
== 0) {
1617 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1620 result
= SSL_get_error(ssl
, cc
);
1622 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1623 sm_ierror("TLS peer aborted connection");
1630 sm_ierror("SSL_read failed: %s",
1631 ERR_error_string(ERR_get_error(), NULL
));
1635 #endif /* TLS_SUPPORT */
1637 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1643 sm_ierror("Unable to read from network: %s", strerror(errno
));
1648 * Don't call sasl_decode unless sasl is complete and we have
1649 * encryption working
1653 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1657 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1660 if (result
!= SASL_OK
) {
1661 sm_ierror("Unable to decode SASL network data: %s",
1662 sasl_errdetail(conn
));
1666 #else /* ! CYRUS_SASL */
1669 #endif /* CYRUS_SASL */
1672 if (retbufsize
> SASL_MAXRECVBUF
) {
1673 sm_ierror("Received data (%d bytes) is larger than the buffer "
1674 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1678 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1679 sasl_inptr
= sasl_inbuffer
+ 1;
1680 sasl_inbuflen
= retbufsize
- 1;
1682 return (int) sasl_inbuffer
[0];
1684 #endif /* CYRUS_SASL || TLS_SUPPORT */
1689 if (sm_mts
== MTS_SMTP
)
1691 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1692 : sm_alarmed
? "read from socket timed out"
1693 : rc
== RP_EOF
? "premature end-of-file on socket"
1694 : "error reading from socket"));
1697 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1698 : sm_alarmed
? "read from pipe timed out"
1699 : rc
== RP_EOF
? "premature end-of-file on pipe"
1700 : "error reading from pipe"));
1702 return (sm_reply
.code
= NOTOK
);
1711 #ifndef RELIABLE_SIGNALS
1712 SIGNAL (SIGALRM
, alrmser
);
1717 printf ("timed out...\n");
1724 rp_string (int code
)
1727 static char buffer
[BUFSIZ
];
1729 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1749 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1769 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1770 text
, sm_reply
.code
, sm_reply
.text
);
1782 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1784 if (strncmp (ep
, s
, len
) == 0) {
1785 for (ep
+= len
; *ep
== ' '; ep
++)