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>
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>
29 #endif /* CYRUS_SASL */
32 #include <openssl/ssl.h>
33 #include <openssl/err.h>
34 #endif /* TLS_SUPPORT */
37 * This module implements an interface to SendMail very similar
38 * to the MMDF mm_(3) routines. The sm_() routines herein talk
39 * SMTP to a sendmail process, mapping SMTP reply codes into
44 * On older 4.2BSD machines without the POSIX function `sigaction',
45 * the alarm handing stuff for time-outs will NOT work due to the way
46 * syscalls get restarted. This is not really crucial, since SendMail
47 * is generally well-behaved in this area.
52 * It appears that some versions of Sendmail will return Code 451
53 * when they don't really want to indicate a failure.
54 * "Code 451 almost always means sendmail has deferred; we don't
55 * really want bomb out at this point since sendmail will rectify
56 * things later." So, if you define SENDMAILBUG, Code 451 is
57 * considered the same as Code 250. Yuck!
64 #define NBITS ((sizeof (int)) * 8)
67 * these codes must all be different!
69 #define SM_OPEN 300 /* Changed to 5 minutes to comply with a SHOULD in RFC 1123 */
72 #define SM_MAIL 301 /* changed to 5 minutes and a second (for uniqueness), see above */
73 #define SM_RCPT 302 /* see above */
74 #define SM_DATA 120 /* see above */
75 #define SM_TEXT 180 /* see above */
76 #define SM_DOT 600 /* see above */
81 #endif /* CYRUS_SASL */
83 static int sm_addrs
= 0;
84 static int sm_alarmed
= 0;
85 static int sm_child
= NOTOK
;
86 static int sm_debug
= 0;
87 static int sm_nl
= TRUE
;
88 static int sm_verbose
= 0;
90 static FILE *sm_rfp
= NULL
;
91 static FILE *sm_wfp
= NULL
;
93 static int next_line_encoded
= 0;
97 * Some globals needed by SASL
100 static sasl_conn_t
*conn
= NULL
; /* SASL connection state */
101 static int sasl_complete
= 0; /* Has authentication succeeded? */
102 static sasl_ssf_t sasl_ssf
; /* Our security strength factor */
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_AUTHNAME
, (sasl_callback_ft
) sm_get_user
, NULL
},
113 #define SM_SASL_N_CB_AUTHNAME 1
114 { SASL_CB_PASS
, (sasl_callback_ft
) sm_get_pass
, NULL
},
115 #define SM_SASL_N_CB_PASS 2
116 { SASL_CB_LIST_END
, NULL
, NULL
},
119 #else /* CYRUS_SASL */
121 #endif /* CYRUS_SASL */
124 static SSL_CTX
*sslctx
= NULL
;
125 static SSL
*ssl
= NULL
;
126 static BIO
*sbior
= NULL
;
127 static BIO
*sbiow
= NULL
;
128 static BIO
*io
= NULL
;
130 static int tls_negotiate(void);
131 #endif /* TLS_SUPPORT */
133 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
134 #define SASL_MAXRECVBUF 65536
135 static int sm_fgetc(FILE *);
136 static char *sasl_inbuffer
; /* SASL input buffer for encryption */
137 static char *sasl_inptr
; /* Pointer to current inbuf position */
138 static int sasl_inbuflen
; /* Current length of data in inbuf */
140 #define sm_fgetc fgetc
143 static int tls_active
= 0;
145 static char *sm_noreply
= "No reply text given";
146 static char *sm_moreply
= "; ";
147 static struct smtp sm_reply
;
151 static int doingEHLO
;
152 static char *EHLOkeys
[MAXEHLO
+ 1];
157 static int smtp_init (char *, char *, char *, int, int, int, int, int,
158 char *, char *, int);
159 static int sendmail_init (char *, char *, int, int, int, int, int,
162 static int rclient (char *, char *);
163 static int sm_ierror (char *fmt
, ...);
164 static int smtalk (int time
, char *fmt
, ...);
165 static int sm_wrecord (char *, int);
166 static int sm_wstream (char *, int);
167 static int sm_werror (void);
168 static int smhear (void);
169 static int sm_rrecord (char *, int *);
170 static int sm_rerror (int);
171 static void alrmser (int);
172 static char *EHLOset (char *);
173 static char *prepare_for_display (const char *, int *);
174 static int sm_fwrite(char *, int);
175 static int sm_fputs(char *);
176 static int sm_fputc(int);
177 static void sm_fflush(void);
178 static int sm_fgets(char *, int, FILE *);
182 * Function prototypes needed for SASL
185 static int sm_auth_sasl(char *, int, char *, char *);
186 #endif /* CYRUS_SASL */
189 sm_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
190 int debug
, int sasl
, int saslssf
, char *saslmech
, char *user
, int tls
)
192 if (sm_mts
== MTS_SMTP
)
193 return smtp_init (client
, server
, port
, watch
, verbose
,
194 debug
, sasl
, saslssf
, saslmech
, user
, tls
);
196 return sendmail_init (client
, server
, watch
, verbose
,
197 debug
, sasl
, saslssf
, saslmech
, user
);
201 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
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");
396 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
397 int debug
, int sasl
, int saslssf
, char *saslmech
, char *user
)
399 unsigned int i
, result
, vecp
;
404 #else /* CYRUS_SASL */
407 NMH_UNUSED (saslssf
);
408 NMH_UNUSED (saslmech
);
410 #endif /* CYRUS_SASL */
415 sm_verbose
= verbose
;
417 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
420 if (client
== NULL
|| *client
== '\0') {
424 client
= LocalName(1); /* no clientname -> LocalName */
428 * Last-ditch check just in case client still isn't set to anything
431 if (client
== NULL
|| *client
== '\0')
432 client
= "localhost";
434 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
435 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
437 return sm_ierror("Unable to allocate %d bytes for read buffer",
439 #endif /* CYRUS_SASL || TLS_SUPPORT */
441 if (pipe (pdi
) == NOTOK
)
442 return sm_ierror ("no pipes");
443 if (pipe (pdo
) == NOTOK
) {
446 return sm_ierror ("no pipes");
449 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
458 return sm_ierror ("unable to fork");
461 if (pdo
[0] != fileno (stdin
))
462 dup2 (pdo
[0], fileno (stdin
));
463 if (pdi
[1] != fileno (stdout
))
464 dup2 (pdi
[1], fileno (stdout
));
465 if (pdi
[1] != fileno (stderr
))
466 dup2 (pdi
[1], fileno (stderr
));
467 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
471 vec
[vecp
++] = r1bindex (sendmail
, '/');
473 vec
[vecp
++] = watch
? "-odi" : "-odb";
474 vec
[vecp
++] = "-oem";
480 execvp (sendmail
, vec
);
481 fprintf (stderr
, "unable to exec ");
483 _exit (-1); /* NOTREACHED */
486 SIGNAL (SIGALRM
, alrmser
);
487 SIGNAL (SIGPIPE
, SIG_IGN
);
491 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
492 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
495 sm_rfp
= sm_wfp
= NULL
;
496 return sm_ierror ("unable to fdopen");
512 result
= smtalk (SM_HELO
, "EHLO %s", client
);
515 if (500 <= result
&& result
<= 599)
516 result
= smtalk (SM_HELO
, "HELO %s", client
);
529 * If the user asked for SASL, then check to see if the SMTP server
530 * supports it. Otherwise, error out (because the SMTP server
531 * might have been spoofed; we don't want to just silently not
536 if (! (server_mechs
= EHLOset("AUTH"))) {
538 return sm_ierror("SMTP server does not support SASL");
541 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
543 return sm_ierror("Requested SASL mech \"%s\" is not in the "
544 "list of supported mechanisms:\n%s",
545 saslmech
, server_mechs
);
548 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
554 #endif /* CYRUS_SASL */
557 smtalk (SM_HELO
, "VERB on");
564 rclient (char *server
, char *service
)
567 char response
[BUFSIZ
];
569 if ((sd
= client (server
, service
, response
, sizeof(response
),
573 sm_ierror ("%s", response
);
578 sm_winit (char *from
)
580 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
597 sm_wadr (char *mbox
, char *host
, char *path
)
599 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
601 path
? path
: "", mbox
, host
)) {
611 #endif /* SENDMAILBUG */
636 switch (smtalk (SM_DATA
, "DATA")) {
645 #endif /* SENDMAILBUG */
662 sm_wtxt (char *buffer
, int len
)
668 result
= sm_wstream (buffer
, len
);
671 return (result
== NOTOK
? RP_BHST
: RP_OK
);
678 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
681 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
689 #endif /* SENDMAILBUG */
707 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
718 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
723 smtalk (SM_QUIT
, "QUIT");
727 sm_note
.code
= sm_reply
.code
;
728 sm_note
.length
= sm_reply
.length
;
729 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
731 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
733 if (sm_mts
== MTS_SMTP
)
734 smtalk (SM_QUIT
, "QUIT");
736 /* The SIGPIPE block replaces old calls to discard ().
737 We're not sure what the discard () calls were for,
738 maybe to prevent deadlock on old systems. In any
739 case, blocking SIGPIPE should be harmless.
740 Because the file handles are closed below, leave it
744 sigaddset (&set
, SIGPIPE
);
745 sigprocmask (SIG_BLOCK
, &set
, &oset
);
747 kill (sm_child
, SIGKILL
);
751 sm_reply
.code
= sm_note
.code
;
752 sm_reply
.length
= sm_note
.length
;
753 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
760 BIO_ssl_shutdown(io
);
763 #endif /* TLS_SUPPORT */
765 if (sm_rfp
!= NULL
) {
770 if (sm_wfp
!= NULL
) {
776 if (sm_mts
== MTS_SMTP
) {
781 if (sasl_outbuffer
) {
782 free(sasl_outbuffer
);
787 #endif /* CYRUS_SASL */
788 } else if (sm_child
!= NOTOK
) {
789 status
= pidwait (sm_child
, OK
);
795 sm_rfp
= sm_wfp
= NULL
;
796 return (status
? RP_BHST
: RP_OK
);
801 * This function implements SASL authentication for SMTP. If this function
802 * completes successfully, then authentication is successful and we've
803 * (optionally) negotiated a security layer.
806 #define CHECKB64SIZE(insize, outbuf, outsize) \
807 { size_t wantout = (((insize + 2) / 3) * 4) + 32; \
808 if (wantout > outsize) { \
809 outbuf = mh_xrealloc(outbuf, outsize = wantout); \
814 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
817 unsigned int buflen
, outlen
;
818 char *buf
, *outbuf
= NULL
, host
[NI_MAXHOST
];
819 const char *chosen_mech
;
820 sasl_security_properties_t secprops
;
823 struct nmh_creds creds
= { 0, 0, 0 };
824 size_t outbufsize
= 0;
827 * Initialize the callback contexts
831 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
832 * to us on the command line, then call getpeername and do a
833 * reverse-address lookup on the IP address to get the name.
836 memset(host
, 0, sizeof(host
));
839 struct sockaddr_storage sin
;
840 socklen_t len
= sizeof(sin
);
843 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
844 sm_ierror("getpeername on SMTP socket failed: %s",
849 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
850 NULL
, 0, NI_NAMEREQD
);
852 sm_ierror("Unable to look up name of connected host: %s",
853 gai_strerror(result
));
857 strncpy(host
, inhost
, sizeof(host
) - 1);
860 /* It's OK to copy the addresses here. The callbacks that use
861 them will only be called before this function returns. */
864 callbacks
[SM_SASL_N_CB_USER
].context
= &creds
;
865 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= &creds
;
866 callbacks
[SM_SASL_N_CB_PASS
].context
= &creds
;
868 result
= sasl_client_init(callbacks
);
870 if (result
!= SASL_OK
) {
871 sm_ierror("SASL library initialization failed: %s",
872 sasl_errstring(result
, NULL
, NULL
));
876 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
878 if (result
!= SASL_OK
) {
879 sm_ierror("SASL client initialization failed: %s",
880 sasl_errstring(result
, NULL
, NULL
));
885 * Initialize the security properties. But if TLS is active, then
886 * don't negotiate encryption here.
889 memset(&secprops
, 0, sizeof(secprops
));
890 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
892 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
894 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
896 if (result
!= SASL_OK
) {
897 sm_ierror("SASL security property initialization failed: %s",
898 sasl_errstring(result
, NULL
, NULL
));
903 * Start the actual protocol. Feed the mech list into the library
904 * and get out a possible initial challenge
907 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
908 &buflen
, (const char **) &chosen_mech
);
910 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
911 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
916 * If we got an initial challenge, send it as part of the AUTH
917 * command; otherwise, just send a plain AUTH command.
921 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
922 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
923 if (status
!= SASL_OK
) {
924 sm_ierror("SASL base64 encode failed: %s",
925 sasl_errstring(status
, NULL
, NULL
));
931 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
933 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
936 * Now we loop until we either fail, get a SASL_OK, or a 235
937 * response code. Receive the challenges and process them until
941 while (result
== SASL_CONTINUE
) {
944 * If we get a 235 response, that means authentication has
945 * succeeded and we need to break out of the loop (yes, even if
946 * we still get SASL_CONTINUE from sasl_client_step()).
948 * Otherwise, if we get a message that doesn't seem to be a
949 * valid response, then abort
954 else if (status
< 300 || status
> 399) {
961 * Special case; a zero-length response from the SMTP server
962 * is returned as a single =. If we get that, then set buflen
963 * to be zero. Otherwise, just decode the response.
966 if (strcmp("=", sm_reply
.text
) == 0) {
969 if (sm_reply
.length
> (int) outbufsize
) {
970 outbuf
= mh_xrealloc(outbuf
, outbufsize
= sm_reply
.length
);
973 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
974 outbuf
, outbufsize
, &outlen
);
975 if (result
!= SASL_OK
) {
976 smtalk(SM_AUTH
, "*");
977 sm_ierror("SASL base64 decode failed: %s",
978 sasl_errstring(result
, NULL
, NULL
));
985 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
986 (const char **) &buf
, &buflen
);
988 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
989 smtalk(SM_AUTH
, "*");
990 sm_ierror("SASL client negotiation failed: %s",
991 sasl_errstring(result
, NULL
, NULL
));
997 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
998 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
1000 if (status
!= SASL_OK
) {
1001 smtalk(SM_AUTH
, "*");
1002 sm_ierror("SASL base64 encode failed: %s",
1003 sasl_errstring(status
, NULL
, NULL
));
1009 status
= smtalk(SM_AUTH
, outbuf
);
1016 * Make sure that we got the correct response
1019 if (status
< 200 || status
> 299)
1023 * We _should_ have completed the authentication successfully.
1024 * Get a few properties from the authentication exchange.
1027 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
1029 if (result
!= SASL_OK
) {
1030 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1031 sasl_errstring(result
, NULL
, NULL
));
1035 maxoutbuf
= *outbufmax
;
1037 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
1041 if (result
!= SASL_OK
) {
1042 sm_ierror("Cannot retrieve SASL negotiated security strength "
1043 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
1048 sasl_outbuffer
= malloc(maxoutbuf
);
1050 if (sasl_outbuffer
== NULL
) {
1051 sm_ierror("Unable to allocate %d bytes for SASL output "
1052 "buffer", maxoutbuf
);
1057 sasl_inptr
= sasl_inbuffer
;
1059 sasl_outbuffer
= NULL
;
1060 /* Don't NULL out sasl_inbuffer because it could be used in
1070 * Our callback functions to feed data to the SASL library
1074 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1076 nmh_creds_t creds
= (nmh_creds_t
) context
;
1078 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1079 return SASL_BADPARAM
;
1081 if (creds
->user
== NULL
) {
1083 * Pass the 1 third argument to nmh_get_credentials() so
1084 * that a default user if the -user switch to send(1)/post(8)
1085 * wasn't used, and so that a default password will be supplied.
1086 * That's used when those values really don't matter, and only
1087 * with legacy/.netrc, i.e., with a credentials profile entry.
1089 if (nmh_get_credentials (creds
->host
, creds
->user
, 1, creds
) != OK
) {
1090 return SASL_BADPARAM
;
1094 *result
= creds
->user
;
1096 *len
= strlen(creds
->user
);
1102 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1103 sasl_secret_t
**psecret
)
1105 nmh_creds_t creds
= (nmh_creds_t
) context
;
1110 if (! psecret
|| id
!= SASL_CB_PASS
)
1111 return SASL_BADPARAM
;
1113 if (creds
->password
== NULL
) {
1115 * Pass the 0 third argument to nmh_get_credentials() so
1116 * that the default password isn't used. With legacy/.netrc
1117 * credentials support, we'll only get here if the -user
1118 * switch to send(1)/post(8) wasn't used.
1120 if (nmh_get_credentials (creds
->host
, creds
->user
, 0, creds
) != OK
) {
1121 return SASL_BADPARAM
;
1125 len
= strlen (creds
->password
);
1127 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1131 (*psecret
)->len
= len
;
1132 strcpy((char *) (*psecret
)->data
, creds
->password
);
1136 #endif /* CYRUS_SASL */
1139 sm_ierror (char *fmt
, ...)
1144 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1147 sm_reply
.length
= strlen (sm_reply
.text
);
1148 sm_reply
.code
= NOTOK
;
1154 smtalk (int time
, char *fmt
, ...)
1159 size_t bufsize
= BUFSIZ
;
1161 buffer
= mh_xmalloc(bufsize
);
1164 result
= vsnprintf (buffer
, bufsize
, fmt
, ap
);
1167 if (result
> (int) bufsize
) {
1168 buffer
= mh_xrealloc(buffer
, bufsize
= result
+ 1);
1170 vsnprintf (buffer
, bufsize
, fmt
, ap
);
1175 char *decoded_buffer
=
1176 prepare_for_display (buffer
, &next_line_encoded
);
1179 printf("(sasl-encrypted) ");
1181 printf("(tls-encrypted) ");
1182 printf ("=> %s\n", decoded_buffer
);
1183 free (decoded_buffer
);
1188 alarm ((unsigned) time
);
1189 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
1200 * write the buffer to the open SMTP channel
1204 sm_wrecord (char *buffer
, int len
)
1207 return sm_werror ();
1209 sm_fwrite (buffer
, len
);
1213 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1218 sm_wstream (char *buffer
, int len
)
1221 static char lc
= '\0';
1224 return sm_werror ();
1226 if (buffer
== NULL
&& len
== 0) {
1230 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1233 for (bp
= buffer
; bp
&& len
> 0; bp
++, len
--) {
1242 sm_fputc ('.');/* FALL THROUGH */
1247 if (ferror (sm_wfp
))
1248 return sm_werror ();
1253 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1257 * Write out to the network, but do buffering for SASL (if enabled)
1261 sm_fwrite(char *buffer
, int len
)
1265 unsigned int outputlen
;
1267 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1268 #endif /* CYRUS_SASL */
1273 ret
= BIO_write(io
, buffer
, len
);
1276 sm_ierror("TLS error during write: %s",
1277 ERR_error_string(ERR_get_error(), NULL
));
1281 #endif /* TLS_SUPPORT */
1282 if ((int) fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
) < len
) {
1283 advise ("sm_fwrite", "fwrite");
1287 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1288 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1289 maxoutbuf
- sasl_outbuflen
);
1290 len
-= maxoutbuf
- sasl_outbuflen
;
1293 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1294 &output
, &outputlen
) != SASL_OK
) {
1295 sm_ierror("Unable to SASL encode connection data: %s",
1296 sasl_errdetail(conn
));
1300 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) <
1302 advise ("sm_fwrite", "fwrite");
1307 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1308 sasl_outbuflen
+= len
;
1311 #endif /* CYRUS_SASL */
1312 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1317 * Negotiate Transport Layer Security
1326 const SSL_METHOD
*method
;
1329 SSL_load_error_strings();
1331 method
= TLSv1_client_method(); /* Not sure about this */
1333 /* Older ssl takes a non-const arg. */
1334 sslctx
= SSL_CTX_new((SSL_METHOD
*) method
);
1338 return sm_ierror("Unable to initialize OpenSSL context: %s",
1339 ERR_error_string(ERR_get_error(), NULL
));
1343 ssl
= SSL_new(sslctx
);
1347 return sm_ierror("Unable to create SSL connection: %s",
1348 ERR_error_string(ERR_get_error(), NULL
));
1351 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
1352 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
1354 if (sbior
== NULL
|| sbiow
== NULL
) {
1356 return sm_ierror("Unable to create BIO endpoints: %s",
1357 ERR_error_string(ERR_get_error(), NULL
));
1360 SSL_set_bio(ssl
, sbior
, sbiow
);
1361 SSL_set_connect_state(ssl
);
1364 * Set up a BIO to handle buffering for us
1367 io
= BIO_new(BIO_f_buffer());
1371 return sm_ierror("Unable to create a buffer BIO: %s",
1372 ERR_error_string(ERR_get_error(), NULL
));
1375 ssl_bio
= BIO_new(BIO_f_ssl());
1379 return sm_ierror("Unable to create a SSL BIO: %s",
1380 ERR_error_string(ERR_get_error(), NULL
));
1383 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1384 BIO_push(io
, ssl_bio
);
1387 * Try doing the handshake now
1390 if (BIO_do_handshake(io
) < 1) {
1392 return sm_ierror("Unable to negotiate SSL connection: %s",
1393 ERR_error_string(ERR_get_error(), NULL
));
1397 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1398 printf("SSL negotiation successful: %s(%d) %s\n",
1399 SSL_CIPHER_get_name(cipher
),
1400 SSL_CIPHER_get_bits(cipher
, NULL
),
1401 SSL_CIPHER_get_version(cipher
));
1409 #endif /* TLS_SUPPORT */
1412 * Convenience functions to replace occurrences of fputs() and fputc()
1416 sm_fputs(char *buffer
)
1418 return sm_fwrite(buffer
, strlen(buffer
));
1426 return sm_fwrite(&h
, 1);
1430 * Flush out any pending data on the connection
1438 unsigned int outputlen
;
1441 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1442 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1443 &output
, &outputlen
);
1444 if (result
!= SASL_OK
) {
1445 sm_ierror("Unable to SASL encode connection data: %s",
1446 sasl_errdetail(conn
));
1450 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) < outputlen
) {
1451 advise ("sm_fflush", "fwrite");
1455 #endif /* CYRUS_SASL */
1459 (void) BIO_flush(io
);
1461 #endif /* TLS_SUPPORT */
1470 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1471 : sm_alarmed
? "write to socket timed out"
1472 : "error writing to socket"));
1474 return (sm_reply
.code
= NOTOK
);
1481 int i
, code
, cont
, bc
= 0, rc
, more
;
1484 char **ehlo
= EHLOkeys
, buffer
[BUFSIZ
];
1487 static int at_least_once
= 0;
1489 if (at_least_once
) {
1492 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1506 sm_reply
.length
= 0;
1507 sm_reply
.text
[0] = 0;
1509 rc
= sizeof(sm_reply
.text
) - 1;
1511 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1514 char *decoded_buffer
=
1515 prepare_for_display (buffer
, &next_line_encoded
);
1518 printf("(sasl-decrypted) ");
1520 printf("(tls-decrypted) ");
1521 printf ("<= %s\n", decoded_buffer
);
1522 free (decoded_buffer
);
1527 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1528 && (buffer
[3] == '-' || doingEHLO
== 2)
1530 if (doingEHLO
== 2) {
1531 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1532 strcpy (*ehlo
++, buffer
+ 4);
1534 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1544 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1548 code
= atoi ((char *) bp
);
1550 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1552 if (bc
> 0 && *bp
== '-') {
1555 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1560 if (code
!= sm_reply
.code
|| cont
)
1564 sm_reply
.code
= code
;
1567 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1568 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1569 bp
= (unsigned char *) buffer
;
1570 bc
= strlen (sm_noreply
);
1574 if ((i
= min (bc
, rc
)) > 0) {
1578 i
= strlen(sm_moreply
);
1579 if (more
&& rc
> i
+ 1) {
1580 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1587 if (sm_reply
.code
< 100) {
1589 printf ("%s\n", sm_reply
.text
);
1595 sm_reply
.length
= rp
- sm_reply
.text
;
1596 sm_reply
.text
[sm_reply
.length
] = 0;
1597 return sm_reply
.code
;
1604 sm_rrecord (char *buffer
, int *len
)
1609 return sm_rerror(0);
1611 buffer
[*len
= 0] = 0;
1613 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1614 return sm_rerror (retval
);
1615 *len
= strlen (buffer
);
1616 /* *len should be >0 except on EOF, but check for safety's sake */
1618 return sm_rerror (RP_EOF
);
1619 if (buffer
[*len
- 1] != '\n')
1620 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1624 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1633 * Our version of fgets, which calls our private fgetc function
1637 sm_fgets(char *buffer
, int size
, FILE *f
)
1651 } while (size
> 1 && c
!= '\n');
1659 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1661 * Read from the network, but do SASL or TLS encryption
1667 char tmpbuf
[BUFSIZ
], *retbuf
;
1668 unsigned int retbufsize
= 0;
1672 * If we have leftover data, return it
1675 if (sasl_inbuflen
) {
1677 return (int) *sasl_inptr
++;
1681 * If not, read from the network until we have some data to return
1684 while (retbufsize
== 0) {
1688 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1691 result
= SSL_get_error(ssl
, cc
);
1693 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1694 sm_ierror("TLS peer aborted connection");
1701 sm_ierror("SSL_read failed: %s",
1702 ERR_error_string(ERR_get_error(), NULL
));
1706 #endif /* TLS_SUPPORT */
1708 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1714 sm_ierror("Unable to read from network: %s", strerror(errno
));
1719 * Don't call sasl_decode unless sasl is complete and we have
1720 * encryption working
1724 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1728 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1731 if (result
!= SASL_OK
) {
1732 sm_ierror("Unable to decode SASL network data: %s",
1733 sasl_errdetail(conn
));
1737 #else /* ! CYRUS_SASL */
1740 #endif /* CYRUS_SASL */
1743 if (retbufsize
> SASL_MAXRECVBUF
) {
1744 sm_ierror("Received data (%d bytes) is larger than the buffer "
1745 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1749 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1750 sasl_inptr
= sasl_inbuffer
+ 1;
1751 sasl_inbuflen
= retbufsize
- 1;
1753 return (int) sasl_inbuffer
[0];
1755 #endif /* CYRUS_SASL || TLS_SUPPORT */
1760 if (sm_mts
== MTS_SMTP
)
1762 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1763 : sm_alarmed
? "read from socket timed out"
1764 : rc
== RP_EOF
? "premature end-of-file on socket"
1765 : "error reading from socket"));
1768 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1769 : sm_alarmed
? "read from pipe timed out"
1770 : rc
== RP_EOF
? "premature end-of-file on pipe"
1771 : "error reading from pipe"));
1773 return (sm_reply
.code
= NOTOK
);
1782 #ifndef RELIABLE_SIGNALS
1783 SIGNAL (SIGALRM
, alrmser
);
1788 printf ("timed out...\n");
1795 rp_string (int code
)
1798 static char buffer
[BUFSIZ
];
1800 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1820 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1840 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1841 text
, sm_reply
.code
, sm_reply
.text
);
1853 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1855 if (strncmp (ep
, s
, len
) == 0) {
1856 for (ep
+= len
; *ep
== ' '; ep
++)
1867 * Detects, using heuristics, if an SMTP server or client response string
1868 * contains a base64-encoded portion. If it does, decodes it and replaces
1869 * any non-printable characters with a hex representation. Caller is
1870 * responsible for free'ing return value. If the decode fails, a copy of
1871 * the input string is returned.
1875 prepare_for_display (const char *string
, int *next_line_encoded
) {
1876 const char *start
= NULL
;
1877 const char *decoded
;
1879 int prefix_len
= -1;
1881 if (strncmp (string
, "AUTH ", 5) == 0) {
1882 /* AUTH line: the mechanism isn't encoded. If there's an initial
1883 response, it must be base64 encoded.. */
1884 char *mechanism
= strchr (string
+ 5, ' ');
1886 if (mechanism
!= NULL
) {
1887 prefix_len
= (int) (mechanism
- string
+ 1);
1888 } /* else no space following the mechanism, so no initial response */
1889 *next_line_encoded
= 0;
1890 } else if (strncmp (string
, "334 ", 4) == 0) {
1891 /* 334 is the server's request for user or password. */
1893 /* The next (client response) line must be base64 encoded. */
1894 *next_line_encoded
= 1;
1895 } else if (*next_line_encoded
) {
1896 /* "next" line now refers to this line, which is a base64-encoded
1899 *next_line_encoded
= 0;
1901 *next_line_encoded
= 0;
1904 /* Don't attempt to decoded unencoded initial response ('=') or cancel
1906 if (prefix_len
> -1 &&
1907 string
[prefix_len
] != '=' && string
[prefix_len
] != '*') {
1908 start
= string
+ prefix_len
;
1911 if (start
&& decodeBase64 (start
, &decoded
, &decoded_len
, 1, NULL
) == OK
) {
1913 char *prefix
= mh_xmalloc(prefix_len
+ 1);
1914 char *display_string
;
1916 /* prefix is the beginning portion, which isn't base64 encoded. */
1917 snprintf (prefix
, prefix_len
+ 1, "%*s", prefix_len
, string
);
1918 hexify ((const unsigned char *) decoded
, decoded_len
, &hexified
);
1919 /* Wrap the decoded portion in "b64<>". */
1920 display_string
= concat (prefix
, "b64<", hexified
, ">", NULL
);
1923 free ((char *) decoded
);
1925 return display_string
;
1927 return getcpy (string
);