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>
17 #include <sasl/sasl.h>
18 #include <sasl/saslutil.h>
19 # if SASL_VERSION_FULL < 0x020125
20 /* Cyrus SASL 2.1.25 introduced the sasl_callback_ft prototype,
21 which has an explicit void parameter list, according to best
22 practice. So we need to cast to avoid compile warnings.
23 Provide this prototype for earlier versions. */
24 typedef int (*sasl_callback_ft
)();
25 # endif /* SASL_VERSION_FULL < 0x020125 */
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #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 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
;
92 static int next_line_encoded
= 0;
96 * Some globals needed by SASL
99 static sasl_conn_t
*conn
= NULL
; /* SASL connection state */
100 static int sasl_complete
= 0; /* Has authentication succeeded? */
101 static sasl_ssf_t sasl_ssf
; /* Our security strength factor */
102 static int maxoutbuf
; /* Maximum crypto output buffer */
103 static char *sasl_outbuffer
; /* SASL output buffer for encryption */
104 static int sasl_outbuflen
; /* Current length of data in outbuf */
105 static int sm_get_user(void *, int, const char **, unsigned *);
106 static int sm_get_pass(sasl_conn_t
*, void *, int, sasl_secret_t
**);
108 static sasl_callback_t callbacks
[] = {
109 { SASL_CB_USER
, (sasl_callback_ft
) sm_get_user
, NULL
},
110 #define SM_SASL_N_CB_USER 0
111 { SASL_CB_AUTHNAME
, (sasl_callback_ft
) sm_get_user
, NULL
},
112 #define SM_SASL_N_CB_AUTHNAME 1
113 { SASL_CB_PASS
, (sasl_callback_ft
) sm_get_pass
, NULL
},
114 #define SM_SASL_N_CB_PASS 2
115 { SASL_CB_LIST_END
, NULL
, NULL
},
118 #else /* CYRUS_SASL */
120 #endif /* CYRUS_SASL */
123 static SSL_CTX
*sslctx
= NULL
;
124 static SSL
*ssl
= NULL
;
125 static BIO
*sbior
= NULL
;
126 static BIO
*sbiow
= NULL
;
127 static BIO
*io
= NULL
;
129 static int tls_negotiate(void);
130 #endif /* TLS_SUPPORT */
132 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
133 #define SASL_MAXRECVBUF 65536
134 static int sm_fgetc(FILE *);
135 static char *sasl_inbuffer
; /* SASL input buffer for encryption */
136 static char *sasl_inptr
; /* Pointer to current inbuf position */
137 static int sasl_inbuflen
; /* Current length of data in inbuf */
139 #define sm_fgetc fgetc
142 static int tls_active
= 0;
144 static char *sm_noreply
= "No reply text given";
145 static char *sm_moreply
= "; ";
146 static struct smtp sm_reply
;
150 static int doingEHLO
;
151 static char *EHLOkeys
[MAXEHLO
+ 1];
156 static int smtp_init (char *, char *, char *, int, int, int, int, int,
157 char *, char *, const char *, int);
158 static int sendmail_init (char *, char *, 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 char *prepare_for_display (const char *, int *);
173 static int sm_fwrite(char *, int);
174 static int sm_fputs(char *);
175 static int sm_fputc(int);
176 static void sm_fflush(void);
177 static int sm_fgets(char *, int, FILE *);
178 static int sm_auth_xoauth2(const char *, const char *, int);
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
,
191 const char *oauth_svc
, int tls
)
193 if (sm_mts
== MTS_SMTP
)
194 return smtp_init (client
, server
, port
, watch
, verbose
,
195 debug
, sasl
, saslssf
, saslmech
, user
,
198 return sendmail_init (client
, server
, watch
, verbose
,
199 debug
, sasl
, saslssf
, saslmech
, user
);
203 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
205 int sasl
, int saslssf
, char *saslmech
, char *user
,
206 const char *oauth_svc
, int tls
)
208 int result
, sd1
, sd2
;
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
370 if (! (server_mechs
= EHLOset("AUTH"))) {
372 return sm_ierror("SMTP server does not support SASL");
375 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
377 return sm_ierror("Requested SASL mech \"%s\" is not in the "
378 "list of supported mechanisms:\n%s",
379 saslmech
, server_mechs
);
382 /* Don't call sm_auth_sasl() for XAUTH2 with -sasl. Instead, call
383 sm_auth_xoauth2() below. */
384 if (oauth_svc
== NULL
&&
385 sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
391 #endif /* CYRUS_SASL */
393 if (oauth_svc
!= NULL
) {
395 if ((server_mechs
= EHLOset("AUTH")) == NULL
396 || stringdex("XOAUTH2", server_mechs
) == -1) {
398 return sm_ierror("SMTP server does not support SASL XOAUTH2");
400 if (sm_auth_xoauth2(user
, oauth_svc
, debug
) != RP_OK
) {
407 if (watch
&& EHLOset ("XVRB"))
408 smtalk (SM_HELO
, "VERB on");
414 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
415 int debug
, int sasl
, int saslssf
, char *saslmech
, char *user
)
417 unsigned int i
, result
, vecp
;
422 #else /* CYRUS_SASL */
425 NMH_UNUSED (saslssf
);
426 NMH_UNUSED (saslmech
);
428 #endif /* CYRUS_SASL */
433 sm_verbose
= verbose
;
435 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
438 if (client
== NULL
|| *client
== '\0') {
442 client
= LocalName(1); /* no clientname -> LocalName */
446 * Last-ditch check just in case client still isn't set to anything
449 if (client
== NULL
|| *client
== '\0')
450 client
= "localhost";
452 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
453 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
455 return sm_ierror("Unable to allocate %d bytes for read buffer",
457 #endif /* CYRUS_SASL || TLS_SUPPORT */
459 if (pipe (pdi
) == NOTOK
)
460 return sm_ierror ("no pipes");
461 if (pipe (pdo
) == NOTOK
) {
464 return sm_ierror ("no pipes");
467 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
476 return sm_ierror ("unable to fork");
479 if (pdo
[0] != fileno (stdin
))
480 dup2 (pdo
[0], fileno (stdin
));
481 if (pdi
[1] != fileno (stdout
))
482 dup2 (pdi
[1], fileno (stdout
));
483 if (pdi
[1] != fileno (stderr
))
484 dup2 (pdi
[1], fileno (stderr
));
485 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
489 vec
[vecp
++] = r1bindex (sendmail
, '/');
491 vec
[vecp
++] = watch
? "-odi" : "-odb";
492 vec
[vecp
++] = "-oem";
498 execvp (sendmail
, vec
);
499 fprintf (stderr
, "unable to exec ");
501 _exit (-1); /* NOTREACHED */
504 SIGNAL (SIGALRM
, alrmser
);
505 SIGNAL (SIGPIPE
, SIG_IGN
);
509 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
510 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
513 sm_rfp
= sm_wfp
= NULL
;
514 return sm_ierror ("unable to fdopen");
530 result
= smtalk (SM_HELO
, "EHLO %s", client
);
533 if (500 <= result
&& result
<= 599)
534 result
= smtalk (SM_HELO
, "HELO %s", client
);
547 * If the user asked for SASL, then check to see if the SMTP server
548 * supports it. Otherwise, error out (because the SMTP server
549 * might have been spoofed; we don't want to just silently not
554 if (! (server_mechs
= EHLOset("AUTH"))) {
556 return sm_ierror("SMTP server does not support SASL");
559 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
561 return sm_ierror("Requested SASL mech \"%s\" is not in the "
562 "list of supported mechanisms:\n%s",
563 saslmech
, server_mechs
);
566 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
572 #endif /* CYRUS_SASL */
575 smtalk (SM_HELO
, "VERB on");
582 rclient (char *server
, char *service
)
585 char response
[BUFSIZ
];
587 if ((sd
= client (server
, service
, response
, sizeof(response
),
591 sm_ierror ("%s", response
);
596 sm_winit (char *from
)
598 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
615 sm_wadr (char *mbox
, char *host
, char *path
)
617 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
619 path
? path
: "", mbox
, host
)) {
629 #endif /* SENDMAILBUG */
654 switch (smtalk (SM_DATA
, "DATA")) {
663 #endif /* SENDMAILBUG */
680 sm_wtxt (char *buffer
, int len
)
686 result
= sm_wstream (buffer
, len
);
689 return (result
== NOTOK
? RP_BHST
: RP_OK
);
696 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
699 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
707 #endif /* SENDMAILBUG */
725 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
736 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
741 smtalk (SM_QUIT
, "QUIT");
745 sm_note
.code
= sm_reply
.code
;
746 sm_note
.length
= sm_reply
.length
;
747 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
749 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
751 if (sm_mts
== MTS_SMTP
)
752 smtalk (SM_QUIT
, "QUIT");
754 /* The SIGPIPE block replaces old calls to discard ().
755 We're not sure what the discard () calls were for,
756 maybe to prevent deadlock on old systems. In any
757 case, blocking SIGPIPE should be harmless.
758 Because the file handles are closed below, leave it
762 sigaddset (&set
, SIGPIPE
);
763 sigprocmask (SIG_BLOCK
, &set
, &oset
);
765 kill (sm_child
, SIGKILL
);
769 sm_reply
.code
= sm_note
.code
;
770 sm_reply
.length
= sm_note
.length
;
771 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
778 BIO_ssl_shutdown(io
);
781 #endif /* TLS_SUPPORT */
783 if (sm_rfp
!= NULL
) {
788 if (sm_wfp
!= NULL
) {
794 if (sm_mts
== MTS_SMTP
) {
799 if (sasl_outbuffer
) {
800 free(sasl_outbuffer
);
805 #endif /* CYRUS_SASL */
806 } else if (sm_child
!= NOTOK
) {
807 status
= pidwait (sm_child
, OK
);
813 sm_rfp
= sm_wfp
= NULL
;
814 return (status
? RP_BHST
: RP_OK
);
819 * This function implements SASL authentication for SMTP. If this function
820 * completes successfully, then authentication is successful and we've
821 * (optionally) negotiated a security layer.
824 #define CHECKB64SIZE(insize, outbuf, outsize) \
825 { size_t wantout = (((insize + 2) / 3) * 4) + 32; \
826 if (wantout > outsize) { \
827 outbuf = mh_xrealloc(outbuf, outsize = wantout); \
832 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
835 unsigned int buflen
, outlen
;
836 char *buf
, *outbuf
= NULL
, host
[NI_MAXHOST
];
837 const char *chosen_mech
;
838 sasl_security_properties_t secprops
;
841 struct nmh_creds creds
= { 0, 0, 0 };
842 size_t outbufsize
= 0;
845 * Initialize the callback contexts
849 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
850 * to us on the command line, then call getpeername and do a
851 * reverse-address lookup on the IP address to get the name.
854 memset(host
, 0, sizeof(host
));
857 struct sockaddr_storage sin
;
858 socklen_t len
= sizeof(sin
);
861 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
862 sm_ierror("getpeername on SMTP socket failed: %s",
867 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
868 NULL
, 0, NI_NAMEREQD
);
870 sm_ierror("Unable to look up name of connected host: %s",
871 gai_strerror(result
));
875 strncpy(host
, inhost
, sizeof(host
) - 1);
878 /* It's OK to copy the addresses here. The callbacks that use
879 them will only be called before this function returns. */
882 callbacks
[SM_SASL_N_CB_USER
].context
= &creds
;
883 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= &creds
;
884 callbacks
[SM_SASL_N_CB_PASS
].context
= &creds
;
886 result
= sasl_client_init(callbacks
);
888 if (result
!= SASL_OK
) {
889 sm_ierror("SASL library initialization failed: %s",
890 sasl_errstring(result
, NULL
, NULL
));
894 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
896 if (result
!= SASL_OK
) {
897 sm_ierror("SASL client initialization failed: %s",
898 sasl_errstring(result
, NULL
, NULL
));
903 * Initialize the security properties. But if TLS is active, then
904 * don't negotiate encryption here.
907 memset(&secprops
, 0, sizeof(secprops
));
908 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
910 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
912 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
914 if (result
!= SASL_OK
) {
915 sm_ierror("SASL security property initialization failed: %s",
916 sasl_errstring(result
, NULL
, NULL
));
921 * Start the actual protocol. Feed the mech list into the library
922 * and get out a possible initial challenge
925 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
926 &buflen
, (const char **) &chosen_mech
);
928 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
929 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
934 * If we got an initial challenge, send it as part of the AUTH
935 * command; otherwise, just send a plain AUTH command.
939 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
940 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
941 if (status
!= SASL_OK
) {
942 sm_ierror("SASL base64 encode failed: %s",
943 sasl_errstring(status
, NULL
, NULL
));
949 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
951 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
954 * Now we loop until we either fail, get a SASL_OK, or a 235
955 * response code. Receive the challenges and process them until
959 while (result
== SASL_CONTINUE
) {
962 * If we get a 235 response, that means authentication has
963 * succeeded and we need to break out of the loop (yes, even if
964 * we still get SASL_CONTINUE from sasl_client_step()).
966 * Otherwise, if we get a message that doesn't seem to be a
967 * valid response, then abort
972 else if (status
< 300 || status
> 399) {
979 * Special case; a zero-length response from the SMTP server
980 * is returned as a single =. If we get that, then set buflen
981 * to be zero. Otherwise, just decode the response.
984 if (strcmp("=", sm_reply
.text
) == 0) {
987 if (sm_reply
.length
> (int) outbufsize
) {
988 outbuf
= mh_xrealloc(outbuf
, outbufsize
= sm_reply
.length
);
991 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
992 outbuf
, outbufsize
, &outlen
);
993 if (result
!= SASL_OK
) {
994 smtalk(SM_AUTH
, "*");
995 sm_ierror("SASL base64 decode failed: %s",
996 sasl_errstring(result
, NULL
, NULL
));
1003 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
1004 (const char **) &buf
, &buflen
);
1006 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
1007 smtalk(SM_AUTH
, "*");
1008 sm_ierror("SASL client negotiation failed: %s",
1009 sasl_errstring(result
, NULL
, NULL
));
1015 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
1016 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
1018 if (status
!= SASL_OK
) {
1019 smtalk(SM_AUTH
, "*");
1020 sm_ierror("SASL base64 encode failed: %s",
1021 sasl_errstring(status
, NULL
, NULL
));
1027 status
= smtalk(SM_AUTH
, outbuf
);
1034 * Make sure that we got the correct response
1037 if (status
< 200 || status
> 299)
1041 * We _should_ have completed the authentication successfully.
1042 * Get a few properties from the authentication exchange.
1045 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
1047 if (result
!= SASL_OK
) {
1048 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1049 sasl_errstring(result
, NULL
, NULL
));
1053 maxoutbuf
= *outbufmax
;
1055 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
1059 if (result
!= SASL_OK
) {
1060 sm_ierror("Cannot retrieve SASL negotiated security strength "
1061 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
1066 sasl_outbuffer
= malloc(maxoutbuf
);
1068 if (sasl_outbuffer
== NULL
) {
1069 sm_ierror("Unable to allocate %d bytes for SASL output "
1070 "buffer", maxoutbuf
);
1075 sasl_inptr
= sasl_inbuffer
;
1077 sasl_outbuffer
= NULL
;
1078 /* Don't NULL out sasl_inbuffer because it could be used in
1088 * Our callback functions to feed data to the SASL library
1092 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1094 nmh_creds_t creds
= (nmh_creds_t
) context
;
1096 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1097 return SASL_BADPARAM
;
1099 if (creds
->user
== NULL
) {
1101 * Pass the 1 third argument to nmh_get_credentials() so
1102 * that a default user if the -user switch to send(1)/post(8)
1103 * wasn't used, and so that a default password will be supplied.
1104 * That's used when those values really don't matter, and only
1105 * with legacy/.netrc, i.e., with a credentials profile entry.
1107 if (nmh_get_credentials (creds
->host
, creds
->user
, 1, creds
) != OK
) {
1108 return SASL_BADPARAM
;
1112 *result
= creds
->user
;
1114 *len
= strlen(creds
->user
);
1120 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1121 sasl_secret_t
**psecret
)
1123 nmh_creds_t creds
= (nmh_creds_t
) context
;
1128 if (! psecret
|| id
!= SASL_CB_PASS
)
1129 return SASL_BADPARAM
;
1131 if (creds
->password
== NULL
) {
1133 * Pass the 0 third argument to nmh_get_credentials() so
1134 * that the default password isn't used. With legacy/.netrc
1135 * credentials support, we'll only get here if the -user
1136 * switch to send(1)/post(8) wasn't used.
1138 if (nmh_get_credentials (creds
->host
, creds
->user
, 0, creds
) != OK
) {
1139 return SASL_BADPARAM
;
1143 len
= strlen (creds
->password
);
1145 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1149 (*psecret
)->len
= len
;
1150 strcpy((char *) (*psecret
)->data
, creds
->password
);
1154 #endif /* CYRUS_SASL */
1156 /* https://developers.google.com/gmail/xoauth2_protocol */
1158 sm_auth_xoauth2(const char *user
, const char *oauth_svc
, int snoop
)
1160 const char *xoauth_client_res
;
1163 #ifdef OAUTH_SUPPORT
1164 xoauth_client_res
= mh_oauth_do_xoauth(user
, oauth_svc
,
1165 snoop
? stderr
: NULL
);
1167 if (xoauth_client_res
== NULL
) {
1168 return sm_ierror("Internal error: mh_oauth_do_xoauth() returned NULL");
1173 adios(NULL
, "sendfrom built without OAUTH_SUPPORT, "
1174 "so oauth_svc %s is not supported", oauth_svc
);
1175 #endif /* OAUTH_SUPPORT */
1177 status
= smtalk(SM_AUTH
, "AUTH XOAUTH2 %s", xoauth_client_res
);
1178 if (status
== 235) {
1184 * Status is 334 and sm_reply.text contains base64-encoded JSON. As far as
1185 * epg can tell, no matter the error, the JSON is always the same:
1186 * {"status":"400","schemes":"Bearer","scope":"https://mail.google.com/"}
1187 * I tried these errors:
1193 /* Then we're supposed to send an empty response ("\r\n"). */
1194 smtalk(SM_AUTH
, "");
1196 * And now we always get this, again, no matter the error:
1197 * 535-5.7.8 Username and Password not accepted. Learn more at
1198 * 535 5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257
1204 sm_ierror (char *fmt
, ...)
1209 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1212 sm_reply
.length
= strlen (sm_reply
.text
);
1213 sm_reply
.code
= NOTOK
;
1219 smtalk (int time
, char *fmt
, ...)
1224 size_t bufsize
= BUFSIZ
;
1226 buffer
= mh_xmalloc(bufsize
);
1229 result
= vsnprintf (buffer
, bufsize
, fmt
, ap
);
1232 if (result
> (int) bufsize
) {
1233 buffer
= mh_xrealloc(buffer
, bufsize
= result
+ 1);
1235 vsnprintf (buffer
, bufsize
, fmt
, ap
);
1240 char *decoded_buffer
=
1241 prepare_for_display (buffer
, &next_line_encoded
);
1244 printf("(sasl-encrypted) ");
1246 printf("(tls-encrypted) ");
1247 printf ("=> %s\n", decoded_buffer
);
1248 free (decoded_buffer
);
1253 alarm ((unsigned) time
);
1254 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
1265 * write the buffer to the open SMTP channel
1269 sm_wrecord (char *buffer
, int len
)
1272 return sm_werror ();
1274 sm_fwrite (buffer
, len
);
1278 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1283 sm_wstream (char *buffer
, int len
)
1286 static char lc
= '\0';
1289 return sm_werror ();
1291 if (buffer
== NULL
&& len
== 0) {
1295 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1298 for (bp
= buffer
; bp
&& len
> 0; bp
++, len
--) {
1307 sm_fputc ('.');/* FALL THROUGH */
1312 if (ferror (sm_wfp
))
1313 return sm_werror ();
1318 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1322 * Write out to the network, but do buffering for SASL (if enabled)
1326 sm_fwrite(char *buffer
, int len
)
1330 unsigned int outputlen
;
1332 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1333 #endif /* CYRUS_SASL */
1338 ret
= BIO_write(io
, buffer
, len
);
1341 sm_ierror("TLS error during write: %s",
1342 ERR_error_string(ERR_get_error(), NULL
));
1346 #endif /* TLS_SUPPORT */
1347 if ((int) fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
) < len
) {
1348 advise ("sm_fwrite", "fwrite");
1352 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1353 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1354 maxoutbuf
- sasl_outbuflen
);
1355 len
-= maxoutbuf
- sasl_outbuflen
;
1358 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1359 &output
, &outputlen
) != SASL_OK
) {
1360 sm_ierror("Unable to SASL encode connection data: %s",
1361 sasl_errdetail(conn
));
1365 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) <
1367 advise ("sm_fwrite", "fwrite");
1372 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1373 sasl_outbuflen
+= len
;
1376 #endif /* CYRUS_SASL */
1377 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1382 * Negotiate Transport Layer Security
1391 const SSL_METHOD
*method
;
1394 SSL_load_error_strings();
1396 method
= TLSv1_client_method(); /* Not sure about this */
1398 /* Older ssl takes a non-const arg. */
1399 sslctx
= SSL_CTX_new((SSL_METHOD
*) method
);
1403 return sm_ierror("Unable to initialize OpenSSL context: %s",
1404 ERR_error_string(ERR_get_error(), NULL
));
1408 ssl
= SSL_new(sslctx
);
1412 return sm_ierror("Unable to create SSL connection: %s",
1413 ERR_error_string(ERR_get_error(), NULL
));
1416 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
1417 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
1419 if (sbior
== NULL
|| sbiow
== NULL
) {
1421 return sm_ierror("Unable to create BIO endpoints: %s",
1422 ERR_error_string(ERR_get_error(), NULL
));
1425 SSL_set_bio(ssl
, sbior
, sbiow
);
1426 SSL_set_connect_state(ssl
);
1429 * Set up a BIO to handle buffering for us
1432 io
= BIO_new(BIO_f_buffer());
1436 return sm_ierror("Unable to create a buffer BIO: %s",
1437 ERR_error_string(ERR_get_error(), NULL
));
1440 ssl_bio
= BIO_new(BIO_f_ssl());
1444 return sm_ierror("Unable to create a SSL BIO: %s",
1445 ERR_error_string(ERR_get_error(), NULL
));
1448 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1449 BIO_push(io
, ssl_bio
);
1452 * Try doing the handshake now
1455 if (BIO_do_handshake(io
) < 1) {
1457 return sm_ierror("Unable to negotiate SSL connection: %s",
1458 ERR_error_string(ERR_get_error(), NULL
));
1462 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1463 printf("SSL negotiation successful: %s(%d) %s\n",
1464 SSL_CIPHER_get_name(cipher
),
1465 SSL_CIPHER_get_bits(cipher
, NULL
),
1466 SSL_CIPHER_get_version(cipher
));
1474 #endif /* TLS_SUPPORT */
1477 * Convenience functions to replace occurrences of fputs() and fputc()
1481 sm_fputs(char *buffer
)
1483 return sm_fwrite(buffer
, strlen(buffer
));
1491 return sm_fwrite(&h
, 1);
1495 * Flush out any pending data on the connection
1503 unsigned int outputlen
;
1506 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1507 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1508 &output
, &outputlen
);
1509 if (result
!= SASL_OK
) {
1510 sm_ierror("Unable to SASL encode connection data: %s",
1511 sasl_errdetail(conn
));
1515 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) < outputlen
) {
1516 advise ("sm_fflush", "fwrite");
1520 #endif /* CYRUS_SASL */
1524 (void) BIO_flush(io
);
1526 #endif /* TLS_SUPPORT */
1535 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1536 : sm_alarmed
? "write to socket timed out"
1537 : "error writing to socket"));
1539 return (sm_reply
.code
= NOTOK
);
1546 int i
, code
, cont
, bc
= 0, rc
, more
;
1549 char **ehlo
= EHLOkeys
, buffer
[BUFSIZ
];
1552 static int at_least_once
= 0;
1554 if (at_least_once
) {
1557 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1571 sm_reply
.length
= 0;
1572 sm_reply
.text
[0] = 0;
1574 rc
= sizeof(sm_reply
.text
) - 1;
1576 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1579 char *decoded_buffer
=
1580 prepare_for_display (buffer
, &next_line_encoded
);
1583 printf("(sasl-decrypted) ");
1585 printf("(tls-decrypted) ");
1586 printf ("<= %s\n", decoded_buffer
);
1587 free (decoded_buffer
);
1592 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1593 && (buffer
[3] == '-' || doingEHLO
== 2)
1595 if (doingEHLO
== 2) {
1596 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1597 strcpy (*ehlo
++, buffer
+ 4);
1599 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1609 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1613 code
= atoi ((char *) bp
);
1615 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1617 if (bc
> 0 && *bp
== '-') {
1620 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1625 if (code
!= sm_reply
.code
|| cont
)
1629 sm_reply
.code
= code
;
1632 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1633 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1634 bp
= (unsigned char *) buffer
;
1635 bc
= strlen (sm_noreply
);
1639 if ((i
= min (bc
, rc
)) > 0) {
1643 i
= strlen(sm_moreply
);
1644 if (more
&& rc
> i
+ 1) {
1645 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1652 if (sm_reply
.code
< 100) {
1654 printf ("%s\n", sm_reply
.text
);
1660 sm_reply
.length
= rp
- sm_reply
.text
;
1661 sm_reply
.text
[sm_reply
.length
] = 0;
1662 return sm_reply
.code
;
1669 sm_rrecord (char *buffer
, int *len
)
1674 return sm_rerror(0);
1676 buffer
[*len
= 0] = 0;
1678 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1679 return sm_rerror (retval
);
1680 *len
= strlen (buffer
);
1681 /* *len should be >0 except on EOF, but check for safety's sake */
1683 return sm_rerror (RP_EOF
);
1684 if (buffer
[*len
- 1] != '\n')
1685 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1689 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1698 * Our version of fgets, which calls our private fgetc function
1702 sm_fgets(char *buffer
, int size
, FILE *f
)
1716 } while (size
> 1 && c
!= '\n');
1724 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1726 * Read from the network, but do SASL or TLS encryption
1732 char tmpbuf
[BUFSIZ
], *retbuf
;
1733 unsigned int retbufsize
= 0;
1737 * If we have leftover data, return it
1740 if (sasl_inbuflen
) {
1742 return (int) *sasl_inptr
++;
1746 * If not, read from the network until we have some data to return
1749 while (retbufsize
== 0) {
1753 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1756 result
= SSL_get_error(ssl
, cc
);
1758 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1759 sm_ierror("TLS peer aborted connection");
1766 sm_ierror("SSL_read failed: %s",
1767 ERR_error_string(ERR_get_error(), NULL
));
1771 #endif /* TLS_SUPPORT */
1773 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1779 sm_ierror("Unable to read from network: %s", strerror(errno
));
1784 * Don't call sasl_decode unless sasl is complete and we have
1785 * encryption working
1789 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1793 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1796 if (result
!= SASL_OK
) {
1797 sm_ierror("Unable to decode SASL network data: %s",
1798 sasl_errdetail(conn
));
1802 #else /* ! CYRUS_SASL */
1805 #endif /* CYRUS_SASL */
1808 if (retbufsize
> SASL_MAXRECVBUF
) {
1809 sm_ierror("Received data (%d bytes) is larger than the buffer "
1810 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1814 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1815 sasl_inptr
= sasl_inbuffer
+ 1;
1816 sasl_inbuflen
= retbufsize
- 1;
1818 return (int) sasl_inbuffer
[0];
1820 #endif /* CYRUS_SASL || TLS_SUPPORT */
1825 if (sm_mts
== MTS_SMTP
)
1827 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1828 : sm_alarmed
? "read from socket timed out"
1829 : rc
== RP_EOF
? "premature end-of-file on socket"
1830 : "error reading from socket"));
1833 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1834 : sm_alarmed
? "read from pipe timed out"
1835 : rc
== RP_EOF
? "premature end-of-file on pipe"
1836 : "error reading from pipe"));
1838 return (sm_reply
.code
= NOTOK
);
1847 #ifndef RELIABLE_SIGNALS
1848 SIGNAL (SIGALRM
, alrmser
);
1853 printf ("timed out...\n");
1860 rp_string (int code
)
1863 static char buffer
[BUFSIZ
];
1865 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1885 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1905 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1906 text
, sm_reply
.code
, sm_reply
.text
);
1918 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1920 if (strncmp (ep
, s
, len
) == 0) {
1921 for (ep
+= len
; *ep
== ' '; ep
++)
1932 * Detects, using heuristics, if an SMTP server or client response string
1933 * contains a base64-encoded portion. If it does, decodes it and replaces
1934 * any non-printable characters with a hex representation. Caller is
1935 * responsible for free'ing return value. If the decode fails, a copy of
1936 * the input string is returned.
1940 prepare_for_display (const char *string
, int *next_line_encoded
) {
1941 const char *start
= NULL
;
1942 const char *decoded
;
1944 int prefix_len
= -1;
1946 if (strncmp (string
, "AUTH ", 5) == 0) {
1947 /* AUTH line: the mechanism isn't encoded. If there's an initial
1948 response, it must be base64 encoded.. */
1949 char *mechanism
= strchr (string
+ 5, ' ');
1951 if (mechanism
!= NULL
) {
1952 prefix_len
= (int) (mechanism
- string
+ 1);
1953 } /* else no space following the mechanism, so no initial response */
1954 *next_line_encoded
= 0;
1955 } else if (strncmp (string
, "334 ", 4) == 0) {
1956 /* 334 is the server's request for user or password. */
1958 /* The next (client response) line must be base64 encoded. */
1959 *next_line_encoded
= 1;
1960 } else if (*next_line_encoded
) {
1961 /* "next" line now refers to this line, which is a base64-encoded
1964 *next_line_encoded
= 0;
1966 *next_line_encoded
= 0;
1969 /* Don't attempt to decoded unencoded initial response ('=') or cancel
1971 if (prefix_len
> -1 &&
1972 string
[prefix_len
] != '=' && string
[prefix_len
] != '*') {
1973 start
= string
+ prefix_len
;
1976 if (start
&& decodeBase64 (start
, &decoded
, &decoded_len
, 1, NULL
) == OK
) {
1978 char *prefix
= mh_xmalloc(prefix_len
+ 1);
1979 char *display_string
;
1981 /* prefix is the beginning portion, which isn't base64 encoded. */
1982 snprintf (prefix
, prefix_len
+ 1, "%*s", prefix_len
, string
);
1983 hexify ((const unsigned char *) decoded
, decoded_len
, &hexified
);
1984 /* Wrap the decoded portion in "b64<>". */
1985 display_string
= concat (prefix
, "b64<", hexified
, ">", NULL
);
1988 free ((char *) decoded
);
1990 return display_string
;
1992 return getcpy (string
);