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
;
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");
283 * Give EHLO or HELO command
287 result
= smtalk (SM_HELO
, "EHLO %s", client
);
290 if (result
>= 500 && result
<= 599)
291 result
= smtalk (SM_HELO
, "HELO %s", client
);
300 * If the user requested TLS support, then try to do the STARTTLS command
301 * as part of the initial dialog. Assuming this works, we then need to
302 * restart the EHLO dialog after TLS negotiation is complete.
308 if (! EHLOset("STARTTLS")) {
310 return sm_ierror("SMTP server does not support TLS");
313 result
= smtalk(SM_HELO
, "STARTTLS");
321 * Okay, the other side should be waiting for us to start TLS
322 * negotiation. Oblige them.
326 const SSL_METHOD
*method
;
329 SSL_load_error_strings();
331 method
= TLSv1_client_method(); /* Not sure about this */
333 sslctx
= SSL_CTX_new(method
);
337 return sm_ierror("Unable to initialize OpenSSL context: %s",
338 ERR_error_string(ERR_get_error(), NULL
));
342 ssl
= SSL_new(sslctx
);
346 return sm_ierror("Unable to create SSL connection: %s",
347 ERR_error_string(ERR_get_error(), NULL
));
350 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
351 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
353 if (sbior
== NULL
|| sbiow
== NULL
) {
355 return sm_ierror("Unable to create BIO endpoints: %s",
356 ERR_error_string(ERR_get_error(), NULL
));
359 SSL_set_bio(ssl
, sbior
, sbiow
);
360 SSL_set_connect_state(ssl
);
363 * Set up a BIO to handle buffering for us
366 io
= BIO_new(BIO_f_buffer());
370 return sm_ierror("Unable to create a buffer BIO: %s",
371 ERR_error_string(ERR_get_error(), NULL
));
374 ssl_bio
= BIO_new(BIO_f_ssl());
378 return sm_ierror("Unable to create a SSL BIO: %s",
379 ERR_error_string(ERR_get_error(), NULL
));
382 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
383 BIO_push(io
, ssl_bio
);
386 * Try doing the handshake now
389 if (BIO_do_handshake(io
) < 1) {
391 return sm_ierror("Unable to negotiate SSL connection: %s",
392 ERR_error_string(ERR_get_error(), NULL
));
396 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
397 printf("SSL negotiation successful: %s(%d) %s\n",
398 SSL_CIPHER_get_name(cipher
),
399 SSL_CIPHER_get_bits(cipher
, NULL
),
400 SSL_CIPHER_get_version(cipher
));
407 result
= smtalk (SM_HELO
, "EHLO %s", client
);
415 #else /* TLS_SUPPORT */
417 #endif /* TLS_SUPPORT */
421 * If the user asked for SASL, then check to see if the SMTP server
422 * supports it. Otherwise, error out (because the SMTP server
423 * might have been spoofed; we don't want to just silently not
428 if (! (server_mechs
= EHLOset("AUTH"))) {
430 return sm_ierror("SMTP server does not support SASL");
433 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
435 return sm_ierror("Requested SASL mech \"%s\" is not in the "
436 "list of supported mechanisms:\n%s",
437 saslmech
, server_mechs
);
440 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
446 #endif /* CYRUS_SASL */
449 if (watch
&& EHLOset ("XVRB"))
450 smtalk (SM_HELO
, "VERB on");
451 if (queued
&& EHLOset ("XQUE"))
452 smtalk (SM_HELO
, "QUED");
458 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
459 int debug
, int queued
,
460 int sasl
, int saslssf
, char *saslmech
, char *user
)
462 unsigned int i
, result
, vecp
;
467 #else /* CYRUS_SASL */
470 NMH_UNUSED (saslssf
);
471 NMH_UNUSED (saslmech
);
473 #endif /* CYRUS_SASL */
478 sm_verbose
= verbose
;
480 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
483 if (client
== NULL
|| *client
== '\0') {
487 client
= LocalName(1); /* no clientname -> LocalName */
491 * Last-ditch check just in case client still isn't set to anything
494 if (client
== NULL
|| *client
== '\0')
495 client
= "localhost";
497 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
498 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
500 return sm_ierror("Unable to allocate %d bytes for read buffer",
502 #endif /* CYRUS_SASL || TLS_SUPPORT */
504 if (pipe (pdi
) == NOTOK
)
505 return sm_ierror ("no pipes");
506 if (pipe (pdo
) == NOTOK
) {
509 return sm_ierror ("no pipes");
512 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
521 return sm_ierror ("unable to fork");
524 if (pdo
[0] != fileno (stdin
))
525 dup2 (pdo
[0], fileno (stdin
));
526 if (pdi
[1] != fileno (stdout
))
527 dup2 (pdi
[1], fileno (stdout
));
528 if (pdi
[1] != fileno (stderr
))
529 dup2 (pdi
[1], fileno (stderr
));
530 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
534 vec
[vecp
++] = r1bindex (sendmail
, '/');
536 vec
[vecp
++] = watch
? "-odi" : queued
? "-odq" : "-odb";
537 vec
[vecp
++] = "-oem";
545 execvp (sendmail
, vec
);
546 fprintf (stderr
, "unable to exec ");
548 _exit (-1); /* NOTREACHED */
551 SIGNAL (SIGALRM
, alrmser
);
552 SIGNAL (SIGPIPE
, SIG_IGN
);
556 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
557 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
560 sm_rfp
= sm_wfp
= NULL
;
561 return sm_ierror ("unable to fdopen");
577 result
= smtalk (SM_HELO
, "EHLO %s", client
);
580 if (500 <= result
&& result
<= 599)
581 result
= smtalk (SM_HELO
, "HELO %s", client
);
594 * If the user asked for SASL, then check to see if the SMTP server
595 * supports it. Otherwise, error out (because the SMTP server
596 * might have been spoofed; we don't want to just silently not
601 if (! (server_mechs
= EHLOset("AUTH"))) {
603 return sm_ierror("SMTP server does not support SASL");
606 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
608 return sm_ierror("Requested SASL mech \"%s\" is not in the "
609 "list of supported mechanisms:\n%s",
610 saslmech
, server_mechs
);
613 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
619 #endif /* CYRUS_SASL */
622 smtalk (SM_HELO
, "VERB on");
629 rclient (char *server
, char *service
)
632 char response
[BUFSIZ
];
634 if ((sd
= client (server
, service
, response
, sizeof(response
),
638 sm_ierror ("%s", response
);
643 sm_winit (char *from
)
645 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
662 sm_wadr (char *mbox
, char *host
, char *path
)
664 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
666 path
? path
: "", mbox
, host
)) {
676 #endif /* SENDMAILBUG */
701 switch (smtalk (SM_DATA
, "DATA")) {
710 #endif /* SENDMAILBUG */
727 sm_wtxt (char *buffer
, int len
)
733 result
= sm_wstream (buffer
, len
);
736 return (result
== NOTOK
? RP_BHST
: RP_OK
);
743 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
746 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
754 #endif /* SENDMAILBUG */
772 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
783 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
788 smtalk (SM_QUIT
, "QUIT");
792 sm_note
.code
= sm_reply
.code
;
793 sm_note
.length
= sm_reply
.length
;
794 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
796 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
798 if (sm_mts
== MTS_SMTP
)
799 smtalk (SM_QUIT
, "QUIT");
801 /* The SIGPIPE block replaces old calls to discard ().
802 We're not sure what the discard () calls were for,
803 maybe to prevent deadlock on old systems. In any
804 case, blocking SIGPIPE should be harmless.
805 Because the file handles are closed below, leave it
809 sigaddset (&set
, SIGPIPE
);
810 sigprocmask (SIG_BLOCK
, &set
, &oset
);
812 kill (sm_child
, SIGKILL
);
816 sm_reply
.code
= sm_note
.code
;
817 sm_reply
.length
= sm_note
.length
;
818 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
825 BIO_ssl_shutdown(io
);
828 #endif /* TLS_SUPPORT */
830 if (sm_rfp
!= NULL
) {
835 if (sm_wfp
!= NULL
) {
841 if (sm_mts
== MTS_SMTP
) {
846 if (sasl_outbuffer
) {
847 free(sasl_outbuffer
);
852 #endif /* CYRUS_SASL */
853 } else if (sm_child
!= NOTOK
) {
854 status
= pidwait (sm_child
, OK
);
860 sm_rfp
= sm_wfp
= NULL
;
861 return (status
? RP_BHST
: RP_OK
);
866 * This function implements SASL authentication for SMTP. If this function
867 * completes successfully, then authentication is successful and we've
868 * (optionally) negotiated a security layer.
871 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
874 unsigned int buflen
, outlen
;
875 char *buf
, outbuf
[BUFSIZ
], host
[NI_MAXHOST
];
876 const char *chosen_mech
;
877 sasl_security_properties_t secprops
;
882 * Initialize the callback contexts
886 user
= getusername();
888 callbacks
[SM_SASL_N_CB_USER
].context
= user
;
889 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= user
;
892 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
893 * to us on the command line, then call getpeername and do a
894 * reverse-address lookup on the IP address to get the name.
897 memset(host
, 0, sizeof(host
));
900 struct sockaddr_storage sin
;
901 socklen_t len
= sizeof(sin
);
904 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
905 sm_ierror("getpeername on SMTP socket failed: %s",
910 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
911 NULL
, 0, NI_NAMEREQD
);
913 sm_ierror("Unable to look up name of connected host: %s",
914 gai_strerror(result
));
918 strncpy(host
, inhost
, sizeof(host
) - 1);
921 sasl_pw_context
[0] = host
;
922 sasl_pw_context
[1] = user
;
924 callbacks
[SM_SASL_N_CB_PASS
].context
= sasl_pw_context
;
926 result
= sasl_client_init(callbacks
);
928 if (result
!= SASL_OK
) {
929 sm_ierror("SASL library initialization failed: %s",
930 sasl_errstring(result
, NULL
, NULL
));
934 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
936 if (result
!= SASL_OK
) {
937 sm_ierror("SASL client initialization failed: %s",
938 sasl_errstring(result
, NULL
, NULL
));
943 * Initialize the security properties. But if TLS is active, then
944 * don't negotiate encryption here.
947 memset(&secprops
, 0, sizeof(secprops
));
948 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
950 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
952 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
954 if (result
!= SASL_OK
) {
955 sm_ierror("SASL security property initialization failed: %s",
956 sasl_errstring(result
, NULL
, NULL
));
961 * Start the actual protocol. Feed the mech list into the library
962 * and get out a possible initial challenge
965 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
966 &buflen
, (const char **) &chosen_mech
);
968 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
969 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
974 * If we got an initial challenge, send it as part of the AUTH
975 * command; otherwise, just send a plain AUTH command.
979 status
= sasl_encode64(buf
, buflen
, outbuf
, sizeof(outbuf
), NULL
);
980 if (status
!= SASL_OK
) {
981 sm_ierror("SASL base64 encode failed: %s",
982 sasl_errstring(status
, NULL
, NULL
));
986 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
988 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
991 * Now we loop until we either fail, get a SASL_OK, or a 235
992 * response code. Receive the challenges and process them until
996 while (result
== SASL_CONTINUE
) {
999 * If we get a 235 response, that means authentication has
1000 * succeeded and we need to break out of the loop (yes, even if
1001 * we still get SASL_CONTINUE from sasl_client_step()).
1003 * Otherwise, if we get a message that doesn't seem to be a
1004 * valid response, then abort
1009 else if (status
< 300 || status
> 399)
1013 * Special case; a zero-length response from the SMTP server
1014 * is returned as a single =. If we get that, then set buflen
1015 * to be zero. Otherwise, just decode the response.
1018 if (strcmp("=", sm_reply
.text
) == 0) {
1021 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
1022 outbuf
, sizeof(outbuf
), &outlen
);
1024 if (result
!= SASL_OK
) {
1025 smtalk(SM_AUTH
, "*");
1026 sm_ierror("SASL base64 decode failed: %s",
1027 sasl_errstring(result
, NULL
, NULL
));
1032 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
1033 (const char **) &buf
, &buflen
);
1035 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
1036 smtalk(SM_AUTH
, "*");
1037 sm_ierror("SASL client negotiation failed: %s",
1038 sasl_errstring(result
, NULL
, NULL
));
1042 status
= sasl_encode64(buf
, buflen
, outbuf
, sizeof(outbuf
), NULL
);
1044 if (status
!= SASL_OK
) {
1045 smtalk(SM_AUTH
, "*");
1046 sm_ierror("SASL base64 encode failed: %s",
1047 sasl_errstring(status
, NULL
, NULL
));
1051 status
= smtalk(SM_AUTH
, outbuf
);
1055 * Make sure that we got the correct response
1058 if (status
< 200 || status
> 299)
1062 * We _should_ have completed the authentication successfully.
1063 * Get a few properties from the authentication exchange.
1066 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
1068 if (result
!= SASL_OK
) {
1069 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1070 sasl_errstring(result
, NULL
, NULL
));
1074 maxoutbuf
= *outbufmax
;
1076 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
1080 if (result
!= SASL_OK
) {
1081 sm_ierror("Cannot retrieve SASL negotiated security strength "
1082 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
1087 sasl_outbuffer
= malloc(maxoutbuf
);
1089 if (sasl_outbuffer
== NULL
) {
1090 sm_ierror("Unable to allocate %d bytes for SASL output "
1091 "buffer", maxoutbuf
);
1096 sasl_inptr
= sasl_inbuffer
;
1098 sasl_outbuffer
= NULL
;
1099 /* Don't NULL out sasl_inbuffer because it could be used in
1109 * Our callback functions to feed data to the SASL library
1113 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1115 char *user
= (char *) context
;
1117 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1118 return SASL_BADPARAM
;
1122 *len
= strlen(user
);
1128 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1129 sasl_secret_t
**psecret
)
1131 char **pw_context
= (char **) context
;
1137 if (! psecret
|| id
!= SASL_CB_PASS
)
1138 return SASL_BADPARAM
;
1140 ruserpass(pw_context
[0], &(pw_context
[1]), &pass
);
1144 *psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
);
1151 (*psecret
)->len
= len
;
1152 strcpy((char *) (*psecret
)->data
, pass
);
1157 #endif /* CYRUS_SASL */
1160 sm_ierror (char *fmt
, ...)
1165 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1168 sm_reply
.length
= strlen (sm_reply
.text
);
1169 sm_reply
.code
= NOTOK
;
1175 smtalk (int time
, char *fmt
, ...)
1179 char buffer
[BUFSIZ
];
1182 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
1187 printf("(sasl-encrypted) ");
1189 printf("(tls-encrypted) ");
1190 printf ("=> %s\n", buffer
);
1195 alarm ((unsigned) time
);
1196 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
1205 * write the buffer to the open SMTP channel
1209 sm_wrecord (char *buffer
, int len
)
1212 return sm_werror ();
1214 sm_fwrite (buffer
, len
);
1218 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1223 sm_wstream (char *buffer
, int len
)
1226 static char lc
= '\0';
1229 return sm_werror ();
1231 if (buffer
== NULL
&& len
== 0) {
1235 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1238 for (bp
= buffer
; len
> 0; bp
++, len
--) {
1247 sm_fputc ('.');/* FALL THROUGH */
1252 if (ferror (sm_wfp
))
1253 return sm_werror ();
1258 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1262 * Write out to the network, but do buffering for SASL (if enabled)
1266 sm_fwrite(char *buffer
, int len
)
1270 unsigned int outputlen
;
1272 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1273 #endif /* CYRUS_SASL */
1278 ret
= BIO_write(io
, buffer
, len
);
1281 sm_ierror("TLS error during write: %s",
1282 ERR_error_string(ERR_get_error(), NULL
));
1286 #endif /* TLS_SUPPORT */
1287 fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
);
1290 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1291 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1292 maxoutbuf
- sasl_outbuflen
);
1293 len
-= maxoutbuf
- sasl_outbuflen
;
1296 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1297 &output
, &outputlen
) != SASL_OK
) {
1298 sm_ierror("Unable to SASL encode connection data: %s",
1299 sasl_errdetail(conn
));
1303 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1307 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1308 sasl_outbuflen
+= len
;
1311 #endif /* CYRUS_SASL */
1312 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1316 * Convenience functions to replace occurences of fputs() and fputc()
1320 sm_fputs(char *buffer
)
1322 return sm_fwrite(buffer
, strlen(buffer
));
1330 return sm_fwrite(&h
, 1);
1334 * Flush out any pending data on the connection
1342 unsigned int outputlen
;
1345 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1346 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1347 &output
, &outputlen
);
1348 if (result
!= SASL_OK
) {
1349 sm_ierror("Unable to SASL encode connection data: %s",
1350 sasl_errdetail(conn
));
1354 fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
);
1357 #endif /* CYRUS_SASL */
1361 (void) BIO_flush(io
);
1363 #endif /* TLS_SUPPORT */
1372 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1373 : sm_alarmed
? "write to socket timed out"
1374 : "error writing to socket"));
1376 return (sm_reply
.code
= NOTOK
);
1383 int i
, code
, cont
, bc
= 0, rc
, more
;
1386 char **ehlo
= NULL
, buffer
[BUFSIZ
];
1389 static int at_least_once
= 0;
1391 if (at_least_once
) {
1394 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1408 sm_reply
.length
= 0;
1409 sm_reply
.text
[0] = 0;
1411 rc
= sizeof(sm_reply
.text
) - 1;
1413 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1417 printf("(sasl-decrypted) ");
1419 printf("(tls-decrypted) ");
1420 printf ("<= %s\n", buffer
);
1425 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1426 && (buffer
[3] == '-' || doingEHLO
== 2)
1428 if (doingEHLO
== 2) {
1429 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1430 strcpy (*ehlo
++, buffer
+ 4);
1432 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1442 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1446 code
= atoi ((char *) bp
);
1448 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1450 if (bc
> 0 && *bp
== '-') {
1453 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1458 if (code
!= sm_reply
.code
|| cont
)
1462 sm_reply
.code
= code
;
1465 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1466 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1467 bp
= (unsigned char *) buffer
;
1468 bc
= strlen (sm_noreply
);
1472 if ((i
= min (bc
, rc
)) > 0) {
1476 i
= strlen(sm_moreply
);
1477 if (more
&& rc
> i
+ 1) {
1478 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1485 if (sm_reply
.code
< 100) {
1487 printf ("%s\n", sm_reply
.text
);
1493 sm_reply
.length
= rp
- sm_reply
.text
;
1494 sm_reply
.text
[sm_reply
.length
] = 0;
1495 return sm_reply
.code
;
1502 sm_rrecord (char *buffer
, int *len
)
1507 return sm_rerror(0);
1509 buffer
[*len
= 0] = 0;
1511 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1512 return sm_rerror (retval
);
1513 *len
= strlen (buffer
);
1514 /* *len should be >0 except on EOF, but check for safety's sake */
1516 return sm_rerror (RP_EOF
);
1517 if (buffer
[*len
- 1] != '\n')
1518 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1522 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1531 * Our version of fgets, which calls our private fgetc function
1535 sm_fgets(char *buffer
, int size
, FILE *f
)
1549 } while (size
> 1 && c
!= '\n');
1557 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1559 * Read from the network, but do SASL or TLS encryption
1565 char tmpbuf
[BUFSIZ
], *retbuf
;
1566 unsigned int retbufsize
= 0;
1570 * If we have leftover data, return it
1573 if (sasl_inbuflen
) {
1575 return (int) *sasl_inptr
++;
1579 * If not, read from the network until we have some data to return
1582 while (retbufsize
== 0) {
1586 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1589 result
= SSL_get_error(ssl
, cc
);
1591 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1592 sm_ierror("TLS peer aborted connection");
1599 sm_ierror("SSL_read failed: %s",
1600 ERR_error_string(ERR_get_error(), NULL
));
1604 #endif /* TLS_SUPPORT */
1606 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1612 sm_ierror("Unable to read from network: %s", strerror(errno
));
1617 * Don't call sasl_decode unless sasl is complete and we have
1618 * encryption working
1622 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1626 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1629 if (result
!= SASL_OK
) {
1630 sm_ierror("Unable to decode SASL network data: %s",
1631 sasl_errdetail(conn
));
1635 #else /* ! CYRUS_SASL */
1638 #endif /* CYRUS_SASL */
1641 if (retbufsize
> SASL_MAXRECVBUF
) {
1642 sm_ierror("Received data (%d bytes) is larger than the buffer "
1643 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1647 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1648 sasl_inptr
= sasl_inbuffer
+ 1;
1649 sasl_inbuflen
= retbufsize
- 1;
1651 return (int) sasl_inbuffer
[0];
1653 #endif /* CYRUS_SASL || TLS_SUPPORT */
1658 if (sm_mts
== MTS_SMTP
)
1660 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1661 : sm_alarmed
? "read from socket timed out"
1662 : rc
== RP_EOF
? "premature end-of-file on socket"
1663 : "error reading from socket"));
1666 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1667 : sm_alarmed
? "read from pipe timed out"
1668 : rc
== RP_EOF
? "premature end-of-file on pipe"
1669 : "error reading from pipe"));
1671 return (sm_reply
.code
= NOTOK
);
1680 #ifndef RELIABLE_SIGNALS
1681 SIGNAL (SIGALRM
, alrmser
);
1686 printf ("timed out...\n");
1693 rp_string (int code
)
1696 static char buffer
[BUFSIZ
];
1698 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1718 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1738 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1739 text
, sm_reply
.code
, sm_reply
.text
);
1751 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1753 if (strncmp (ep
, s
, len
) == 0) {
1754 for (ep
+= len
; *ep
== ' '; ep
++)