2 * smtp.c -- nmh SMTP interface
4 * This code is Copyright (c) 2002, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
12 #include <h/signals.h>
17 * This module implements an interface to SendMail very similar
18 * to the MMDF mm_(3) routines. The sm_() routines herein talk
19 * SMTP to a sendmail process, mapping SMTP reply codes into
24 * On older 4.2BSD machines without the POSIX function `sigaction',
25 * the alarm handing stuff for time-outs will NOT work due to the way
26 * syscalls get restarted. This is not really crucial, since SendMail
27 * is generally well-behaved in this area.
32 * It appears that some versions of Sendmail will return Code 451
33 * when they don't really want to indicate a failure.
34 * "Code 451 almost always means sendmail has deferred; we don't
35 * really want bomb out at this point since sendmail will rectify
36 * things later." So, if you define SENDMAILBUG, Code 451 is
37 * considered the same as Code 250. Yuck!
44 #define NBITS ((sizeof (int)) * 8)
47 * these codes must all be different!
49 #define SM_OPEN 300 /* Changed to 5 minutes to comply with a SHOULD in RFC 1123 */
52 #define SM_MAIL 301 /* changed to 5 minutes and a second (for uniqueness), see above */
53 #define SM_RCPT 302 /* see above */
54 #define SM_DATA 120 /* see above */
55 #define SM_TEXT 180 /* see above */
56 #define SM_DOT 600 /* see above */
61 static int sm_addrs
= 0;
62 static int sm_alarmed
= 0;
63 static int sm_child
= NOTOK
;
64 static int sm_debug
= 0;
65 static int sm_nl
= TRUE
;
66 static int sm_verbose
= 0;
67 static netsec_context
*nsc
= NULL
;
69 static int next_line_encoded
= 0;
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 *, 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 int sm_rrecord (char *, int *);
151 static int sm_rerror (int);
152 static void alrmser (int);
153 static char *EHLOset (char *);
154 static char *prepare_for_display (const char *, int *);
155 static int sm_fwrite(char *, int);
156 static int sm_fputs(char *);
157 static int sm_fputc(int);
158 static void sm_fflush(void);
159 static int sm_fgets(char *, int, FILE *);
160 static int sm_sasl_callback(enum sasl_message_type
, unsigned const char *,
161 unsigned int, unsigned char **, unsigned int *,
165 sm_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
166 int debug
, int sasl
, const char *saslmech
, const char *user
,
167 const char *oauth_svc
, int tls
)
169 if (sm_mts
== MTS_SMTP
)
170 return smtp_init (client
, server
, port
, watch
, verbose
,
171 debug
, sasl
, saslmech
, user
, oauth_svc
, tls
);
173 return sendmail_init (client
, server
, watch
, verbose
,
174 debug
, sasl
, saslmech
, user
);
178 smtp_init (char *client
, char *server
, char *port
, int watch
, int verbose
,
179 int debug
, int sasl
, const char *saslmech
, const char *user
,
180 const char *oauth_svc
, int tls
)
188 sm_verbose
= verbose
;
194 if (client
== NULL
|| *client
== '\0') {
198 client
= LocalName(1); /* no clientname -> LocalName */
203 * Last-ditch check just in case client still isn't set to anything
206 if (client
== NULL
|| *client
== '\0')
207 client
= "localhost";
212 netsec_set_userid(nsc
, user
);
215 if (netsec_set_tls(nsc
, 1, &errstr
) != OK
)
216 return sm_nerror(errstr
);
220 netsec_set_snoop(nsc
, 1);
223 if (netsec_set_sasl_params(nsc
, client
, "smtp", saslmech
,
224 sm_sasl_callback
, &errstr
) != OK
)
225 return sm_nerror(errstr
);
229 if (netsec_set_oauth_service(nsc
, oauth_svc
) != OK
)
230 return sm_ierror("OAuth2 not supported");
233 if ((sd1
= rclient (server
, port
)) == NOTOK
)
236 SIGNAL (SIGALRM
, alrmser
);
237 SIGNAL (SIGPIPE
, SIG_IGN
);
239 netsec_set_fd(nsc
, sd1
, sd1
);
242 * If tls == 2, that means that the user requested "initial" TLS,
243 * which happens right after the connection has opened. Do that
248 if (netsec_negotiate_tls(nsc
, &errstr
) != OK
) {
250 return sm_nerror(errstr
);
254 netsec_set_timeout(nsc
, SM_OPEN
);
267 * Give EHLO or HELO command
271 result
= smtalk (SM_HELO
, "EHLO %s", client
);
274 if (result
>= 500 && result
<= 599)
275 result
= smtalk (SM_HELO
, "HELO %s", client
);
283 * If the user requested TLS support, then try to do the STARTTLS command
284 * as part of the initial dialog. Assuming this works, we then need to
285 * restart the EHLO dialog after TLS negotiation is complete.
289 if (! EHLOset("STARTTLS")) {
291 return sm_ierror("SMTP server does not support TLS");
294 result
= smtalk(SM_HELO
, "STARTTLS");
302 * Okay, the other side should be waiting for us to start TLS
303 * negotiation. Oblige them.
306 if (netsec_negotiate_tls(nsc
, errstr
) != OK
) {
308 return sm_nerror(errstr
);
312 result
= smtalk (SM_HELO
, "EHLO %s", client
);
322 * If the user asked for SASL, then check to see if the SMTP server
323 * supports it. Otherwise, error out (because the SMTP server
324 * might have been spoofed; we don't want to just silently not
330 if (! (server_mechs
= EHLOset("AUTH"))) {
332 return sm_ierror("SMTP server does not support SASL");
335 if (netsec_negotiate_sasl(nsc
, server_mechs
, &errstr
) != OK
) {
337 return sm_nerror(errstr
);
342 if (watch
&& EHLOset ("XVRB"))
343 smtalk (SM_HELO
, "VERB on");
349 sendmail_init (char *client
, char *server
, int watch
, int verbose
,
350 int debug
, int sasl
, const char *saslmech
, const char *user
)
352 unsigned int i
, result
, vecp
;
359 sm_verbose
= verbose
;
361 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
364 if (client
== NULL
|| *client
== '\0') {
368 client
= LocalName(1); /* no clientname -> LocalName */
372 * Last-ditch check just in case client still isn't set to anything
375 if (client
== NULL
|| *client
== '\0')
376 client
= "localhost";
378 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
379 sasl_inbuffer
= malloc(SASL_MAXRECVBUF
);
381 return sm_ierror("Unable to allocate %d bytes for read buffer",
383 #endif /* CYRUS_SASL || TLS_SUPPORT */
385 if (pipe (pdi
) == NOTOK
)
386 return sm_ierror ("no pipes");
387 if (pipe (pdo
) == NOTOK
) {
390 return sm_ierror ("no pipes");
393 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
402 return sm_ierror ("unable to fork");
405 if (pdo
[0] != fileno (stdin
))
406 dup2 (pdo
[0], fileno (stdin
));
407 if (pdi
[1] != fileno (stdout
))
408 dup2 (pdi
[1], fileno (stdout
));
409 if (pdi
[1] != fileno (stderr
))
410 dup2 (pdi
[1], fileno (stderr
));
411 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
415 vec
[vecp
++] = r1bindex (sendmail
, '/');
417 vec
[vecp
++] = watch
? "-odi" : "-odb";
418 vec
[vecp
++] = "-oem";
424 execvp (sendmail
, vec
);
425 fprintf (stderr
, "unable to exec ");
427 _exit (-1); /* NOTREACHED */
430 SIGNAL (SIGALRM
, alrmser
);
431 SIGNAL (SIGPIPE
, SIG_IGN
);
435 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
436 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
439 sm_rfp
= sm_wfp
= NULL
;
440 return sm_ierror ("unable to fdopen");
456 result
= smtalk (SM_HELO
, "EHLO %s", client
);
459 if (500 <= result
&& result
<= 599)
460 result
= smtalk (SM_HELO
, "HELO %s", client
);
473 * If the user asked for SASL, then check to see if the SMTP server
474 * supports it. Otherwise, error out (because the SMTP server
475 * might have been spoofed; we don't want to just silently not
480 if (! (server_mechs
= EHLOset("AUTH"))) {
482 return sm_ierror("SMTP server does not support SASL");
485 if (saslmech
&& stringdex(saslmech
, server_mechs
) == -1) {
487 return sm_ierror("Requested SASL mech \"%s\" is not in the "
488 "list of supported mechanisms:\n%s",
489 saslmech
, server_mechs
);
492 if (sm_auth_sasl(user
, saslssf
, saslmech
? saslmech
: server_mechs
,
498 #endif /* CYRUS_SASL */
501 smtalk (SM_HELO
, "VERB on");
508 rclient (char *server
, char *service
)
511 char response
[BUFSIZ
];
513 if ((sd
= client (server
, service
, response
, sizeof(response
),
517 sm_ierror ("%s", response
);
522 sm_winit (char *from
)
524 switch (smtalk (SM_MAIL
, "MAIL FROM:<%s>", from
)) {
541 sm_wadr (char *mbox
, char *host
, char *path
)
543 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
545 path
? path
: "", mbox
, host
)) {
555 #endif /* SENDMAILBUG */
580 switch (smtalk (SM_DATA
, "DATA")) {
589 #endif /* SENDMAILBUG */
606 sm_wtxt (char *buffer
, int len
)
612 result
= sm_wstream (buffer
, len
);
615 return (result
== NOTOK
? RP_BHST
: RP_OK
);
622 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
625 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
633 #endif /* SENDMAILBUG */
651 if (sm_mts
== MTS_SENDMAIL_SMTP
) {
667 smtalk (SM_QUIT
, "QUIT");
671 sm_note
.code
= sm_reply
.code
;
672 sm_note
.length
= sm_reply
.length
;
673 memcpy (sm_note
.text
, sm_reply
.text
, sm_reply
.length
+ 1);/* fall */
675 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
677 if (sm_mts
== MTS_SMTP
)
678 smtalk (SM_QUIT
, "QUIT");
680 /* The SIGPIPE block replaces old calls to discard ().
681 We're not sure what the discard () calls were for,
682 maybe to prevent deadlock on old systems. In any
683 case, blocking SIGPIPE should be harmless.
684 Because the file handles are closed below, leave it
688 sigaddset (&set
, SIGPIPE
);
689 sigprocmask (SIG_BLOCK
, &set
, &oset
);
691 kill (sm_child
, SIGKILL
);
695 sm_reply
.code
= sm_note
.code
;
696 sm_reply
.length
= sm_note
.length
;
697 memcpy (sm_reply
.text
, sm_note
.text
, sm_note
.length
+ 1);
704 netsec_shutdown(nsc
, 1);
709 if (sm_mts
== MTS_SMTP
) {
711 } else if (sm_child
!= NOTOK
) {
712 status
= pidwait (sm_child
, OK
);
718 return (status
? RP_BHST
: RP_OK
);
723 * This function implements SASL authentication for SMTP. If this function
724 * completes successfully, then authentication is successful and we've
725 * (optionally) negotiated a security layer.
728 #define CHECKB64SIZE(insize, outbuf, outsize) \
729 { size_t wantout = (((insize + 2) / 3) * 4) + 32; \
730 if (wantout > outsize) { \
731 outbuf = mh_xrealloc(outbuf, outsize = wantout); \
736 sm_auth_sasl(char *user
, int saslssf
, char *mechlist
, char *inhost
)
739 unsigned int buflen
, outlen
;
740 char *buf
, *outbuf
= NULL
, host
[NI_MAXHOST
];
741 const char *chosen_mech
;
742 sasl_security_properties_t secprops
;
745 struct nmh_creds creds
= { 0, 0, 0 };
746 size_t outbufsize
= 0;
749 * Initialize the callback contexts
753 * This is a _bit_ of a hack ... but if the hostname wasn't supplied
754 * to us on the command line, then call getpeername and do a
755 * reverse-address lookup on the IP address to get the name.
758 memset(host
, 0, sizeof(host
));
761 struct sockaddr_storage sin
;
762 socklen_t len
= sizeof(sin
);
765 if (getpeername(fileno(sm_wfp
), (struct sockaddr
*) &sin
, &len
) < 0) {
766 sm_ierror("getpeername on SMTP socket failed: %s",
771 result
= getnameinfo((struct sockaddr
*) &sin
, len
, host
, sizeof(host
),
772 NULL
, 0, NI_NAMEREQD
);
774 sm_ierror("Unable to look up name of connected host: %s",
775 gai_strerror(result
));
779 strncpy(host
, inhost
, sizeof(host
) - 1);
782 /* It's OK to copy the addresses here. The callbacks that use
783 them will only be called before this function returns. */
786 callbacks
[SM_SASL_N_CB_USER
].context
= &creds
;
787 callbacks
[SM_SASL_N_CB_AUTHNAME
].context
= &creds
;
788 callbacks
[SM_SASL_N_CB_PASS
].context
= &creds
;
790 result
= sasl_client_init(callbacks
);
792 if (result
!= SASL_OK
) {
793 sm_ierror("SASL library initialization failed: %s",
794 sasl_errstring(result
, NULL
, NULL
));
798 result
= sasl_client_new("smtp", host
, NULL
, NULL
, NULL
, 0, &conn
);
800 if (result
!= SASL_OK
) {
801 sm_ierror("SASL client initialization failed: %s",
802 sasl_errstring(result
, NULL
, NULL
));
807 * Initialize the security properties. But if TLS is active, then
808 * don't negotiate encryption here.
811 memset(&secprops
, 0, sizeof(secprops
));
812 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
814 tls_active
? 0 : (saslssf
!= -1 ? (unsigned int) saslssf
: UINT_MAX
);
816 result
= sasl_setprop(conn
, SASL_SEC_PROPS
, &secprops
);
818 if (result
!= SASL_OK
) {
819 sm_ierror("SASL security property initialization failed: %s",
820 sasl_errstring(result
, NULL
, NULL
));
825 * Start the actual protocol. Feed the mech list into the library
826 * and get out a possible initial challenge
829 result
= sasl_client_start(conn
, mechlist
, NULL
, (const char **) &buf
,
830 &buflen
, (const char **) &chosen_mech
);
832 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
833 sm_ierror("SASL client start failed: %s", sasl_errdetail(conn
));
838 * If we got an initial challenge, send it as part of the AUTH
839 * command; otherwise, just send a plain AUTH command.
843 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
844 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
845 if (status
!= SASL_OK
) {
846 sm_ierror("SASL base64 encode failed: %s",
847 sasl_errstring(status
, NULL
, NULL
));
853 status
= smtalk(SM_AUTH
, "AUTH %s %s", chosen_mech
, outbuf
);
855 status
= smtalk(SM_AUTH
, "AUTH %s", chosen_mech
);
858 * Now we loop until we either fail, get a SASL_OK, or a 235
859 * response code. Receive the challenges and process them until
863 while (result
== SASL_CONTINUE
) {
866 * If we get a 235 response, that means authentication has
867 * succeeded and we need to break out of the loop (yes, even if
868 * we still get SASL_CONTINUE from sasl_client_step()).
870 * Otherwise, if we get a message that doesn't seem to be a
871 * valid response, then abort
876 else if (status
< 300 || status
> 399) {
883 * Special case; a zero-length response from the SMTP server
884 * is returned as a single =. If we get that, then set buflen
885 * to be zero. Otherwise, just decode the response.
888 if (strcmp("=", sm_reply
.text
) == 0) {
891 if (sm_reply
.length
> (int) outbufsize
) {
892 outbuf
= mh_xrealloc(outbuf
, outbufsize
= sm_reply
.length
);
895 result
= sasl_decode64(sm_reply
.text
, sm_reply
.length
,
896 outbuf
, outbufsize
, &outlen
);
897 if (result
!= SASL_OK
) {
898 smtalk(SM_AUTH
, "*");
899 sm_ierror("SASL base64 decode failed: %s",
900 sasl_errstring(result
, NULL
, NULL
));
907 result
= sasl_client_step(conn
, outbuf
, outlen
, NULL
,
908 (const char **) &buf
, &buflen
);
910 if (result
!= SASL_OK
&& result
!= SASL_CONTINUE
) {
911 smtalk(SM_AUTH
, "*");
912 sm_ierror("SASL client negotiation failed: %s",
913 sasl_errstring(result
, NULL
, NULL
));
919 CHECKB64SIZE(buflen
, outbuf
, outbufsize
);
920 status
= sasl_encode64(buf
, buflen
, outbuf
, outbufsize
, NULL
);
922 if (status
!= SASL_OK
) {
923 smtalk(SM_AUTH
, "*");
924 sm_ierror("SASL base64 encode failed: %s",
925 sasl_errstring(status
, NULL
, NULL
));
931 status
= smtalk(SM_AUTH
, outbuf
);
938 * Make sure that we got the correct response
941 if (status
< 200 || status
> 299)
945 * We _should_ have completed the authentication successfully.
946 * Get a few properties from the authentication exchange.
949 result
= sasl_getprop(conn
, SASL_MAXOUTBUF
, (const void **) &outbufmax
);
951 if (result
!= SASL_OK
) {
952 sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s",
953 sasl_errstring(result
, NULL
, NULL
));
957 maxoutbuf
= *outbufmax
;
959 result
= sasl_getprop(conn
, SASL_SSF
, (const void **) &ssf
);
963 if (result
!= SASL_OK
) {
964 sm_ierror("Cannot retrieve SASL negotiated security strength "
965 "factor: %s", sasl_errstring(result
, NULL
, NULL
));
970 sasl_outbuffer
= malloc(maxoutbuf
);
972 if (sasl_outbuffer
== NULL
) {
973 sm_ierror("Unable to allocate %d bytes for SASL output "
974 "buffer", maxoutbuf
);
979 sasl_inptr
= sasl_inbuffer
;
981 sasl_outbuffer
= NULL
;
982 /* Don't NULL out sasl_inbuffer because it could be used in
992 * Our callback functions to feed data to the SASL library
996 sm_get_user(void *context
, int id
, const char **result
, unsigned *len
)
998 nmh_creds_t creds
= (nmh_creds_t
) context
;
1000 if (! result
|| ((id
!= SASL_CB_USER
) && (id
!= SASL_CB_AUTHNAME
)))
1001 return SASL_BADPARAM
;
1003 if (creds
->user
== NULL
) {
1005 * Pass the 1 third argument to nmh_get_credentials() so
1006 * that a default user if the -user switch to send(1)/post(8)
1007 * wasn't used, and so that a default password will be supplied.
1008 * That's used when those values really don't matter, and only
1009 * with legacy/.netrc, i.e., with a credentials profile entry.
1011 if (nmh_get_credentials (creds
->host
, creds
->user
, 1, creds
) != OK
) {
1012 return SASL_BADPARAM
;
1016 *result
= creds
->user
;
1018 *len
= strlen(creds
->user
);
1024 sm_get_pass(sasl_conn_t
*conn
, void *context
, int id
,
1025 sasl_secret_t
**psecret
)
1027 nmh_creds_t creds
= (nmh_creds_t
) context
;
1032 if (! psecret
|| id
!= SASL_CB_PASS
)
1033 return SASL_BADPARAM
;
1035 if (creds
->password
== NULL
) {
1037 * Pass the 0 third argument to nmh_get_credentials() so
1038 * that the default password isn't used. With legacy/.netrc
1039 * credentials support, we'll only get here if the -user
1040 * switch to send(1)/post(8) wasn't used.
1042 if (nmh_get_credentials (creds
->host
, creds
->user
, 0, creds
) != OK
) {
1043 return SASL_BADPARAM
;
1047 len
= strlen (creds
->password
);
1049 if (! (*psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
))) {
1053 (*psecret
)->len
= len
;
1054 strcpy((char *) (*psecret
)->data
, creds
->password
);
1058 #endif /* CYRUS_SASL */
1060 /* https://developers.google.com/gmail/xoauth2_protocol */
1062 sm_auth_xoauth2(const char *user
, const char *oauth_svc
, int snoop
)
1064 const char *xoauth_client_res
;
1068 xoauth_client_res
= mh_oauth_do_xoauth(user
, oauth_svc
,
1069 snoop
? stderr
: NULL
);
1071 if (xoauth_client_res
== NULL
) {
1072 return sm_ierror("Internal error: mh_oauth_do_xoauth() returned NULL");
1077 adios(NULL
, "sendfrom built without OAUTH_SUPPORT, "
1078 "so oauth_svc %s is not supported", oauth_svc
);
1079 #endif /* OAUTH_SUPPORT */
1081 status
= smtalk(SM_AUTH
, "AUTH XOAUTH2 %s", xoauth_client_res
);
1082 if (status
== 235) {
1088 * Status is 334 and sm_reply.text contains base64-encoded JSON. As far as
1089 * epg can tell, no matter the error, the JSON is always the same:
1090 * {"status":"400","schemes":"Bearer","scope":"https://mail.google.com/"}
1091 * I tried these errors:
1097 /* Then we're supposed to send an empty response ("\r\n"). */
1098 smtalk(SM_AUTH
, "");
1100 * And now we always get this, again, no matter the error:
1101 * 535-5.7.8 Username and Password not accepted. Learn more at
1102 * 535 5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257
1108 sm_ierror (const char *fmt
, ...)
1113 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
1116 sm_reply
.length
= strlen (sm_reply
.text
);
1117 sm_reply
.code
= NOTOK
;
1123 * Like sm_ierror, but assume it's an allocated error string we need to free.
1127 sm_nerror (char *str
)
1129 strncpy(sm_reply
.text
, str
, sizeof(sm_reply
.text
));
1130 sm_reply
.text
[sizeof(sm_reply
.text
) - 1] = '\0';
1131 sm_reply
.length
= strlen(sm_reply
.text
);
1132 sm_reply
.code
= NOTOK
;
1139 smtalk (int time
, char *fmt
, ...)
1145 result
= netsec_vprintf (nsc
, &errstr
, fmt
, ap
);
1149 return sm_nerror(errstr
);
1151 if (netsec_printf (nsc
, &errstr
, "\r\n") != OK
)
1152 return sm_nerror(errstr
);
1154 if (netsec_flush (nsc
, &errstr
) != OK
)
1155 return sm_nerror(errstr
);
1157 netsec_set_timeout(nsc
, time
);
1164 sm_wstream (char *buffer
, int len
)
1167 static char lc
= '\0';
1170 return sm_werror ();
1172 if (buffer
== NULL
&& len
== 0) {
1176 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1179 for (bp
= buffer
; bp
&& len
> 0; bp
++, len
--) {
1188 sm_fputc ('.');/* FALL THROUGH */
1193 if (ferror (sm_wfp
))
1194 return sm_werror ();
1199 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1203 * Write out to the network, but do buffering for SASL (if enabled)
1207 sm_fwrite(char *buffer
, int len
)
1211 unsigned int outputlen
;
1213 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1214 #endif /* CYRUS_SASL */
1219 ret
= BIO_write(io
, buffer
, len
);
1222 sm_ierror("TLS error during write: %s",
1223 ERR_error_string(ERR_get_error(), NULL
));
1227 #endif /* TLS_SUPPORT */
1228 if ((int) fwrite(buffer
, sizeof(*buffer
), len
, sm_wfp
) < len
) {
1229 advise ("sm_fwrite", "fwrite");
1233 while (len
>= maxoutbuf
- sasl_outbuflen
) {
1234 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
,
1235 maxoutbuf
- sasl_outbuflen
);
1236 len
-= maxoutbuf
- sasl_outbuflen
;
1239 if (sasl_encode(conn
, sasl_outbuffer
, maxoutbuf
,
1240 &output
, &outputlen
) != SASL_OK
) {
1241 sm_ierror("Unable to SASL encode connection data: %s",
1242 sasl_errdetail(conn
));
1246 if (fwrite(output
, sizeof(*output
), outputlen
, sm_wfp
) <
1248 advise ("sm_fwrite", "fwrite");
1253 memcpy(sasl_outbuffer
+ sasl_outbuflen
, buffer
, len
);
1254 sasl_outbuflen
+= len
;
1257 #endif /* CYRUS_SASL */
1258 return ferror(sm_wfp
) ? NOTOK
: RP_OK
;
1265 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1266 : sm_alarmed
? "write to socket timed out"
1267 : "error writing to socket"));
1269 return (sm_reply
.code
= NOTOK
);
1276 int i
, code
, cont
, rc
, more
;
1281 char **ehlo
= EHLOkeys
, *buffer
;
1284 static int at_least_once
= 0;
1286 if (at_least_once
) {
1289 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1303 sm_reply
.length
= 0;
1304 sm_reply
.text
[0] = 0;
1306 rc
= sizeof(sm_reply
.text
) - 1;
1308 for (more
= FALSE
; (buffer
= netsec_readline(nsc
, &buflen
,
1309 &errstr
)) != NULL
; ) {
1312 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1313 && (buffer
[3] == '-' || doingEHLO
== 2)
1315 if (doingEHLO
== 2) {
1316 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1317 strcpy (*ehlo
++, buffer
+ 4);
1319 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1329 bp
= (unsigned char *) buffer
;
1331 for (; buflen
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, buflen
--)
1335 code
= atoi ((char *) bp
);
1336 bp
+= 3, buflen
-= 3;
1337 for (; buflen
> 0 && isspace (*bp
); bp
++, buflen
--)
1339 if (buflen
> 0 && *bp
== '-') {
1342 for (; buflen
> 0 && isspace (*bp
); bp
++, buflen
--)
1347 if (code
!= sm_reply
.code
|| cont
)
1351 sm_reply
.code
= code
;
1354 bp
= (unsigned char *) sm_noreply
;
1355 buflen
= strlen (sm_noreply
);
1359 if ((i
= min (buflen
, rc
)) > 0) {
1363 i
= strlen(sm_moreply
);
1364 if (more
&& rc
> i
+ 1) {
1365 memcpy (rp
, sm_moreply
, i
); /* safe because of check in if() */
1372 if (sm_reply
.code
< 100) {
1374 printf ("%s\n", sm_reply
.text
);
1380 sm_reply
.length
= rp
- sm_reply
.text
;
1381 sm_reply
.text
[sm_reply
.length
] = 0;
1382 return sm_reply
.code
;
1391 sm_rrecord (char *buffer
, int *len
)
1400 buffer
[*len
= 0] = 0;
1402 str
= netsec_readline(nsc
, &strlen
, &errstr
);
1403 if ((retval
= netsec_readline(nsc
,
1404 if ((retval
= sm_fgets (buffer
, BUFSIZ
, sm_rfp
)) != RP_OK
)
1405 return sm_rerror (retval
);
1406 *len
= strlen (buffer
);
1407 /* *len should be >0 except on EOF, but check for safety's sake */
1409 return sm_rerror (RP_EOF
);
1410 if (buffer
[*len
- 1] != '\n')
1411 while ((retval
= sm_fgetc (sm_rfp
)) != '\n' && retval
!= EOF
&&
1415 if ((*len
> 1) && (buffer
[*len
- 2] == '\r'))
1424 * Our version of fgets, which calls our private fgetc function
1428 sm_fgets(char *buffer
, int size
, FILE *f
)
1442 } while (size
> 1 && c
!= '\n');
1450 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
1452 * Read from the network, but do SASL or TLS encryption
1458 char tmpbuf
[BUFSIZ
], *retbuf
;
1459 unsigned int retbufsize
= 0;
1463 * If we have leftover data, return it
1466 if (sasl_inbuflen
) {
1468 return (int) *sasl_inptr
++;
1472 * If not, read from the network until we have some data to return
1475 while (retbufsize
== 0) {
1479 cc
= SSL_read(ssl
, tmpbuf
, sizeof(tmpbuf
));
1482 result
= SSL_get_error(ssl
, cc
);
1484 if (result
!= SSL_ERROR_ZERO_RETURN
) {
1485 sm_ierror("TLS peer aborted connection");
1492 sm_ierror("SSL_read failed: %s",
1493 ERR_error_string(ERR_get_error(), NULL
));
1497 #endif /* TLS_SUPPORT */
1499 cc
= read(fileno(f
), tmpbuf
, sizeof(tmpbuf
));
1505 sm_ierror("Unable to read from network: %s", strerror(errno
));
1510 * Don't call sasl_decode unless sasl is complete and we have
1511 * encryption working
1515 if (sasl_complete
== 0 || sasl_ssf
== 0) {
1519 result
= sasl_decode(conn
, tmpbuf
, cc
, (const char **) &retbuf
,
1522 if (result
!= SASL_OK
) {
1523 sm_ierror("Unable to decode SASL network data: %s",
1524 sasl_errdetail(conn
));
1528 #else /* ! CYRUS_SASL */
1531 #endif /* CYRUS_SASL */
1534 if (retbufsize
> SASL_MAXRECVBUF
) {
1535 sm_ierror("Received data (%d bytes) is larger than the buffer "
1536 "size (%d bytes)", retbufsize
, SASL_MAXRECVBUF
);
1540 memcpy(sasl_inbuffer
, retbuf
, retbufsize
);
1541 sasl_inptr
= sasl_inbuffer
+ 1;
1542 sasl_inbuflen
= retbufsize
- 1;
1544 return (int) sasl_inbuffer
[0];
1546 #endif /* CYRUS_SASL || TLS_SUPPORT */
1551 if (sm_mts
== MTS_SMTP
)
1553 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1554 : sm_alarmed
? "read from socket timed out"
1555 : rc
== RP_EOF
? "premature end-of-file on socket"
1556 : "error reading from socket"));
1559 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
1560 : sm_alarmed
? "read from pipe timed out"
1561 : rc
== RP_EOF
? "premature end-of-file on pipe"
1562 : "error reading from pipe"));
1564 return (sm_reply
.code
= NOTOK
);
1573 #ifndef RELIABLE_SIGNALS
1574 SIGNAL (SIGALRM
, alrmser
);
1579 printf ("timed out...\n");
1586 rp_string (int code
)
1589 static char buffer
[BUFSIZ
];
1591 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1611 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1631 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1632 text
, sm_reply
.code
, sm_reply
.text
);
1644 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1646 if (strncmp (ep
, s
, len
) == 0) {
1647 for (ep
+= len
; *ep
== ' '; ep
++)
1658 * Detects, using heuristics, if an SMTP server or client response string
1659 * contains a base64-encoded portion. If it does, decodes it and replaces
1660 * any non-printable characters with a hex representation. Caller is
1661 * responsible for free'ing return value. If the decode fails, a copy of
1662 * the input string is returned.
1666 prepare_for_display (const char *string
, int *next_line_encoded
) {
1667 const char *start
= NULL
;
1668 const char *decoded
;
1670 int prefix_len
= -1;
1672 if (strncmp (string
, "AUTH ", 5) == 0) {
1673 /* AUTH line: the mechanism isn't encoded. If there's an initial
1674 response, it must be base64 encoded.. */
1675 char *mechanism
= strchr (string
+ 5, ' ');
1677 if (mechanism
!= NULL
) {
1678 prefix_len
= (int) (mechanism
- string
+ 1);
1679 } /* else no space following the mechanism, so no initial response */
1680 *next_line_encoded
= 0;
1681 } else if (strncmp (string
, "334 ", 4) == 0) {
1682 /* 334 is the server's request for user or password. */
1684 /* The next (client response) line must be base64 encoded. */
1685 *next_line_encoded
= 1;
1686 } else if (*next_line_encoded
) {
1687 /* "next" line now refers to this line, which is a base64-encoded
1690 *next_line_encoded
= 0;
1692 *next_line_encoded
= 0;
1695 /* Don't attempt to decoded unencoded initial response ('=') or cancel
1697 if (prefix_len
> -1 &&
1698 string
[prefix_len
] != '=' && string
[prefix_len
] != '*') {
1699 start
= string
+ prefix_len
;
1702 if (start
&& decodeBase64 (start
, &decoded
, &decoded_len
, 1, NULL
) == OK
) {
1704 char *prefix
= mh_xmalloc(prefix_len
+ 1);
1705 char *display_string
;
1707 /* prefix is the beginning portion, which isn't base64 encoded. */
1708 snprintf (prefix
, prefix_len
+ 1, "%*s", prefix_len
, string
);
1709 hexify ((const unsigned char *) decoded
, decoded_len
, &hexified
);
1710 /* Wrap the decoded portion in "b64<>". */
1711 display_string
= concat (prefix
, "b64<", hexified
, ">", NULL
);
1714 free ((char *) decoded
);
1716 return display_string
;
1718 return getcpy (string
);