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 static int sm_addrs
= 0;
82 static int sm_alarmed
= 0;
83 static int sm_child
= NOTOK
;
84 static int sm_debug
= 0;
85 static int sm_nl
= TRUE
;
86 static int sm_verbose
= 0;
88 static FILE *sm_rfp
= NULL
;
89 static FILE *sm_wfp
= NULL
;
91 static int next_line_encoded
= 0;
95 * Some globals needed by SASL
98 static sasl_conn_t
*conn
= NULL
; /* SASL connection state */
99 static int sasl_complete
= 0; /* Has authentication succeeded? */
100 static sasl_ssf_t sasl_ssf
; /* Our security strength factor */
101 static int maxoutbuf
; /* Maximum crypto output buffer */
102 static char *sasl_outbuffer
; /* SASL output buffer for encryption */
103 static int sasl_outbuflen
; /* Current length of data in outbuf */
104 static int sm_get_user(void *, int, const char **, unsigned *);
105 static int sm_get_pass(sasl_conn_t
*, void *, int, sasl_secret_t
**);
107 static sasl_callback_t callbacks
[] = {
108 { SASL_CB_USER
, (sasl_callback_ft
) sm_get_user
, NULL
},
109 #define SM_SASL_N_CB_USER 0
110 { SASL_CB_AUTHNAME
, (sasl_callback_ft
) sm_get_user
, NULL
},
111 #define SM_SASL_N_CB_AUTHNAME 1
112 { SASL_CB_PASS
, (sasl_callback_ft
) sm_get_pass
, NULL
},
113 #define SM_SASL_N_CB_PASS 2
114 { SASL_CB_LIST_END
, NULL
, NULL
},
117 #else /* CYRUS_SASL */
119 #endif /* CYRUS_SASL */
122 static SSL_CTX
*sslctx
= NULL
;
123 static SSL
*ssl
= NULL
;
124 static BIO
*sbior
= NULL
;
125 static BIO
*sbiow
= NULL
;
126 static BIO
*io
= NULL
;
128 static int tls_negotiate(void);
129 #endif /* TLS_SUPPORT */
131 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
132 #define SASL_MAXRECVBUF 65536
133 static int sm_fgetc(FILE *);
134 static char *sasl_inbuffer
; /* SASL input buffer for encryption */
135 static char *sasl_inptr
; /* Pointer to current inbuf position */
136 static int sasl_inbuflen
; /* Current length of data in inbuf */
138 #define sm_fgetc fgetc
141 static int tls_active
= 0;
143 static char *sm_noreply
= "No reply text given";
144 static char *sm_moreply
= "; ";
145 static struct smtp sm_reply
;
149 static int doingEHLO
;
150 static char *EHLOkeys
[MAXEHLO
+ 1];
155 static int smtp_init (char *, char *, char *, int, int, int, int, int,
156 char *, char *, const char *, int);
157 static int sendmail_init (char *, char *, int, int, int, int, int,
160 static int rclient (char *, char *);
161 static int sm_ierror (char *fmt
, ...);
162 static int smtalk (int time
, char *fmt
, ...);
163 static int sm_wrecord (char *, int);
164 static int sm_wstream (char *, int);
165 static int sm_werror (void);
166 static int smhear (void);
167 static int sm_rrecord (char *, int *);
168 static int sm_rerror (int);
169 static void alrmser (int);
170 static char *EHLOset (char *);
171 static char *prepare_for_display (const char *, int *);
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 *);
177 static int sm_auth_xoauth2(const char *);
181 * Function prototypes needed for SASL
184 static int sm_auth_sasl(char *, int, char *, char *);
185 #endif /* CYRUS_SASL */
188 sm_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
189 int debug
, int sasl
, int saslssf
, char *saslmech
, char *user
,
190 const char *xoauth_client_res
, int tls
)
192 if (sm_mts
== MTS_SMTP
)
193 return smtp_init (client
, server
, port
, watch
, verbose
,
194 debug
, sasl
, saslssf
, saslmech
, user
,
195 xoauth_client_res
, tls
);
197 return sendmail_init (client
, server
, watch
, verbose
,
198 debug
, sasl
, saslssf
, saslmech
, user
);
202 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
204 int sasl
, int saslssf
, char *saslmech
, char *user
,
205 const char *xoauth_client_res
, int tls
)
207 int result
, sd1
, sd2
;
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
369 if (! (server_mechs
= EHLOset("AUTH"))) {
371 return sm_ierror("SMTP server does not support SASL");
374 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
376 return sm_ierror("Requested SASL mech \"%s\" is not in the "
377 "list of supported mechanisms:\n%s",
378 saslmech
, server_mechs
);
381 /* Don't call sm_auth_sasl() for XAUTH2 with -sasl. Instead, call
382 sm_auth_xoauth2() below. */
383 if (xoauth_client_res
== NULL
&&
384 sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
390 #endif /* CYRUS_SASL */
392 if (xoauth_client_res
!= NULL
) {
394 if ((server_mechs
= EHLOset("AUTH")) == NULL
395 || stringdex("XOAUTH2", server_mechs
) == -1) {
397 return sm_ierror("SMTP server does not support SASL XOAUTH2");
399 if (sm_auth_xoauth2(xoauth_client_res
) != RP_OK
) {
406 if (watch
&& EHLOset ("XVRB"))
407 smtalk (SM_HELO
, "VERB on");
413 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
414 int debug
, int sasl
, int saslssf
, char *saslmech
, char *user
)
416 unsigned int i
, result
, vecp
;
421 #else /* CYRUS_SASL */
424 NMH_UNUSED (saslssf
);
425 NMH_UNUSED (saslmech
);
427 #endif /* CYRUS_SASL */
432 sm_verbose
= verbose
;
434 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
437 if (client
== NULL
|| *client
== '\0') {
441 client
= LocalName(1); /* no clientname -> LocalName */
445 * Last-ditch check just in case client still isn't set to anything
448 if (client
== NULL
|| *client
== '\0')
449 client
= "localhost";
451 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
452 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
454 return sm_ierror("Unable to allocate %d bytes for read buffer",
456 #endif /* CYRUS_SASL || TLS_SUPPORT */
458 if (pipe (pdi
) == NOTOK
)
459 return sm_ierror ("no pipes");
460 if (pipe (pdo
) == NOTOK
) {
463 return sm_ierror ("no pipes");
466 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
475 return sm_ierror ("unable to fork");
478 if (pdo
[0] != fileno (stdin
))
479 dup2 (pdo
[0], fileno (stdin
));
480 if (pdi
[1] != fileno (stdout
))
481 dup2 (pdi
[1], fileno (stdout
));
482 if (pdi
[1] != fileno (stderr
))
483 dup2 (pdi
[1], fileno (stderr
));
484 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
488 vec
[vecp
++] = r1bindex (sendmail
, '/');
490 vec
[vecp
++] = watch
? "-odi" : "-odb";
491 vec
[vecp
++] = "-oem";
497 execvp (sendmail
, vec
);
498 fprintf (stderr
, "unable to exec ");
500 _exit (-1); /* NOTREACHED */
503 SIGNAL (SIGALRM
, alrmser
);
504 SIGNAL (SIGPIPE
, SIG_IGN
);
508 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
509 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
512 sm_rfp
= sm_wfp
= NULL
;
513 return sm_ierror ("unable to fdopen");
529 result
= smtalk (SM_HELO
, "EHLO %s", client
);
532 if (500 <= result
&& result
<= 599)
533 result
= smtalk (SM_HELO
, "HELO %s", client
);
546 * If the user asked for SASL, then check to see if the SMTP server
547 * supports it. Otherwise, error out (because the SMTP server
548 * might have been spoofed; we don't want to just silently not
553 if (! (server_mechs
= EHLOset("AUTH"))) {
555 return sm_ierror("SMTP server does not support SASL");
558 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
560 return sm_ierror("Requested SASL mech \"%s\" is not in the "
561 "list of supported mechanisms:\n%s",
562 saslmech
, server_mechs
);
565 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
571 #endif /* CYRUS_SASL */
574 smtalk (SM_HELO
, "VERB on");
581 rclient (char *server
, char *service
)
584 char response
[BUFSIZ
];
586 if ((sd
= client (server
, service
, response
, sizeof(response
),
590 sm_ierror ("%s", response
);
595 sm_winit (char *from
)
597 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
614 sm_wadr (char *mbox
, char *host
, char *path
)
616 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
618 path
? path
: "", mbox
, host
)) {
628 #endif /* SENDMAILBUG */
653 switch (smtalk (SM_DATA
, "DATA")) {
662 #endif /* SENDMAILBUG */
679 sm_wtxt (char *buffer
, int len
)
685 result
= sm_wstream (buffer
, len
);
688 return (result
== NOTOK
? RP_BHST
: RP_OK
);
695 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
698 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
706 #endif /* SENDMAILBUG */
724 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
735 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
740 smtalk (SM_QUIT
, "QUIT");
744 sm_note
.code
= sm_reply
.code
;
745 sm_note
.length
= sm_reply
.length
;
746 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
748 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
750 if (sm_mts
== MTS_SMTP
)
751 smtalk (SM_QUIT
, "QUIT");
753 /* The SIGPIPE block replaces old calls to discard ().
754 We're not sure what the discard () calls were for,
755 maybe to prevent deadlock on old systems. In any
756 case, blocking SIGPIPE should be harmless.
757 Because the file handles are closed below, leave it
761 sigaddset (&set
, SIGPIPE
);
762 sigprocmask (SIG_BLOCK
, &set
, &oset
);
764 kill (sm_child
, SIGKILL
);
768 sm_reply
.code
= sm_note
.code
;
769 sm_reply
.length
= sm_note
.length
;
770 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
777 BIO_ssl_shutdown(io
);
780 #endif /* TLS_SUPPORT */
782 if (sm_rfp
!= NULL
) {
787 if (sm_wfp
!= NULL
) {
793 if (sm_mts
== MTS_SMTP
) {
798 if (sasl_outbuffer
) {
799 free(sasl_outbuffer
);
804 #endif /* CYRUS_SASL */
805 } else if (sm_child
!= NOTOK
) {
806 status
= pidwait (sm_child
, OK
);
812 sm_rfp
= sm_wfp
= NULL
;
813 return (status
? RP_BHST
: RP_OK
);
818 * This function implements SASL authentication for SMTP. If this function
819 * completes successfully, then authentication is successful and we've
820 * (optionally) negotiated a security layer.
823 #define CHECKB64SIZE(insize, outbuf, outsize) \
824 { size_t wantout = (((insize + 2) / 3) * 4) + 32; \
825 if (wantout > outsize) { \
826 outbuf = mh_xrealloc(outbuf, outsize = wantout); \
831 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
834 unsigned int buflen
, outlen
;
835 char *buf
, *outbuf
= NULL
, host
[NI_MAXHOST
];
836 const char *chosen_mech
;
837 sasl_security_properties_t secprops
;
840 struct nmh_creds creds
= { 0, 0, 0 };
841 size_t outbufsize
= 0;
844 * Initialize the callback contexts
848 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
849 * to us on the command line, then call getpeername and do a
850 * reverse-address lookup on the IP address to get the name.
853 memset(host
, 0, sizeof(host
));
856 struct sockaddr_storage sin
;
857 socklen_t len
= sizeof(sin
);
860 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
861 sm_ierror("getpeername on SMTP socket failed: %s",
866 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
867 NULL
, 0, NI_NAMEREQD
);
869 sm_ierror("Unable to look up name of connected host: %s",
870 gai_strerror(result
));
874 strncpy(host
, inhost
, sizeof(host
) - 1);
877 /* It's OK to copy the addresses here. The callbacks that use
878 them will only be called before this function returns. */
881 callbacks
[SM_SASL_N_CB_USER
].context
= &creds
;
882 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= &creds
;
883 callbacks
[SM_SASL_N_CB_PASS
].context
= &creds
;
885 result
= sasl_client_init(callbacks
);
887 if (result
!= SASL_OK
) {
888 sm_ierror("SASL library initialization failed: %s",
889 sasl_errstring(result
, NULL
, NULL
));
893 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
895 if (result
!= SASL_OK
) {
896 sm_ierror("SASL client initialization failed: %s",
897 sasl_errstring(result
, NULL
, NULL
));
902 * Initialize the security properties. But if TLS is active, then
903 * don't negotiate encryption here.
906 memset(&secprops
, 0, sizeof(secprops
));
907 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
909 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
911 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
913 if (result
!= SASL_OK
) {
914 sm_ierror("SASL security property initialization failed: %s",
915 sasl_errstring(result
, NULL
, NULL
));
920 * Start the actual protocol. Feed the mech list into the library
921 * and get out a possible initial challenge
924 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
925 &buflen
, (const char **) &chosen_mech
);
927 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
928 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
933 * If we got an initial challenge, send it as part of the AUTH
934 * command; otherwise, just send a plain AUTH command.
938 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
939 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
940 if (status
!= SASL_OK
) {
941 sm_ierror("SASL base64 encode failed: %s",
942 sasl_errstring(status
, NULL
, NULL
));
948 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
950 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
953 * Now we loop until we either fail, get a SASL_OK, or a 235
954 * response code. Receive the challenges and process them until
958 while (result
== SASL_CONTINUE
) {
961 * If we get a 235 response, that means authentication has
962 * succeeded and we need to break out of the loop (yes, even if
963 * we still get SASL_CONTINUE from sasl_client_step()).
965 * Otherwise, if we get a message that doesn't seem to be a
966 * valid response, then abort
971 else if (status
< 300 || status
> 399) {
978 * Special case; a zero-length response from the SMTP server
979 * is returned as a single =. If we get that, then set buflen
980 * to be zero. Otherwise, just decode the response.
983 if (strcmp("=", sm_reply
.text
) == 0) {
986 if (sm_reply
.length
> (int) outbufsize
) {
987 outbuf
= mh_xrealloc(outbuf
, outbufsize
= sm_reply
.length
);
990 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
991 outbuf
, outbufsize
, &outlen
);
992 if (result
!= SASL_OK
) {
993 smtalk(SM_AUTH
, "*");
994 sm_ierror("SASL base64 decode failed: %s",
995 sasl_errstring(result
, NULL
, NULL
));
1002 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
1003 (const char **) &buf
, &buflen
);
1005 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
1006 smtalk(SM_AUTH
, "*");
1007 sm_ierror("SASL client negotiation failed: %s",
1008 sasl_errstring(result
, NULL
, NULL
));
1014 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
1015 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
1017 if (status
!= SASL_OK
) {
1018 smtalk(SM_AUTH
, "*");
1019 sm_ierror("SASL base64 encode failed: %s",
1020 sasl_errstring(status
, NULL
, NULL
));
1026 status
= smtalk(SM_AUTH
, outbuf
);
1033 * Make sure that we got the correct response
1036 if (status
< 200 || status
> 299)
1040 * We _should_ have completed the authentication successfully.
1041 * Get a few properties from the authentication exchange.
1044 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
1046 if (result
!= SASL_OK
) {
1047 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
1048 sasl_errstring(result
, NULL
, NULL
));
1052 maxoutbuf
= *outbufmax
;
1054 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
1058 if (result
!= SASL_OK
) {
1059 sm_ierror("Cannot retrieve SASL negotiated security strength "
1060 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
1065 sasl_outbuffer
= malloc(maxoutbuf
);
1067 if (sasl_outbuffer
== NULL
) {
1068 sm_ierror("Unable to allocate %d bytes for SASL output "
1069 "buffer", maxoutbuf
);
1074 sasl_inptr
= sasl_inbuffer
;
1076 sasl_outbuffer
= NULL
;
1077 /* Don't NULL out sasl_inbuffer because it could be used in
1087 * Our callback functions to feed data to the SASL library
1091 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1093 nmh_creds_t creds
= (nmh_creds_t
) context
;
1095 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1096 return SASL_BADPARAM
;
1098 if (creds
->user
== NULL
) {
1100 * Pass the 1 third argument to nmh_get_credentials() so
1101 * that a default user if the -user switch to send(1)/post(8)
1102 * wasn't used, and so that a default password will be supplied.
1103 * That's used when those values really don't matter, and only
1104 * with legacy/.netrc, i.e., with a credentials profile entry.
1106 if (nmh_get_credentials (creds
->host
, creds
->user
, 1, creds
) != OK
) {
1107 return SASL_BADPARAM
;
1111 *result
= creds
->user
;
1113 *len
= strlen(creds
->user
);
1119 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1120 sasl_secret_t
**psecret
)
1122 nmh_creds_t creds
= (nmh_creds_t
) context
;
1127 if (! psecret
|| id
!= SASL_CB_PASS
)
1128 return SASL_BADPARAM
;
1130 if (creds
->password
== NULL
) {
1132 * Pass the 0 third argument to nmh_get_credentials() so
1133 * that the default password isn't used. With legacy/.netrc
1134 * credentials support, we'll only get here if the -user
1135 * switch to send(1)/post(8) wasn't used.
1137 if (nmh_get_credentials (creds
->host
, creds
->user
, 0, creds
) != OK
) {
1138 return SASL_BADPARAM
;
1142 len
= strlen (creds
->password
);
1144 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1148 (*psecret
)->len
= len
;
1149 strcpy((char *) (*psecret
)->data
, creds
->password
);
1153 #endif /* CYRUS_SASL */
1155 /* https://developers.google.com/gmail/xoauth2_protocol */
1157 sm_auth_xoauth2(const char *client_res
)
1159 int status
= smtalk(SM_AUTH
, "AUTH XOAUTH2 %s", client_res
);
1160 if (status
== 235) {
1166 * Status is 334 and sm_reply.text contains base64-encoded JSON. As far as
1167 * epg can tell, no matter the error, the JSON is always the same:
1168 * {"status":"400","schemes":"Bearer","scope":"https://mail.google.com/"}
1169 * I tried these errors:
1175 /* Then we're supposed to send an empty response ("\r\n"). */
1176 smtalk(SM_AUTH
, "");
1178 * And now we always get this, again, no matter the error:
1179 * 535-5.7.8 Username and Password not accepted. Learn more at
1180 * 535 5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257
1186 sm_ierror (char *fmt
, ...)
1191 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1194 sm_reply
.length
= strlen (sm_reply
.text
);
1195 sm_reply
.code
= NOTOK
;
1201 smtalk (int time
, char *fmt
, ...)
1206 size_t bufsize
= BUFSIZ
;
1208 buffer
= mh_xmalloc(bufsize
);
1211 result
= vsnprintf (buffer
, bufsize
, fmt
, ap
);
1214 if (result
> (int) bufsize
) {
1215 buffer
= mh_xrealloc(buffer
, bufsize
= result
+ 1);
1217 vsnprintf (buffer
, bufsize
, fmt
, ap
);
1222 char *decoded_buffer
=
1223 prepare_for_display (buffer
, &next_line_encoded
);
1226 printf("(sasl-encrypted) ");
1228 printf("(tls-encrypted) ");
1229 printf ("=> %s\n", decoded_buffer
);
1230 free (decoded_buffer
);
1235 alarm ((unsigned) time
);
1236 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
1247 * write the buffer to the open SMTP channel
1251 sm_wrecord (char *buffer
, int len
)
1254 return sm_werror ();
1256 sm_fwrite (buffer
, len
);
1260 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1265 sm_wstream (char *buffer
, int len
)
1268 static char lc
= '\0';
1271 return sm_werror ();
1273 if (buffer
== NULL
&& len
== 0) {
1277 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1280 for (bp
= buffer
; bp
&& len
> 0; bp
++, len
--) {
1289 sm_fputc ('.');/* FALL THROUGH */
1294 if (ferror (sm_wfp
))
1295 return sm_werror ();
1300 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1304 * Write out to the network, but do buffering for SASL (if enabled)
1308 sm_fwrite(char *buffer
, int len
)
1312 unsigned int outputlen
;
1314 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1315 #endif /* CYRUS_SASL */
1320 ret
= BIO_write(io
, buffer
, len
);
1323 sm_ierror("TLS error during write: %s",
1324 ERR_error_string(ERR_get_error(), NULL
));
1328 #endif /* TLS_SUPPORT */
1329 if ((int) fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
) < len
) {
1330 advise ("sm_fwrite", "fwrite");
1334 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1335 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1336 maxoutbuf
- sasl_outbuflen
);
1337 len
-= maxoutbuf
- sasl_outbuflen
;
1340 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1341 &output
, &outputlen
) != SASL_OK
) {
1342 sm_ierror("Unable to SASL encode connection data: %s",
1343 sasl_errdetail(conn
));
1347 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) <
1349 advise ("sm_fwrite", "fwrite");
1354 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1355 sasl_outbuflen
+= len
;
1358 #endif /* CYRUS_SASL */
1359 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1364 * Negotiate Transport Layer Security
1373 const SSL_METHOD
*method
;
1376 SSL_load_error_strings();
1378 method
= TLSv1_client_method(); /* Not sure about this */
1380 /* Older ssl takes a non-const arg. */
1381 sslctx
= SSL_CTX_new((SSL_METHOD
*) method
);
1385 return sm_ierror("Unable to initialize OpenSSL context: %s",
1386 ERR_error_string(ERR_get_error(), NULL
));
1390 ssl
= SSL_new(sslctx
);
1394 return sm_ierror("Unable to create SSL connection: %s",
1395 ERR_error_string(ERR_get_error(), NULL
));
1398 sbior
= BIO_new_socket(fileno(sm_rfp
), BIO_NOCLOSE
);
1399 sbiow
= BIO_new_socket(fileno(sm_wfp
), BIO_NOCLOSE
);
1401 if (sbior
== NULL
|| sbiow
== NULL
) {
1403 return sm_ierror("Unable to create BIO endpoints: %s",
1404 ERR_error_string(ERR_get_error(), NULL
));
1407 SSL_set_bio(ssl
, sbior
, sbiow
);
1408 SSL_set_connect_state(ssl
);
1411 * Set up a BIO to handle buffering for us
1414 io
= BIO_new(BIO_f_buffer());
1418 return sm_ierror("Unable to create a buffer BIO: %s",
1419 ERR_error_string(ERR_get_error(), NULL
));
1422 ssl_bio
= BIO_new(BIO_f_ssl());
1426 return sm_ierror("Unable to create a SSL BIO: %s",
1427 ERR_error_string(ERR_get_error(), NULL
));
1430 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1431 BIO_push(io
, ssl_bio
);
1434 * Try doing the handshake now
1437 if (BIO_do_handshake(io
) < 1) {
1439 return sm_ierror("Unable to negotiate SSL connection: %s",
1440 ERR_error_string(ERR_get_error(), NULL
));
1444 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1445 printf("SSL negotiation successful: %s(%d) %s\n",
1446 SSL_CIPHER_get_name(cipher
),
1447 SSL_CIPHER_get_bits(cipher
, NULL
),
1448 SSL_CIPHER_get_version(cipher
));
1456 #endif /* TLS_SUPPORT */
1459 * Convenience functions to replace occurrences of fputs() and fputc()
1463 sm_fputs(char *buffer
)
1465 return sm_fwrite(buffer
, strlen(buffer
));
1473 return sm_fwrite(&h
, 1);
1477 * Flush out any pending data on the connection
1485 unsigned int outputlen
;
1488 if (sasl_complete
== 1 && sasl_ssf
> 0 && sasl_outbuflen
> 0) {
1489 result
= sasl_encode(conn
, sasl_outbuffer
, sasl_outbuflen
,
1490 &output
, &outputlen
);
1491 if (result
!= SASL_OK
) {
1492 sm_ierror("Unable to SASL encode connection data: %s",
1493 sasl_errdetail(conn
));
1497 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) < outputlen
) {
1498 advise ("sm_fflush", "fwrite");
1502 #endif /* CYRUS_SASL */
1506 (void) BIO_flush(io
);
1508 #endif /* TLS_SUPPORT */
1517 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1518 : sm_alarmed
? "write to socket timed out"
1519 : "error writing to socket"));
1521 return (sm_reply
.code
= NOTOK
);
1528 int i
, code
, cont
, bc
= 0, rc
, more
;
1531 char **ehlo
= EHLOkeys
, buffer
[BUFSIZ
];
1534 static int at_least_once
= 0;
1536 if (at_least_once
) {
1539 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1553 sm_reply
.length
= 0;
1554 sm_reply
.text
[0] = 0;
1556 rc
= sizeof(sm_reply
.text
) - 1;
1558 for (more
= FALSE
; sm_rrecord ((char *) (bp
= (unsigned char *) buffer
),
1561 char *decoded_buffer
=
1562 prepare_for_display (buffer
, &next_line_encoded
);
1565 printf("(sasl-decrypted) ");
1567 printf("(tls-decrypted) ");
1568 printf ("<= %s\n", decoded_buffer
);
1569 free (decoded_buffer
);
1574 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1575 && (buffer
[3] == '-' || doingEHLO
== 2)
1577 if (doingEHLO
== 2) {
1578 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1579 strcpy (*ehlo
++, buffer
+ 4);
1581 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1591 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1595 code
= atoi ((char *) bp
);
1597 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1599 if (bc
> 0 && *bp
== '-') {
1602 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1607 if (code
!= sm_reply
.code
|| cont
)
1611 sm_reply
.code
= code
;
1614 /* can never fail to 0-terminate because of size of buffer vs fixed string */
1615 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1616 bp
= (unsigned char *) buffer
;
1617 bc
= strlen (sm_noreply
);
1621 if ((i
= min (bc
, rc
)) > 0) {
1625 i
= strlen(sm_moreply
);
1626 if (more
&& rc
> i
+ 1) {
1627 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1634 if (sm_reply
.code
< 100) {
1636 printf ("%s\n", sm_reply
.text
);
1642 sm_reply
.length
= rp
- sm_reply
.text
;
1643 sm_reply
.text
[sm_reply
.length
] = 0;
1644 return sm_reply
.code
;
1651 sm_rrecord (char *buffer
, int *len
)
1656 return sm_rerror(0);
1658 buffer
[*len
= 0] = 0;
1660 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1661 return sm_rerror (retval
);
1662 *len
= strlen (buffer
);
1663 /* *len should be >0 except on EOF, but check for safety's sake */
1665 return sm_rerror (RP_EOF
);
1666 if (buffer
[*len
- 1] != '\n')
1667 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1671 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1680 * Our version of fgets, which calls our private fgetc function
1684 sm_fgets(char *buffer
, int size
, FILE *f
)
1698 } while (size
> 1 && c
!= '\n');
1706 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1708 * Read from the network, but do SASL or TLS encryption
1714 char tmpbuf
[BUFSIZ
], *retbuf
;
1715 unsigned int retbufsize
= 0;
1719 * If we have leftover data, return it
1722 if (sasl_inbuflen
) {
1724 return (int) *sasl_inptr
++;
1728 * If not, read from the network until we have some data to return
1731 while (retbufsize
== 0) {
1735 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1738 result
= SSL_get_error(ssl
, cc
);
1740 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1741 sm_ierror("TLS peer aborted connection");
1748 sm_ierror("SSL_read failed: %s",
1749 ERR_error_string(ERR_get_error(), NULL
));
1753 #endif /* TLS_SUPPORT */
1755 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1761 sm_ierror("Unable to read from network: %s", strerror(errno
));
1766 * Don't call sasl_decode unless sasl is complete and we have
1767 * encryption working
1771 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1775 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1778 if (result
!= SASL_OK
) {
1779 sm_ierror("Unable to decode SASL network data: %s",
1780 sasl_errdetail(conn
));
1784 #else /* ! CYRUS_SASL */
1787 #endif /* CYRUS_SASL */
1790 if (retbufsize
> SASL_MAXRECVBUF
) {
1791 sm_ierror("Received data (%d bytes) is larger than the buffer "
1792 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1796 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1797 sasl_inptr
= sasl_inbuffer
+ 1;
1798 sasl_inbuflen
= retbufsize
- 1;
1800 return (int) sasl_inbuffer
[0];
1802 #endif /* CYRUS_SASL || TLS_SUPPORT */
1807 if (sm_mts
== MTS_SMTP
)
1809 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1810 : sm_alarmed
? "read from socket timed out"
1811 : rc
== RP_EOF
? "premature end-of-file on socket"
1812 : "error reading from socket"));
1815 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1816 : sm_alarmed
? "read from pipe timed out"
1817 : rc
== RP_EOF
? "premature end-of-file on pipe"
1818 : "error reading from pipe"));
1820 return (sm_reply
.code
= NOTOK
);
1829 #ifndef RELIABLE_SIGNALS
1830 SIGNAL (SIGALRM
, alrmser
);
1835 printf ("timed out...\n");
1842 rp_string (int code
)
1845 static char buffer
[BUFSIZ
];
1847 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1867 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1887 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1888 text
, sm_reply
.code
, sm_reply
.text
);
1900 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1902 if (strncmp (ep
, s
, len
) == 0) {
1903 for (ep
+= len
; *ep
== ' '; ep
++)
1914 * Detects, using heuristics, if an SMTP server or client response string
1915 * contains a base64-encoded portion. If it does, decodes it and replaces
1916 * any non-printable characters with a hex representation. Caller is
1917 * responsible for free'ing return value. If the decode fails, a copy of
1918 * the input string is returned.
1922 prepare_for_display (const char *string
, int *next_line_encoded
) {
1923 const char *start
= NULL
;
1924 const char *decoded
;
1926 int prefix_len
= -1;
1928 if (strncmp (string
, "AUTH ", 5) == 0) {
1929 /* AUTH line: the mechanism isn't encoded. If there's an initial
1930 response, it must be base64 encoded.. */
1931 char *mechanism
= strchr (string
+ 5, ' ');
1933 if (mechanism
!= NULL
) {
1934 prefix_len
= (int) (mechanism
- string
+ 1);
1935 } /* else no space following the mechanism, so no initial response */
1936 *next_line_encoded
= 0;
1937 } else if (strncmp (string
, "334 ", 4) == 0) {
1938 /* 334 is the server's request for user or password. */
1940 /* The next (client response) line must be base64 encoded. */
1941 *next_line_encoded
= 1;
1942 } else if (*next_line_encoded
) {
1943 /* "next" line now refers to this line, which is a base64-encoded
1946 *next_line_encoded
= 0;
1948 *next_line_encoded
= 0;
1951 /* Don't attempt to decoded unencoded initial response ('=') or cancel
1953 if (prefix_len
> -1 &&
1954 string
[prefix_len
] != '=' && string
[prefix_len
] != '*') {
1955 start
= string
+ prefix_len
;
1958 if (start
&& decodeBase64 (start
, &decoded
, &decoded_len
, 1, NULL
) == OK
) {
1960 char *prefix
= mh_xmalloc(prefix_len
+ 1);
1961 char *display_string
;
1963 /* prefix is the beginning portion, which isn't base64 encoded. */
1964 snprintf (prefix
, prefix_len
+ 1, "%*s", prefix_len
, string
);
1965 hexify ((const unsigned char *) decoded
, decoded_len
, &hexified
);
1966 /* Wrap the decoded portion in "b64<>". */
1967 display_string
= concat (prefix
, "b64<", hexified
, ">", NULL
);
1970 free ((char *) decoded
);
1972 return display_string
;
1974 return getcpy (string
);