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 <sys/socket.h>
19 * This module implements an interface to SendMail very similar
20 * to the MMDF mm_(3) routines. The sm_() routines herein talk
21 * SMTP to a sendmail process, mapping SMTP reply codes into
26 * On older 4.2BSD machines without the POSIX function `sigaction',
27 * the alarm handing stuff for time-outs will NOT work due to the way
28 * syscalls get restarted. This is not really crucial, since SendMail
29 * is generally well-behaved in this area.
34 * It appears that some versions of Sendmail will return Code 451
35 * when they don't really want to indicate a failure.
36 * "Code 451 almost always means sendmail has deferred; we don't
37 * really want bomb out at this point since sendmail will rectify
38 * things later." So, if you define SENDMAILBUG, Code 451 is
39 * considered the same as Code 250. Yuck!
46 #define NBITS ((sizeof (int)) * 8)
49 * these codes must all be different!
51 #define SM_OPEN 300 /* Changed to 5 minutes to comply with a SHOULD in RFC 1123 */
54 #define SM_MAIL 301 /* changed to 5 minutes and a second (for uniqueness), see above */
55 #define SM_RCPT 302 /* see above */
56 #define SM_DATA 120 /* see above */
57 #define SM_TEXT 180 /* see above */
58 #define SM_DOT 600 /* see above */
63 static int sm_addrs
= 0;
64 static int sm_alarmed
= 0;
65 static int sm_child
= NOTOK
;
66 static int sm_debug
= 0;
67 static int sm_nl
= TRUE
;
68 static int sm_verbose
= 0;
69 static netsec_context
*nsc
= NULL
;
71 static int next_line_encoded
= 0;
76 * Some globals needed by SASL
79 static sasl_conn_t
*conn
= NULL
; /* SASL connection state */
80 static int sasl_complete
= 0; /* Has authentication succeeded? */
81 static sasl_ssf_t sasl_ssf
; /* Our security strength factor */
82 static int maxoutbuf
; /* Maximum crypto output buffer */
83 static char *sasl_outbuffer
; /* SASL output buffer for encryption */
84 static int sasl_outbuflen
; /* Current length of data in outbuf */
85 static int sm_get_user(void *, int, const char **, unsigned *);
86 static int sm_get_pass(sasl_conn_t
*, void *, int, sasl_secret_t
**);
88 static sasl_callback_t callbacks
[] = {
89 { SASL_CB_USER
, (sasl_callback_ft
) sm_get_user
, NULL
},
90 #define SM_SASL_N_CB_USER 0
91 { SASL_CB_AUTHNAME
, (sasl_callback_ft
) sm_get_user
, NULL
},
92 #define SM_SASL_N_CB_AUTHNAME 1
93 { SASL_CB_PASS
, (sasl_callback_ft
) sm_get_pass
, NULL
},
94 #define SM_SASL_N_CB_PASS 2
95 { SASL_CB_LIST_END
, NULL
, NULL
},
98 #else /* CYRUS_SASL */
100 #endif /* CYRUS_SASL */
105 static SSL_CTX
*sslctx
= NULL
;
106 static SSL
*ssl
= NULL
;
107 static BIO
*sbior
= NULL
;
108 static BIO
*sbiow
= NULL
;
109 static BIO
*io
= NULL
;
111 static int tls_negotiate(void);
112 #endif /* TLS_SUPPORT */
116 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
117 #define SASL_MAXRECVBUF 65536
118 static int sm_fgetc(FILE *);
119 static char *sasl_inbuffer
; /* SASL input buffer for encryption */
120 static char *sasl_inptr
; /* Pointer to current inbuf position */
121 static int sasl_inbuflen
; /* Current length of data in inbuf */
123 #define sm_fgetc fgetc
126 static int tls_active
= 0;
129 static char *sm_noreply
= "No reply text given";
130 static char *sm_moreply
= "; ";
131 static struct smtp sm_reply
;
135 static int doingEHLO
;
136 static char *EHLOkeys
[MAXEHLO
+ 1];
141 static int smtp_init (char *, char *, char *, int, int, int, int, const char *,
142 const char *, const char *, int);
143 static int sendmail_init (char *, char *, int, int, int, int, const char *,
146 static int rclient (char *, char *);
147 static int sm_ierror (const char *fmt
, ...);
148 static int sm_nerror (char *);
149 static int smtalk (int time
, char *fmt
, ...);
150 static int sm_wstream (char *, int);
151 static int smhear (void);
152 static int sm_rrecord (char *, int *);
153 static int sm_rerror (int);
154 static void alrmser (int);
155 static char *EHLOset (char *);
156 static char *prepare_for_display (const char *, int *);
158 static int sm_fwrite(char *, int);
159 static int sm_fputs(char *);
160 static int sm_fputc(int);
161 static void sm_fflush(void);
162 static int sm_fgets(char *, int, FILE *);
164 static int sm_sasl_callback(enum sasl_message_type
, unsigned const char *,
165 unsigned int, unsigned char **, unsigned int *,
169 sm_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
170 int debug
, int sasl
, const char *saslmech
, const char *user
,
171 const char *oauth_svc
, int tls
)
173 if (sm_mts
== MTS_SMTP
)
174 return smtp_init (client
, server
, port
, watch
, verbose
,
175 debug
, sasl
, saslmech
, user
, oauth_svc
, tls
);
177 return sendmail_init (client
, server
, watch
, verbose
,
178 debug
, sasl
, saslmech
, user
);
182 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
183 int debug
, int sasl
, const char *saslmech
, const char *user
,
184 const char *oauth_svc
, int tls
)
192 sm_verbose
= verbose
;
198 if (client
== NULL
|| *client
== '\0') {
202 client
= LocalName(1); /* no clientname -> LocalName */
207 * Last-ditch check just in case client still isn't set to anything
210 if (client
== NULL
|| *client
== '\0')
211 client
= "localhost";
216 netsec_set_userid(nsc
, user
);
219 if (netsec_set_tls(nsc
, 1, &errstr
) != OK
)
220 return sm_nerror(errstr
);
224 netsec_set_snoop(nsc
, 1);
227 if (netsec_set_sasl_params(nsc
, client
, "smtp", saslmech
,
228 sm_sasl_callback
, &errstr
) != OK
)
229 return sm_nerror(errstr
);
233 if (netsec_set_oauth_service(nsc
, oauth_svc
) != OK
)
234 return sm_ierror("OAuth2 not supported");
237 if ((sd1
= rclient (server
, port
)) == NOTOK
)
240 SIGNAL (SIGALRM
, alrmser
);
241 SIGNAL (SIGPIPE
, SIG_IGN
);
243 netsec_set_fd(nsc
, sd1
, sd1
);
246 * If tls == 2, that means that the user requested "initial" TLS,
247 * which happens right after the connection has opened. Do that
252 if (netsec_negotiate_tls(nsc
, &errstr
) != OK
) {
254 return sm_nerror(errstr
);
258 netsec_set_timeout(nsc
, SM_OPEN
);
271 * Give EHLO or HELO command
275 result
= smtalk (SM_HELO
, "EHLO %s", client
);
278 if (result
>= 500 && result
<= 599)
279 result
= smtalk (SM_HELO
, "HELO %s", client
);
287 * If the user requested TLS support, then try to do the STARTTLS command
288 * as part of the initial dialog. Assuming this works, we then need to
289 * restart the EHLO dialog after TLS negotiation is complete.
293 if (! EHLOset("STARTTLS")) {
295 return sm_ierror("SMTP server does not support TLS");
298 result
= smtalk(SM_HELO
, "STARTTLS");
306 * Okay, the other side should be waiting for us to start TLS
307 * negotiation. Oblige them.
310 if (netsec_negotiate_tls(nsc
, &errstr
) != OK
) {
312 return sm_nerror(errstr
);
316 result
= smtalk (SM_HELO
, "EHLO %s", client
);
326 * If the user asked for SASL, then check to see if the SMTP server
327 * supports it. Otherwise, error out (because the SMTP server
328 * might have been spoofed; we don't want to just silently not
334 if (! (server_mechs
= EHLOset("AUTH"))) {
336 return sm_ierror("SMTP server does not support SASL");
339 if (netsec_negotiate_sasl(nsc
, server_mechs
, &errstr
) != OK
) {
341 return sm_nerror(errstr
);
346 if (watch
&& EHLOset ("XVRB"))
347 smtalk (SM_HELO
, "VERB on");
353 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
354 int debug
, int sasl
, const char *saslmech
, const char *user
)
356 unsigned int i
, result
, vecp
;
358 char *vec
[15], *errstr
;
363 sm_verbose
= verbose
;
368 if (client
== NULL
|| *client
== '\0') {
372 client
= LocalName(1); /* no clientname -> LocalName */
376 * Last-ditch check just in case client still isn't set to anything
379 if (client
== NULL
|| *client
== '\0')
380 client
= "localhost";
385 netsec_set_userid(nsc
, user
);
388 netsec_set_snoop(nsc
, 1);
391 if (netsec_set_sasl_params(nsc
, client
, "smtp", saslmech
,
392 sm_sasl_callback
, &errstr
) != OK
)
393 return sm_nerror(errstr
);
398 if (netsec_set_oauth_service(nsc
, oauth_svc
) != OK
)
399 return sm_ierror("OAuth2 not supported");
404 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
405 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
407 return sm_ierror("Unable to allocate %d bytes for read buffer",
409 #endif /* CYRUS_SASL || TLS_SUPPORT */
412 if (pipe (pdi
) == NOTOK
)
413 return sm_ierror ("no pipes");
414 if (pipe (pdo
) == NOTOK
) {
417 return sm_ierror ("no pipes");
420 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
429 return sm_ierror ("unable to fork");
432 if (pdo
[0] != fileno (stdin
))
433 dup2 (pdo
[0], fileno (stdin
));
434 if (pdi
[1] != fileno (stdout
))
435 dup2 (pdi
[1], fileno (stdout
));
436 if (pdi
[1] != fileno (stderr
))
437 dup2 (pdi
[1], fileno (stderr
));
438 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
442 vec
[vecp
++] = r1bindex (sendmail
, '/');
444 vec
[vecp
++] = watch
? "-odi" : "-odb";
445 vec
[vecp
++] = "-oem";
451 execvp (sendmail
, vec
);
452 fprintf (stderr
, "unable to exec ");
454 _exit (-1); /* NOTREACHED */
457 SIGNAL (SIGALRM
, alrmser
);
458 SIGNAL (SIGPIPE
, SIG_IGN
);
463 netsec_set_fd(nsc
, pdi
[i
], pdo
[1]);
464 netsec_set_timeout(nsc
, SM_OPEN
);
476 result
= smtalk (SM_HELO
, "EHLO %s", client
);
479 if (500 <= result
&& result
<= 599)
480 result
= smtalk (SM_HELO
, "HELO %s", client
);
492 * If the user asked for SASL, then check to see if the SMTP server
493 * supports it. Otherwise, error out (because the SMTP server
494 * might have been spoofed; we don't want to just silently not
500 if (! (server_mechs
= EHLOset("AUTH"))) {
502 return sm_ierror("SMTP server does not support SASL");
504 if (netsec_negotiate_sasl(nsc
, server_mechs
, &errstr
) != OK
) {
506 return sm_nerror(errstr
);
511 smtalk (SM_HELO
, "VERB on");
518 rclient (char *server
, char *service
)
521 char response
[BUFSIZ
];
523 if ((sd
= client (server
, service
, response
, sizeof(response
),
527 sm_ierror ("%s", response
);
532 sm_winit (char *from
)
534 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
551 sm_wadr (char *mbox
, char *host
, char *path
)
553 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
555 path
? path
: "", mbox
, host
)) {
565 #endif /* SENDMAILBUG */
590 switch (smtalk (SM_DATA
, "DATA")) {
599 #endif /* SENDMAILBUG */
616 sm_wtxt (char *buffer
, int len
)
622 result
= sm_wstream (buffer
, len
);
625 return (result
== NOTOK
? RP_BHST
: RP_OK
);
632 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
635 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
643 #endif /* SENDMAILBUG */
661 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
677 smtalk (SM_QUIT
, "QUIT");
681 sm_note
.code
= sm_reply
.code
;
682 sm_note
.length
= sm_reply
.length
;
683 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
685 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
687 if (sm_mts
== MTS_SMTP
)
688 smtalk (SM_QUIT
, "QUIT");
690 /* The SIGPIPE block replaces old calls to discard ().
691 We're not sure what the discard () calls were for,
692 maybe to prevent deadlock on old systems. In any
693 case, blocking SIGPIPE should be harmless.
694 Because the file handles are closed below, leave it
698 sigaddset (&set
, SIGPIPE
);
699 sigprocmask (SIG_BLOCK
, &set
, &oset
);
701 kill (sm_child
, SIGKILL
);
705 sm_reply
.code
= sm_note
.code
;
706 sm_reply
.length
= sm_note
.length
;
707 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
714 netsec_shutdown(nsc
, 1);
719 if (sm_mts
== MTS_SMTP
) {
721 } else if (sm_child
!= NOTOK
) {
722 status
= pidwait (sm_child
, OK
);
728 return (status
? RP_BHST
: RP_OK
);
733 * This function implements SASL authentication for SMTP. If this function
734 * completes successfully, then authentication is successful and we've
735 * (optionally) negotiated a security layer.
738 #define CHECKB64SIZE(insize, outbuf, outsize) \
739 { size_t wantout = (((insize + 2) / 3) * 4) + 32; \
740 if (wantout > outsize) { \
741 outbuf = mh_xrealloc(outbuf, outsize = wantout); \
746 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
749 unsigned int buflen
, outlen
;
750 char *buf
, *outbuf
= NULL
, host
[NI_MAXHOST
];
751 const char *chosen_mech
;
752 sasl_security_properties_t secprops
;
755 struct nmh_creds creds
= { 0, 0, 0 };
756 size_t outbufsize
= 0;
759 * Initialize the callback contexts
763 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
764 * to us on the command line, then call getpeername and do a
765 * reverse-address lookup on the IP address to get the name.
768 memset(host
, 0, sizeof(host
));
771 struct sockaddr_storage sin
;
772 socklen_t len
= sizeof(sin
);
775 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
776 sm_ierror("getpeername on SMTP socket failed: %s",
781 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
782 NULL
, 0, NI_NAMEREQD
);
784 sm_ierror("Unable to look up name of connected host: %s",
785 gai_strerror(result
));
789 strncpy(host
, inhost
, sizeof(host
) - 1);
792 /* It's OK to copy the addresses here. The callbacks that use
793 them will only be called before this function returns. */
796 callbacks
[SM_SASL_N_CB_USER
].context
= &creds
;
797 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= &creds
;
798 callbacks
[SM_SASL_N_CB_PASS
].context
= &creds
;
800 result
= sasl_client_init(callbacks
);
802 if (result
!= SASL_OK
) {
803 sm_ierror("SASL library initialization failed: %s",
804 sasl_errstring(result
, NULL
, NULL
));
808 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
810 if (result
!= SASL_OK
) {
811 sm_ierror("SASL client initialization failed: %s",
812 sasl_errstring(result
, NULL
, NULL
));
817 * Initialize the security properties. But if TLS is active, then
818 * don't negotiate encryption here.
821 memset(&secprops
, 0, sizeof(secprops
));
822 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
824 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
826 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
828 if (result
!= SASL_OK
) {
829 sm_ierror("SASL security property initialization failed: %s",
830 sasl_errstring(result
, NULL
, NULL
));
835 * Start the actual protocol. Feed the mech list into the library
836 * and get out a possible initial challenge
839 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
840 &buflen
, (const char **) &chosen_mech
);
842 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
843 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
848 * If we got an initial challenge, send it as part of the AUTH
849 * command; otherwise, just send a plain AUTH command.
853 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
854 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
855 if (status
!= SASL_OK
) {
856 sm_ierror("SASL base64 encode failed: %s",
857 sasl_errstring(status
, NULL
, NULL
));
863 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
865 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
868 * Now we loop until we either fail, get a SASL_OK, or a 235
869 * response code. Receive the challenges and process them until
873 while (result
== SASL_CONTINUE
) {
876 * If we get a 235 response, that means authentication has
877 * succeeded and we need to break out of the loop (yes, even if
878 * we still get SASL_CONTINUE from sasl_client_step()).
880 * Otherwise, if we get a message that doesn't seem to be a
881 * valid response, then abort
886 else if (status
< 300 || status
> 399) {
893 * Special case; a zero-length response from the SMTP server
894 * is returned as a single =. If we get that, then set buflen
895 * to be zero. Otherwise, just decode the response.
898 if (strcmp("=", sm_reply
.text
) == 0) {
901 if (sm_reply
.length
> (int) outbufsize
) {
902 outbuf
= mh_xrealloc(outbuf
, outbufsize
= sm_reply
.length
);
905 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
906 outbuf
, outbufsize
, &outlen
);
907 if (result
!= SASL_OK
) {
908 smtalk(SM_AUTH
, "*");
909 sm_ierror("SASL base64 decode failed: %s",
910 sasl_errstring(result
, NULL
, NULL
));
917 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
918 (const char **) &buf
, &buflen
);
920 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
921 smtalk(SM_AUTH
, "*");
922 sm_ierror("SASL client negotiation failed: %s",
923 sasl_errstring(result
, NULL
, NULL
));
929 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
930 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
932 if (status
!= SASL_OK
) {
933 smtalk(SM_AUTH
, "*");
934 sm_ierror("SASL base64 encode failed: %s",
935 sasl_errstring(status
, NULL
, NULL
));
941 status
= smtalk(SM_AUTH
, outbuf
);
948 * Make sure that we got the correct response
951 if (status
< 200 || status
> 299)
955 * We _should_ have completed the authentication successfully.
956 * Get a few properties from the authentication exchange.
959 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
961 if (result
!= SASL_OK
) {
962 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
963 sasl_errstring(result
, NULL
, NULL
));
967 maxoutbuf
= *outbufmax
;
969 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
973 if (result
!= SASL_OK
) {
974 sm_ierror("Cannot retrieve SASL negotiated security strength "
975 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
980 sasl_outbuffer
= malloc(maxoutbuf
);
982 if (sasl_outbuffer
== NULL
) {
983 sm_ierror("Unable to allocate %d bytes for SASL output "
984 "buffer", maxoutbuf
);
989 sasl_inptr
= sasl_inbuffer
;
991 sasl_outbuffer
= NULL
;
992 /* Don't NULL out sasl_inbuffer because it could be used in
1002 * Our callback functions to feed data to the SASL library
1006 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1008 nmh_creds_t creds
= (nmh_creds_t
) context
;
1010 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1011 return SASL_BADPARAM
;
1013 if (creds
->user
== NULL
) {
1015 * Pass the 1 third argument to nmh_get_credentials() so
1016 * that a default user if the -user switch to send(1)/post(8)
1017 * wasn't used, and so that a default password will be supplied.
1018 * That's used when those values really don't matter, and only
1019 * with legacy/.netrc, i.e., with a credentials profile entry.
1021 if (nmh_get_credentials (creds
->host
, creds
->user
, 1, creds
) != OK
) {
1022 return SASL_BADPARAM
;
1026 *result
= creds
->user
;
1028 *len
= strlen(creds
->user
);
1034 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1035 sasl_secret_t
**psecret
)
1037 nmh_creds_t creds
= (nmh_creds_t
) context
;
1042 if (! psecret
|| id
!= SASL_CB_PASS
)
1043 return SASL_BADPARAM
;
1045 if (creds
->password
== NULL
) {
1047 * Pass the 0 third argument to nmh_get_credentials() so
1048 * that the default password isn't used. With legacy/.netrc
1049 * credentials support, we'll only get here if the -user
1050 * switch to send(1)/post(8) wasn't used.
1052 if (nmh_get_credentials (creds
->host
, creds
->user
, 0, creds
) != OK
) {
1053 return SASL_BADPARAM
;
1057 len
= strlen (creds
->password
);
1059 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1063 (*psecret
)->len
= len
;
1064 strcpy((char *) (*psecret
)->data
, creds
->password
);
1068 #endif /* CYRUS_SASL */
1070 /* https://developers.google.com/gmail/xoauth2_protocol */
1072 sm_auth_xoauth2(const char *user
, const char *oauth_svc
, int snoop
)
1074 const char *xoauth_client_res
;
1078 xoauth_client_res
= mh_oauth_do_xoauth(user
, oauth_svc
,
1079 snoop
? stderr
: NULL
);
1081 if (xoauth_client_res
== NULL
) {
1082 return sm_ierror("Internal error: mh_oauth_do_xoauth() returned NULL");
1087 adios(NULL
, "sendfrom built without OAUTH_SUPPORT, "
1088 "so oauth_svc %s is not supported", oauth_svc
);
1089 #endif /* OAUTH_SUPPORT */
1091 status
= smtalk(SM_AUTH
, "AUTH XOAUTH2 %s", xoauth_client_res
);
1092 if (status
== 235) {
1098 * Status is 334 and sm_reply.text contains base64-encoded JSON. As far as
1099 * epg can tell, no matter the error, the JSON is always the same:
1100 * {"status":"400","schemes":"Bearer","scope":"https://mail.google.com/"}
1101 * I tried these errors:
1107 /* Then we're supposed to send an empty response ("\r\n"). */
1108 smtalk(SM_AUTH
, "");
1110 * And now we always get this, again, no matter the error:
1111 * 535-5.7.8 Username and Password not accepted. Learn more at
1112 * 535 5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257
1118 sm_ierror (const char *fmt
, ...)
1123 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1126 sm_reply
.length
= strlen (sm_reply
.text
);
1127 sm_reply
.code
= NOTOK
;
1133 * Like sm_ierror, but assume it's an allocated error string we need to free.
1137 sm_nerror (char *str
)
1139 strncpy(sm_reply
.text
, str
, sizeof(sm_reply
.text
));
1140 sm_reply
.text
[sizeof(sm_reply
.text
) - 1] = '\0';
1141 sm_reply
.length
= strlen(sm_reply
.text
);
1142 sm_reply
.code
= NOTOK
;
1149 smtalk (int time
, char *fmt
, ...)
1156 result
= netsec_vprintf (nsc
, &errstr
, fmt
, ap
);
1160 return sm_nerror(errstr
);
1162 if (netsec_printf (nsc
, &errstr
, "\r\n") != OK
)
1163 return sm_nerror(errstr
);
1165 if (netsec_flush (nsc
, &errstr
) != OK
)
1166 return sm_nerror(errstr
);
1168 netsec_set_timeout(nsc
, time
);
1175 sm_wstream (char *buffer
, int len
)
1178 static char lc
= '\0';
1182 sm_ierror("No socket opened");
1186 if (buffer
== NULL
&& len
== 0) {
1189 rc
= netsec_write(nsc
, "\r\n", 2, &errstr
);
1196 for (bp
= buffer
; bp
&& len
> 0; bp
++, len
--) {
1200 if (netsec_write(nsc
, "\r", 1, &errstr
) != OK
) {
1208 if (netsec_write(nsc
, ".", 1, &errstr
) != OK
) {
1211 } /* FALL THROUGH */
1216 if (netsec_write(nsc
, bp
, 1, &errstr
) != OK
) {
1228 * Write out to the network, but do buffering for SASL (if enabled)
1233 sm_fwrite(char *buffer
, int len
)
1237 unsigned int outputlen
;
1239 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1240 #endif /* CYRUS_SASL */
1245 ret
= BIO_write(io
, buffer
, len
);
1248 sm_ierror("TLS error during write: %s",
1249 ERR_error_string(ERR_get_error(), NULL
));
1253 #endif /* TLS_SUPPORT */
1254 if ((int) fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
) < len
) {
1255 advise ("sm_fwrite", "fwrite");
1259 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1260 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1261 maxoutbuf
- sasl_outbuflen
);
1262 len
-= maxoutbuf
- sasl_outbuflen
;
1265 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1266 &output
, &outputlen
) != SASL_OK
) {
1267 sm_ierror("Unable to SASL encode connection data: %s",
1268 sasl_errdetail(conn
));
1272 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) <
1274 advise ("sm_fwrite", "fwrite");
1279 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1280 sasl_outbuflen
+= len
;
1283 #endif /* CYRUS_SASL */
1284 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1291 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1292 : sm_alarmed
? "write to socket timed out"
1293 : "error writing to socket"));
1295 return (sm_reply
.code
= NOTOK
);
1303 int i
, code
, cont
, more
;
1308 char **ehlo
= EHLOkeys
, *buffer
;
1311 static int at_least_once
= 0;
1313 if (at_least_once
) {
1316 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1330 sm_reply
.length
= 0;
1331 sm_reply
.text
[0] = 0;
1333 rc
= sizeof(sm_reply
.text
) - 1;
1335 for (more
= FALSE
; (buffer
= netsec_readline(nsc
, &buflen
,
1336 &errstr
)) != NULL
; ) {
1339 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1340 && (buffer
[3] == '-' || doingEHLO
== 2)
1342 if (doingEHLO
== 2) {
1343 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1344 strcpy (*ehlo
++, buffer
+ 4);
1346 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1356 bp
= (unsigned char *) buffer
;
1358 for (; buflen
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, buflen
--)
1362 code
= atoi ((char *) bp
);
1363 bp
+= 3, buflen
-= 3;
1364 for (; buflen
> 0 && isspace (*bp
); bp
++, buflen
--)
1366 if (buflen
> 0 && *bp
== '-') {
1369 for (; buflen
> 0 && isspace (*bp
); bp
++, buflen
--)
1374 if (code
!= sm_reply
.code
|| cont
)
1378 sm_reply
.code
= code
;
1381 bp
= (unsigned char *) sm_noreply
;
1382 buflen
= strlen (sm_noreply
);
1386 if ((i
= min (buflen
, rc
)) > 0) {
1390 i
= strlen(sm_moreply
);
1391 if (more
&& rc
> i
+ 1) {
1392 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1399 if (sm_reply
.code
< 100) {
1401 printf ("%s\n", sm_reply
.text
);
1407 sm_reply
.length
= rp
- sm_reply
.text
;
1408 sm_reply
.text
[sm_reply
.length
] = 0;
1409 return sm_reply
.code
;
1419 sm_rrecord (char *buffer
, int *len
)
1428 buffer
[*len
= 0] = 0;
1430 str
= netsec_readline(nsc
, &strlen
, &errstr
);
1431 if ((retval
= netsec_readline(nsc
,
1432 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1433 return sm_rerror (retval
);
1434 *len
= strlen (buffer
);
1435 /* *len should be >0 except on EOF, but check for safety's sake */
1437 return sm_rerror (RP_EOF
);
1438 if (buffer
[*len
- 1] != '\n')
1439 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1443 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1452 * Our version of fgets, which calls our private fgetc function
1456 sm_fgets(char *buffer
, int size
, FILE *f
)
1470 } while (size
> 1 && c
!= '\n');
1478 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1480 * Read from the network, but do SASL or TLS encryption
1486 char tmpbuf
[BUFSIZ
], *retbuf
;
1487 unsigned int retbufsize
= 0;
1491 * If we have leftover data, return it
1494 if (sasl_inbuflen
) {
1496 return (int) *sasl_inptr
++;
1500 * If not, read from the network until we have some data to return
1503 while (retbufsize
== 0) {
1507 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1510 result
= SSL_get_error(ssl
, cc
);
1512 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1513 sm_ierror("TLS peer aborted connection");
1520 sm_ierror("SSL_read failed: %s",
1521 ERR_error_string(ERR_get_error(), NULL
));
1525 #endif /* TLS_SUPPORT */
1527 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1533 sm_ierror("Unable to read from network: %s", strerror(errno
));
1538 * Don't call sasl_decode unless sasl is complete and we have
1539 * encryption working
1543 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1547 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1550 if (result
!= SASL_OK
) {
1551 sm_ierror("Unable to decode SASL network data: %s",
1552 sasl_errdetail(conn
));
1556 #else /* ! CYRUS_SASL */
1559 #endif /* CYRUS_SASL */
1562 if (retbufsize
> SASL_MAXRECVBUF
) {
1563 sm_ierror("Received data (%d bytes) is larger than the buffer "
1564 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1568 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1569 sasl_inptr
= sasl_inbuffer
+ 1;
1570 sasl_inbuflen
= retbufsize
- 1;
1572 return (int) sasl_inbuffer
[0];
1574 #endif /* CYRUS_SASL || TLS_SUPPORT */
1579 if (sm_mts
== MTS_SMTP
)
1581 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1582 : sm_alarmed
? "read from socket timed out"
1583 : rc
== RP_EOF
? "premature end-of-file on socket"
1584 : "error reading from socket"));
1587 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1588 : sm_alarmed
? "read from pipe timed out"
1589 : rc
== RP_EOF
? "premature end-of-file on pipe"
1590 : "error reading from pipe"));
1592 return (sm_reply
.code
= NOTOK
);
1602 #ifndef RELIABLE_SIGNALS
1603 SIGNAL (SIGALRM
, alrmser
);
1608 printf ("timed out...\n");
1615 rp_string (int code
)
1618 static char buffer
[BUFSIZ
];
1620 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1640 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1660 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1661 text
, sm_reply
.code
, sm_reply
.text
);
1673 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1675 if (strncmp (ep
, s
, len
) == 0) {
1676 for (ep
+= len
; *ep
== ' '; ep
++)
1687 * Detects, using heuristics, if an SMTP server or client response string
1688 * contains a base64-encoded portion. If it does, decodes it and replaces
1689 * any non-printable characters with a hex representation. Caller is
1690 * responsible for free'ing return value. If the decode fails, a copy of
1691 * the input string is returned.
1695 prepare_for_display (const char *string
, int *next_line_encoded
) {
1696 const char *start
= NULL
;
1697 const char *decoded
;
1699 int prefix_len
= -1;
1701 if (strncmp (string
, "AUTH ", 5) == 0) {
1702 /* AUTH line: the mechanism isn't encoded. If there's an initial
1703 response, it must be base64 encoded.. */
1704 char *mechanism
= strchr (string
+ 5, ' ');
1706 if (mechanism
!= NULL
) {
1707 prefix_len
= (int) (mechanism
- string
+ 1);
1708 } /* else no space following the mechanism, so no initial response */
1709 *next_line_encoded
= 0;
1710 } else if (strncmp (string
, "334 ", 4) == 0) {
1711 /* 334 is the server's request for user or password. */
1713 /* The next (client response) line must be base64 encoded. */
1714 *next_line_encoded
= 1;
1715 } else if (*next_line_encoded
) {
1716 /* "next" line now refers to this line, which is a base64-encoded
1719 *next_line_encoded
= 0;
1721 *next_line_encoded
= 0;
1724 /* Don't attempt to decoded unencoded initial response ('=') or cancel
1726 if (prefix_len
> -1 &&
1727 string
[prefix_len
] != '=' && string
[prefix_len
] != '*') {
1728 start
= string
+ prefix_len
;
1731 if (start
&& decodeBase64 (start
, &decoded
, &decoded_len
, 1, NULL
) == OK
) {
1733 char *prefix
= mh_xmalloc(prefix_len
+ 1);
1734 char *display_string
;
1736 /* prefix is the beginning portion, which isn't base64 encoded. */
1737 snprintf (prefix
, prefix_len
+ 1, "%*s", prefix_len
, string
);
1738 hexify ((const unsigned char *) decoded
, decoded_len
, &hexified
);
1739 /* Wrap the decoded portion in "b64<>". */
1740 display_string
= concat (prefix
, "b64<", hexified
, ">", NULL
);
1743 free ((char *) decoded
);
1745 return display_string
;
1747 return getcpy (string
);