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
;
74 * Some globals needed by SASL
77 static sasl_conn_t
*conn
= NULL
; /* SASL connection state */
78 static int sasl_complete
= 0; /* Has authentication succeeded? */
79 static sasl_ssf_t sasl_ssf
; /* Our security strength factor */
80 static int maxoutbuf
; /* Maximum crypto output buffer */
81 static char *sasl_outbuffer
; /* SASL output buffer for encryption */
82 static int sasl_outbuflen
; /* Current length of data in outbuf */
83 static int sm_get_user(void *, int, const char **, unsigned *);
84 static int sm_get_pass(sasl_conn_t
*, void *, int, sasl_secret_t
**);
86 static sasl_callback_t callbacks
[] = {
87 { SASL_CB_USER
, (sasl_callback_ft
) sm_get_user
, NULL
},
88 #define SM_SASL_N_CB_USER 0
89 { SASL_CB_AUTHNAME
, (sasl_callback_ft
) sm_get_user
, NULL
},
90 #define SM_SASL_N_CB_AUTHNAME 1
91 { SASL_CB_PASS
, (sasl_callback_ft
) sm_get_pass
, NULL
},
92 #define SM_SASL_N_CB_PASS 2
93 { SASL_CB_LIST_END
, NULL
, NULL
},
96 #else /* CYRUS_SASL */
98 #endif /* CYRUS_SASL */
103 static SSL_CTX
*sslctx
= NULL
;
104 static SSL
*ssl
= NULL
;
105 static BIO
*sbior
= NULL
;
106 static BIO
*sbiow
= NULL
;
107 static BIO
*io
= NULL
;
109 static int tls_negotiate(void);
110 #endif /* TLS_SUPPORT */
114 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
115 #define SASL_MAXRECVBUF 65536
116 static int sm_fgetc(FILE *);
117 static char *sasl_inbuffer
; /* SASL input buffer for encryption */
118 static char *sasl_inptr
; /* Pointer to current inbuf position */
119 static int sasl_inbuflen
; /* Current length of data in inbuf */
121 #define sm_fgetc fgetc
124 static int tls_active
= 0;
127 static char *sm_noreply
= "No reply text given";
128 static char *sm_moreply
= "; ";
129 static struct smtp sm_reply
;
133 static int doingEHLO
;
134 static char *EHLOkeys
[MAXEHLO
+ 1];
139 static int smtp_init (char *, char *, char *, int, int, int, int, const char *,
140 const char *, const char *, int);
141 static int sendmail_init (char *, int, int, int, int, const char *,
144 static int rclient (char *, char *);
145 static int sm_ierror (const char *fmt
, ...);
146 static int sm_nerror (char *);
147 static int smtalk (int time
, char *fmt
, ...);
148 static int sm_wstream (char *, int);
149 static int smhear (void);
150 static void alrmser (int);
151 static char *EHLOset (char *);
153 static int sm_fwrite(char *, int);
154 static int sm_fputs(char *);
155 static int sm_fputc(int);
156 static void sm_fflush(void);
157 static int sm_fgets(char *, int, FILE *);
159 static int sm_sasl_callback(enum sasl_message_type
, unsigned const char *,
160 unsigned int, unsigned char **, unsigned int *,
164 sm_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
165 int debug
, int sasl
, const char *saslmech
, const char *user
,
166 const char *oauth_svc
, int tls
)
168 if (sm_mts
== MTS_SMTP
)
169 return smtp_init (client
, server
, port
, watch
, verbose
,
170 debug
, sasl
, saslmech
, user
, oauth_svc
, tls
);
172 return sendmail_init (client
, watch
, verbose
, debug
, sasl
,
177 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
178 int debug
, int sasl
, const char *saslmech
, const char *user
,
179 const char *oauth_svc
, int tls
)
187 sm_verbose
= verbose
;
193 if (client
== NULL
|| *client
== '\0') {
197 client
= LocalName(1); /* no clientname -> LocalName */
202 * Last-ditch check just in case client still isn't set to anything
205 if (client
== NULL
|| *client
== '\0')
206 client
= "localhost";
211 netsec_set_userid(nsc
, user
);
214 netsec_set_snoop(nsc
, 1);
217 if (netsec_set_sasl_params(nsc
, client
, "smtp", saslmech
,
218 sm_sasl_callback
, &errstr
) != OK
)
219 return sm_nerror(errstr
);
223 if (netsec_set_oauth_service(nsc
, oauth_svc
) != OK
)
224 return sm_ierror("OAuth2 not supported");
227 if ((sd1
= rclient (server
, port
)) == NOTOK
)
231 SIGNAL (SIGALRM
, alrmser
);
233 SIGNAL (SIGPIPE
, SIG_IGN
);
235 netsec_set_fd(nsc
, sd1
, sd1
);
238 if (netsec_set_tls(nsc
, 1, &errstr
) != OK
)
239 return sm_nerror(errstr
);
243 * If tls == 2, that means that the user requested "initial" TLS,
244 * which happens right after the connection has opened. Do that
249 if (netsec_negotiate_tls(nsc
, &errstr
) != OK
) {
251 return sm_nerror(errstr
);
255 netsec_set_timeout(nsc
, SM_OPEN
);
268 * Give EHLO or HELO command
272 result
= smtalk (SM_HELO
, "EHLO %s", client
);
275 if (result
>= 500 && result
<= 599)
276 result
= smtalk (SM_HELO
, "HELO %s", client
);
284 * If the user requested TLS support, then try to do the STARTTLS command
285 * as part of the initial dialog. Assuming this works, we then need to
286 * restart the EHLO dialog after TLS negotiation is complete.
290 if (! EHLOset("STARTTLS")) {
292 return sm_ierror("SMTP server does not support TLS");
295 result
= smtalk(SM_HELO
, "STARTTLS");
303 * Okay, the other side should be waiting for us to start TLS
304 * negotiation. Oblige them.
307 if (netsec_negotiate_tls(nsc
, &errstr
) != OK
) {
309 return sm_nerror(errstr
);
313 result
= smtalk (SM_HELO
, "EHLO %s", client
);
323 * If the user asked for SASL, then check to see if the SMTP server
324 * supports it. Otherwise, error out (because the SMTP server
325 * might have been spoofed; we don't want to just silently not
331 if (! (server_mechs
= EHLOset("AUTH"))) {
333 return sm_ierror("SMTP server does not support SASL");
336 if (netsec_negotiate_sasl(nsc
, server_mechs
, &errstr
) != OK
) {
338 return sm_nerror(errstr
);
343 if (watch
&& EHLOset ("XVRB"))
344 smtalk (SM_HELO
, "VERB on");
350 sendmail_init (char *client
, int watch
, int verbose
, int debug
, int sasl
,
351 const char *saslmech
, const char *user
)
353 unsigned int i
, result
, vecp
;
355 char *vec
[15], *errstr
;
360 sm_verbose
= verbose
;
365 if (client
== NULL
|| *client
== '\0') {
369 client
= LocalName(1); /* no clientname -> LocalName */
373 * Last-ditch check just in case client still isn't set to anything
376 if (client
== NULL
|| *client
== '\0')
377 client
= "localhost";
382 netsec_set_userid(nsc
, user
);
385 netsec_set_snoop(nsc
, 1);
388 if (netsec_set_sasl_params(nsc
, client
, "smtp", saslmech
,
389 sm_sasl_callback
, &errstr
) != OK
)
390 return sm_nerror(errstr
);
395 if (netsec_set_oauth_service(nsc
, oauth_svc
) != OK
)
396 return sm_ierror("OAuth2 not supported");
401 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
402 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
404 return sm_ierror("Unable to allocate %d bytes for read buffer",
406 #endif /* CYRUS_SASL || TLS_SUPPORT */
409 if (pipe (pdi
) == NOTOK
)
410 return sm_ierror ("no pipes");
411 if (pipe (pdo
) == NOTOK
) {
414 return sm_ierror ("no pipes");
417 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
426 return sm_ierror ("unable to fork");
429 if (pdo
[0] != fileno (stdin
))
430 dup2 (pdo
[0], fileno (stdin
));
431 if (pdi
[1] != fileno (stdout
))
432 dup2 (pdi
[1], fileno (stdout
));
433 if (pdi
[1] != fileno (stderr
))
434 dup2 (pdi
[1], fileno (stderr
));
435 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
439 vec
[vecp
++] = r1bindex (sendmail
, '/');
441 vec
[vecp
++] = watch
? "-odi" : "-odb";
442 vec
[vecp
++] = "-oem";
448 execvp (sendmail
, vec
);
449 fprintf (stderr
, "unable to exec ");
451 _exit (-1); /* NOTREACHED */
454 SIGNAL (SIGALRM
, alrmser
);
455 SIGNAL (SIGPIPE
, SIG_IGN
);
460 netsec_set_fd(nsc
, pdi
[i
], pdo
[1]);
461 netsec_set_timeout(nsc
, SM_OPEN
);
473 result
= smtalk (SM_HELO
, "EHLO %s", client
);
476 if (500 <= result
&& result
<= 599)
477 result
= smtalk (SM_HELO
, "HELO %s", client
);
489 * If the user asked for SASL, then check to see if the SMTP server
490 * supports it. Otherwise, error out (because the SMTP server
491 * might have been spoofed; we don't want to just silently not
497 if (! (server_mechs
= EHLOset("AUTH"))) {
499 return sm_ierror("SMTP server does not support SASL");
501 if (netsec_negotiate_sasl(nsc
, server_mechs
, &errstr
) != OK
) {
503 return sm_nerror(errstr
);
508 smtalk (SM_HELO
, "VERB on");
515 rclient (char *server
, char *service
)
518 char response
[BUFSIZ
];
520 if ((sd
= client (server
, service
, response
, sizeof(response
),
524 sm_ierror ("%s", response
);
529 sm_winit (char *from
)
531 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
548 sm_wadr (char *mbox
, char *host
, char *path
)
550 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
552 path
? path
: "", mbox
, host
)) {
562 #endif /* SENDMAILBUG */
587 switch (smtalk (SM_DATA
, "DATA")) {
596 #endif /* SENDMAILBUG */
613 sm_wtxt (char *buffer
, int len
)
621 result
= sm_wstream (buffer
, len
);
626 return (result
== NOTOK
? RP_BHST
: RP_OK
);
633 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
636 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
644 #endif /* SENDMAILBUG */
662 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
678 smtalk (SM_QUIT
, "QUIT");
682 sm_note
.code
= sm_reply
.code
;
683 sm_note
.length
= sm_reply
.length
;
684 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
686 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
688 if (sm_mts
== MTS_SMTP
)
689 smtalk (SM_QUIT
, "QUIT");
691 /* The SIGPIPE block replaces old calls to discard ().
692 We're not sure what the discard () calls were for,
693 maybe to prevent deadlock on old systems. In any
694 case, blocking SIGPIPE should be harmless.
695 Because the file handles are closed below, leave it
699 sigaddset (&set
, SIGPIPE
);
700 sigprocmask (SIG_BLOCK
, &set
, &oset
);
702 kill (sm_child
, SIGKILL
);
706 sm_reply
.code
= sm_note
.code
;
707 sm_reply
.length
= sm_note
.length
;
708 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
715 netsec_shutdown(nsc
, 1);
720 if (sm_mts
== MTS_SMTP
) {
722 } else if (sm_child
!= NOTOK
) {
723 status
= pidwait (sm_child
, OK
);
729 return (status
? RP_BHST
: RP_OK
);
734 * This function implements SASL authentication for SMTP. If this function
735 * completes successfully, then authentication is successful and we've
736 * (optionally) negotiated a security layer.
739 #define CHECKB64SIZE(insize, outbuf, outsize) \
740 { size_t wantout = (((insize + 2) / 3) * 4) + 32; \
741 if (wantout > outsize) { \
742 outbuf = mh_xrealloc(outbuf, outsize = wantout); \
747 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
750 unsigned int buflen
, outlen
;
751 char *buf
, *outbuf
= NULL
, host
[NI_MAXHOST
];
752 const char *chosen_mech
;
753 sasl_security_properties_t secprops
;
756 struct nmh_creds creds
= { 0, 0, 0 };
757 size_t outbufsize
= 0;
760 * Initialize the callback contexts
764 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
765 * to us on the command line, then call getpeername and do a
766 * reverse-address lookup on the IP address to get the name.
769 memset(host
, 0, sizeof(host
));
772 struct sockaddr_storage sin
;
773 socklen_t len
= sizeof(sin
);
776 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
777 sm_ierror("getpeername on SMTP socket failed: %s",
782 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
783 NULL
, 0, NI_NAMEREQD
);
785 sm_ierror("Unable to look up name of connected host: %s",
786 gai_strerror(result
));
790 strncpy(host
, inhost
, sizeof(host
) - 1);
793 /* It's OK to copy the addresses here. The callbacks that use
794 them will only be called before this function returns. */
797 callbacks
[SM_SASL_N_CB_USER
].context
= &creds
;
798 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= &creds
;
799 callbacks
[SM_SASL_N_CB_PASS
].context
= &creds
;
801 result
= sasl_client_init(callbacks
);
803 if (result
!= SASL_OK
) {
804 sm_ierror("SASL library initialization failed: %s",
805 sasl_errstring(result
, NULL
, NULL
));
809 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
811 if (result
!= SASL_OK
) {
812 sm_ierror("SASL client initialization failed: %s",
813 sasl_errstring(result
, NULL
, NULL
));
818 * Initialize the security properties. But if TLS is active, then
819 * don't negotiate encryption here.
822 memset(&secprops
, 0, sizeof(secprops
));
823 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
825 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
827 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
829 if (result
!= SASL_OK
) {
830 sm_ierror("SASL security property initialization failed: %s",
831 sasl_errstring(result
, NULL
, NULL
));
836 * Start the actual protocol. Feed the mech list into the library
837 * and get out a possible initial challenge
840 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
841 &buflen
, (const char **) &chosen_mech
);
843 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
844 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
849 * If we got an initial challenge, send it as part of the AUTH
850 * command; otherwise, just send a plain AUTH command.
854 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
855 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
856 if (status
!= SASL_OK
) {
857 sm_ierror("SASL base64 encode failed: %s",
858 sasl_errstring(status
, NULL
, NULL
));
864 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
866 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
869 * Now we loop until we either fail, get a SASL_OK, or a 235
870 * response code. Receive the challenges and process them until
874 while (result
== SASL_CONTINUE
) {
877 * If we get a 235 response, that means authentication has
878 * succeeded and we need to break out of the loop (yes, even if
879 * we still get SASL_CONTINUE from sasl_client_step()).
881 * Otherwise, if we get a message that doesn't seem to be a
882 * valid response, then abort
887 else if (status
< 300 || status
> 399) {
894 * Special case; a zero-length response from the SMTP server
895 * is returned as a single =. If we get that, then set buflen
896 * to be zero. Otherwise, just decode the response.
899 if (strcmp("=", sm_reply
.text
) == 0) {
902 if (sm_reply
.length
> (int) outbufsize
) {
903 outbuf
= mh_xrealloc(outbuf
, outbufsize
= sm_reply
.length
);
906 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
907 outbuf
, outbufsize
, &outlen
);
908 if (result
!= SASL_OK
) {
909 smtalk(SM_AUTH
, "*");
910 sm_ierror("SASL base64 decode failed: %s",
911 sasl_errstring(result
, NULL
, NULL
));
918 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
919 (const char **) &buf
, &buflen
);
921 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
922 smtalk(SM_AUTH
, "*");
923 sm_ierror("SASL client negotiation failed: %s",
924 sasl_errstring(result
, NULL
, NULL
));
930 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
931 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
933 if (status
!= SASL_OK
) {
934 smtalk(SM_AUTH
, "*");
935 sm_ierror("SASL base64 encode failed: %s",
936 sasl_errstring(status
, NULL
, NULL
));
942 status
= smtalk(SM_AUTH
, outbuf
);
949 * Make sure that we got the correct response
952 if (status
< 200 || status
> 299)
956 * We _should_ have completed the authentication successfully.
957 * Get a few properties from the authentication exchange.
960 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
962 if (result
!= SASL_OK
) {
963 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
964 sasl_errstring(result
, NULL
, NULL
));
968 maxoutbuf
= *outbufmax
;
970 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
974 if (result
!= SASL_OK
) {
975 sm_ierror("Cannot retrieve SASL negotiated security strength "
976 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
981 sasl_outbuffer
= malloc(maxoutbuf
);
983 if (sasl_outbuffer
== NULL
) {
984 sm_ierror("Unable to allocate %d bytes for SASL output "
985 "buffer", maxoutbuf
);
990 sasl_inptr
= sasl_inbuffer
;
992 sasl_outbuffer
= NULL
;
993 /* Don't NULL out sasl_inbuffer because it could be used in
1003 * Our callback functions to feed data to the SASL library
1007 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
1009 nmh_creds_t creds
= (nmh_creds_t
) context
;
1011 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1012 return SASL_BADPARAM
;
1014 if (creds
->user
== NULL
) {
1016 * Pass the 1 third argument to nmh_get_credentials() so
1017 * that a default user if the -user switch to send(1)/post(8)
1018 * wasn't used, and so that a default password will be supplied.
1019 * That's used when those values really don't matter, and only
1020 * with legacy/.netrc, i.e., with a credentials profile entry.
1022 if (nmh_get_credentials (creds
->host
, creds
->user
, 1, creds
) != OK
) {
1023 return SASL_BADPARAM
;
1027 *result
= creds
->user
;
1029 *len
= strlen(creds
->user
);
1035 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1036 sasl_secret_t
**psecret
)
1038 nmh_creds_t creds
= (nmh_creds_t
) context
;
1043 if (! psecret
|| id
!= SASL_CB_PASS
)
1044 return SASL_BADPARAM
;
1046 if (creds
->password
== NULL
) {
1048 * Pass the 0 third argument to nmh_get_credentials() so
1049 * that the default password isn't used. With legacy/.netrc
1050 * credentials support, we'll only get here if the -user
1051 * switch to send(1)/post(8) wasn't used.
1053 if (nmh_get_credentials (creds
->host
, creds
->user
, 0, creds
) != OK
) {
1054 return SASL_BADPARAM
;
1058 len
= strlen (creds
->password
);
1060 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1064 (*psecret
)->len
= len
;
1065 strcpy((char *) (*psecret
)->data
, creds
->password
);
1069 #endif /* CYRUS_SASL */
1071 /* https://developers.google.com/gmail/xoauth2_protocol */
1073 sm_auth_xoauth2(const char *user
, const char *oauth_svc
, int snoop
)
1075 const char *xoauth_client_res
;
1079 xoauth_client_res
= mh_oauth_do_xoauth(user
, oauth_svc
,
1080 snoop
? stderr
: NULL
);
1082 if (xoauth_client_res
== NULL
) {
1083 return sm_ierror("Internal error: mh_oauth_do_xoauth() returned NULL");
1088 adios(NULL
, "sendfrom built without OAUTH_SUPPORT, "
1089 "so oauth_svc %s is not supported", oauth_svc
);
1090 #endif /* OAUTH_SUPPORT */
1092 status
= smtalk(SM_AUTH
, "AUTH XOAUTH2 %s", xoauth_client_res
);
1093 if (status
== 235) {
1099 * Status is 334 and sm_reply.text contains base64-encoded JSON. As far as
1100 * epg can tell, no matter the error, the JSON is always the same:
1101 * {"status":"400","schemes":"Bearer","scope":"https://mail.google.com/"}
1102 * I tried these errors:
1108 /* Then we're supposed to send an empty response ("\r\n"). */
1109 smtalk(SM_AUTH
, "");
1111 * And now we always get this, again, no matter the error:
1112 * 535-5.7.8 Username and Password not accepted. Learn more at
1113 * 535 5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257
1119 sm_ierror (const char *fmt
, ...)
1124 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1127 sm_reply
.length
= strlen (sm_reply
.text
);
1128 sm_reply
.code
= NOTOK
;
1134 * Like sm_ierror, but assume it's an allocated error string we need to free.
1138 sm_nerror (char *str
)
1140 strncpy(sm_reply
.text
, str
, sizeof(sm_reply
.text
));
1141 sm_reply
.text
[sizeof(sm_reply
.text
) - 1] = '\0';
1142 sm_reply
.length
= strlen(sm_reply
.text
);
1143 sm_reply
.code
= NOTOK
;
1150 smtalk (int time
, char *fmt
, ...)
1157 result
= netsec_vprintf (nsc
, &errstr
, fmt
, ap
);
1161 return sm_nerror(errstr
);
1163 if (netsec_printf (nsc
, &errstr
, "\r\n") != OK
)
1164 return sm_nerror(errstr
);
1166 if (netsec_flush (nsc
, &errstr
) != OK
)
1167 return sm_nerror(errstr
);
1169 netsec_set_timeout(nsc
, time
);
1176 sm_wstream (char *buffer
, int len
)
1179 static char lc
= '\0';
1183 sm_ierror("No socket opened");
1187 if (buffer
== NULL
&& len
== 0) {
1190 rc
= netsec_write(nsc
, "\r\n", 2, &errstr
);
1197 for (bp
= buffer
; bp
&& len
> 0; bp
++, len
--) {
1201 if (netsec_write(nsc
, "\r", 1, &errstr
) != OK
) {
1209 if (netsec_write(nsc
, ".", 1, &errstr
) != OK
) {
1212 } /* FALL THROUGH */
1217 if (netsec_write(nsc
, bp
, 1, &errstr
) != OK
) {
1229 * Write out to the network, but do buffering for SASL (if enabled)
1234 sm_fwrite(char *buffer
, int len
)
1238 unsigned int outputlen
;
1240 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1241 #endif /* CYRUS_SASL */
1246 ret
= BIO_write(io
, buffer
, len
);
1249 sm_ierror("TLS error during write: %s",
1250 ERR_error_string(ERR_get_error(), NULL
));
1254 #endif /* TLS_SUPPORT */
1255 if ((int) fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
) < len
) {
1256 advise ("sm_fwrite", "fwrite");
1260 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1261 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1262 maxoutbuf
- sasl_outbuflen
);
1263 len
-= maxoutbuf
- sasl_outbuflen
;
1266 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1267 &output
, &outputlen
) != SASL_OK
) {
1268 sm_ierror("Unable to SASL encode connection data: %s",
1269 sasl_errdetail(conn
));
1273 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) <
1275 advise ("sm_fwrite", "fwrite");
1280 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1281 sasl_outbuflen
+= len
;
1284 #endif /* CYRUS_SASL */
1285 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1292 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1293 : sm_alarmed
? "write to socket timed out"
1294 : "error writing to socket"));
1296 return (sm_reply
.code
= NOTOK
);
1304 int i
, code
, cont
, more
;
1309 char **ehlo
= EHLOkeys
, *buffer
;
1312 static int at_least_once
= 0;
1314 if (at_least_once
) {
1317 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1331 sm_reply
.length
= 0;
1332 sm_reply
.text
[0] = 0;
1334 rc
= sizeof(sm_reply
.text
) - 1;
1336 for (more
= FALSE
; (buffer
= netsec_readline(nsc
, &buflen
,
1337 &errstr
)) != NULL
; ) {
1340 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1341 && (buffer
[3] == '-' || doingEHLO
== 2)
1343 if (doingEHLO
== 2) {
1344 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1345 strcpy (*ehlo
++, buffer
+ 4);
1347 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1357 bp
= (unsigned char *) buffer
;
1359 for (; buflen
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, buflen
--)
1363 code
= atoi ((char *) bp
);
1364 bp
+= 3, buflen
-= 3;
1365 for (; buflen
> 0 && isspace (*bp
); bp
++, buflen
--)
1367 if (buflen
> 0 && *bp
== '-') {
1370 for (; buflen
> 0 && isspace (*bp
); bp
++, buflen
--)
1375 if (code
!= sm_reply
.code
|| cont
)
1379 sm_reply
.code
= code
;
1382 bp
= (unsigned char *) sm_noreply
;
1383 buflen
= strlen (sm_noreply
);
1387 if ((i
= min (buflen
, rc
)) > 0) {
1391 i
= strlen(sm_moreply
);
1392 if (more
&& (int) rc
> i
+ 1) {
1393 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1400 if (sm_reply
.code
< 100) {
1402 printf ("%s\n", sm_reply
.text
);
1408 sm_reply
.length
= rp
- sm_reply
.text
;
1409 sm_reply
.text
[sm_reply
.length
] = 0;
1410 return sm_reply
.code
;
1420 sm_rrecord (char *buffer
, int *len
)
1429 buffer
[*len
= 0] = 0;
1431 str
= netsec_readline(nsc
, &strlen
, &errstr
);
1432 if ((retval
= netsec_readline(nsc
,
1433 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1434 return sm_rerror (retval
);
1435 *len
= strlen (buffer
);
1436 /* *len should be >0 except on EOF, but check for safety's sake */
1438 return sm_rerror (RP_EOF
);
1439 if (buffer
[*len
- 1] != '\n')
1440 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1444 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1453 * Our version of fgets, which calls our private fgetc function
1457 sm_fgets(char *buffer
, int size
, FILE *f
)
1471 } while (size
> 1 && c
!= '\n');
1479 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1481 * Read from the network, but do SASL or TLS encryption
1487 char tmpbuf
[BUFSIZ
], *retbuf
;
1488 unsigned int retbufsize
= 0;
1492 * If we have leftover data, return it
1495 if (sasl_inbuflen
) {
1497 return (int) *sasl_inptr
++;
1501 * If not, read from the network until we have some data to return
1504 while (retbufsize
== 0) {
1508 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1511 result
= SSL_get_error(ssl
, cc
);
1513 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1514 sm_ierror("TLS peer aborted connection");
1521 sm_ierror("SSL_read failed: %s",
1522 ERR_error_string(ERR_get_error(), NULL
));
1526 #endif /* TLS_SUPPORT */
1528 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1534 sm_ierror("Unable to read from network: %s", strerror(errno
));
1539 * Don't call sasl_decode unless sasl is complete and we have
1540 * encryption working
1544 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1548 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1551 if (result
!= SASL_OK
) {
1552 sm_ierror("Unable to decode SASL network data: %s",
1553 sasl_errdetail(conn
));
1557 #else /* ! CYRUS_SASL */
1560 #endif /* CYRUS_SASL */
1563 if (retbufsize
> SASL_MAXRECVBUF
) {
1564 sm_ierror("Received data (%d bytes) is larger than the buffer "
1565 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1569 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1570 sasl_inptr
= sasl_inbuffer
+ 1;
1571 sasl_inbuflen
= retbufsize
- 1;
1573 return (int) sasl_inbuffer
[0];
1575 #endif /* CYRUS_SASL || TLS_SUPPORT */
1580 if (sm_mts
== MTS_SMTP
)
1582 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1583 : sm_alarmed
? "read from socket timed out"
1584 : rc
== RP_EOF
? "premature end-of-file on socket"
1585 : "error reading from socket"));
1588 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1589 : sm_alarmed
? "read from pipe timed out"
1590 : rc
== RP_EOF
? "premature end-of-file on pipe"
1591 : "error reading from pipe"));
1593 return (sm_reply
.code
= NOTOK
);
1603 #ifndef RELIABLE_SIGNALS
1604 SIGNAL (SIGALRM
, alrmser
);
1609 printf ("timed out...\n");
1616 rp_string (int code
)
1619 static char buffer
[BUFSIZ
];
1621 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1641 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1661 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1662 text
, sm_reply
.code
, sm_reply
.text
);
1674 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1676 if (strncmp (ep
, s
, len
) == 0) {
1677 for (ep
+= len
; *ep
== ' '; ep
++)
1687 * Our SASL callback; we are either given SASL tokens to generate network
1688 * protocols messages for, or we decode incoming protocol messages and
1689 * convert them to binary SASL tokens to pass up into the SASL library.
1693 sm_sasl_callback(enum sasl_message_type mtype
, unsigned const char *indata
,
1694 unsigned int indatalen
, unsigned char **outdata
,
1695 unsigned int *outdatalen
, char **errstr
)
1697 int rc
, snoopoffset
;
1702 case NETSEC_SASL_START
:
1704 * Generate an AUTH message; if we were given an input token
1705 * then generate a an AUTH message that includes the initial
1709 mech
= netsec_get_sasl_mechanism(nsc
);
1714 b64data
= mh_xmalloc(BASE64SIZE(indatalen
));
1715 writeBase64raw(indata
, indatalen
, (unsigned char *) b64data
);
1717 netsec_set_snoop_callback(nsc
, netsec_b64_snoop_decoder
,
1719 snoopoffset
= 6 + strlen(mech
);
1720 rc
= netsec_printf(nsc
, errstr
, "AUTH %s %s\r\n", mech
, b64data
);
1722 netsec_set_snoop_callback(nsc
, NULL
, NULL
);
1724 rc
= netsec_printf(nsc
, errstr
, "AUTH %s\r\n", mech
);
1730 if (netsec_flush(nsc
, errstr
) != OK
)
1735 case NETSEC_SASL_READ
:
1737 * Read in a line that should contain a 334 response code, followed
1738 * by base64 response data.
1741 netsec_set_snoop_callback(nsc
, netsec_b64_snoop_decoder
, &snoopoffset
);
1743 line
= netsec_readline(nsc
, &len
, errstr
);
1744 netsec_set_snoop_callback(nsc
, NULL
, NULL
);
1750 netsec_err(errstr
, "Invalid format for SASL response");
1754 if (strncmp(line
, "334 ", 4) != 0) {
1755 netsec_err(errstr
, "Improper SASL protocol response: %s", line
);
1763 rc
= decodeBase64(line
+ 4, (const char **) outdata
, &len
, 0, NULL
);
1765 netsec_err(errstr
, "Unable to decode base64 response");
1772 case NETSEC_SASL_WRITE
:
1774 * The output encoding is pretty simple, so this is easy.
1776 if (indatalen
== 0) {
1777 rc
= netsec_printf(nsc
, errstr
, "\r\n");
1779 unsigned char *b64data
;
1780 b64data
= mh_xmalloc(BASE64SIZE(indatalen
));
1781 writeBase64raw(indata
, indatalen
, b64data
);
1782 netsec_set_snoop_callback(nsc
, netsec_b64_snoop_decoder
, NULL
);
1783 rc
= netsec_printf(nsc
, errstr
, "%s\r\n", b64data
);
1784 netsec_set_snoop_callback(nsc
, NULL
, NULL
);
1791 if (netsec_flush(nsc
, errstr
) != OK
)
1795 case NETSEC_SASL_FINISH
:
1797 * Finish the protocol; we're looking for a 235 message.
1799 line
= netsec_readline(nsc
, &len
, errstr
);
1803 if (strncmp(line
, "235 ", 4) != 0) {
1805 netsec_err(errstr
, "Authentication failed: %s", line
+ 4);
1807 netsec_err(errstr
, "Authentication failed: %s", line
);
1812 case NETSEC_SASL_CANCEL
:
1814 * Cancel the SASL exchange; this is done by sending a single "*".
1816 rc
= netsec_printf(nsc
, errstr
, "*\r\n");
1818 rc
= netsec_flush(nsc
, errstr
);