X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/dd740c4e3e407d8dba7884bb599c1f5a588b05e9..f1920d78123667716f2321d37ce37628603b2700:/mts/smtp/smtp.c diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c index 0261d6d6..873e0cd8 100644 --- a/mts/smtp/smtp.c +++ b/mts/smtp/smtp.c @@ -10,6 +10,7 @@ #include "smtp.h" #include #include +#include #ifdef CYRUS_SASL #include @@ -151,9 +152,9 @@ static char *EHLOkeys[MAXEHLO + 1]; /* * static prototypes */ -static int smtp_init (char *, char *, char *, int, int, int, int, int, int, +static int smtp_init (char *, char *, char *, int, int, int, int, int, char *, char *, int); -static int sendmail_init (char *, char *, int, int, int, int, int, int, +static int sendmail_init (char *, char *, int, int, int, int, int, char *, char *); static int rclient (char *, char *); @@ -183,22 +184,19 @@ static int sm_auth_sasl(char *, int, char *, char *); int sm_init (char *client, char *server, char *port, int watch, int verbose, - int debug, int queued, int sasl, int saslssf, - char *saslmech, char *user, int tls) + int debug, int sasl, int saslssf, char *saslmech, char *user, int tls) { if (sm_mts == MTS_SMTP) return smtp_init (client, server, port, watch, verbose, - debug, queued, sasl, saslssf, saslmech, - user, tls); + debug, sasl, saslssf, saslmech, user, tls); else return sendmail_init (client, server, watch, verbose, - debug, queued, sasl, saslssf, saslmech, - user); + debug, sasl, saslssf, saslmech, user); } static int smtp_init (char *client, char *server, char *port, int watch, int verbose, - int debug, int queued, + int debug, int sasl, int saslssf, char *saslmech, char *user, int tls) { int result, sd1, sd2; @@ -387,16 +385,13 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, send_options: ; if (watch && EHLOset ("XVRB")) smtalk (SM_HELO, "VERB on"); - if (queued && EHLOset ("XQUE")) - smtalk (SM_HELO, "QUED"); return RP_OK; } int sendmail_init (char *client, char *server, int watch, int verbose, - int debug, int queued, - int sasl, int saslssf, char *saslmech, char *user) + int debug, int sasl, int saslssf, char *saslmech, char *user) { unsigned int i, result, vecp; int pdi[2], pdo[2]; @@ -472,7 +467,7 @@ sendmail_init (char *client, char *server, int watch, int verbose, vecp = 0; vec[vecp++] = r1bindex (sendmail, '/'); vec[vecp++] = "-bs"; - vec[vecp++] = watch ? "-odi" : queued ? "-odq" : "-odb"; + vec[vecp++] = watch ? "-odi" : "-odb"; vec[vecp++] = "-oem"; vec[vecp++] = "-om"; if (verbose) @@ -804,17 +799,26 @@ sm_end (int type) * completes successfully, then authentication is successful and we've * (optionally) negotiated a security layer. */ + +#define CHECKB64SIZE(insize, outbuf, outsize) \ + { size_t wantout = (((insize + 2) / 3) * 4) + 32; \ + if (wantout > outsize) { \ + outbuf = mh_xrealloc(outbuf, outsize = wantout); \ + } \ + } + static int sm_auth_sasl(char *user, int saslssf, char *mechlist, char *inhost) { int result, status; unsigned int buflen, outlen; - char *buf, outbuf[BUFSIZ], host[NI_MAXHOST]; + char *buf, *outbuf = NULL, host[NI_MAXHOST]; const char *chosen_mech; sasl_security_properties_t secprops; sasl_ssf_t *ssf; int *outbufmax; struct nmh_creds creds = { 0, 0, 0 }; + size_t outbufsize = 0; /* * Initialize the callback contexts @@ -911,10 +915,13 @@ sm_auth_sasl(char *user, int saslssf, char *mechlist, char *inhost) */ if (buflen) { - status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); + CHECKB64SIZE(buflen, outbuf, outbufsize); + status = sasl_encode64(buf, buflen, outbuf, outbufsize, NULL); if (status != SASL_OK) { sm_ierror("SASL base64 encode failed: %s", sasl_errstring(status, NULL, NULL)); + if (outbuf) + free(outbuf); return NOTOK; } @@ -941,8 +948,11 @@ sm_auth_sasl(char *user, int saslssf, char *mechlist, char *inhost) if (status == 235) break; - else if (status < 300 || status > 399) + else if (status < 300 || status > 399) { + if (outbuf) + free(outbuf); return RP_BHST; + } /* * Special case; a zero-length response from the SMTP server @@ -953,12 +963,18 @@ sm_auth_sasl(char *user, int saslssf, char *mechlist, char *inhost) if (strcmp("=", sm_reply.text) == 0) { outlen = 0; } else { + if (sm_reply.length > (int) outbufsize) { + outbuf = mh_xrealloc(outbuf, outbufsize = sm_reply.length); + } + result = sasl_decode64(sm_reply.text, sm_reply.length, - outbuf, sizeof(outbuf), &outlen); + outbuf, outbufsize, &outlen); if (result != SASL_OK) { smtalk(SM_AUTH, "*"); sm_ierror("SASL base64 decode failed: %s", sasl_errstring(result, NULL, NULL)); + if (outbuf) + free(outbuf); return NOTOK; } } @@ -970,21 +986,29 @@ sm_auth_sasl(char *user, int saslssf, char *mechlist, char *inhost) smtalk(SM_AUTH, "*"); sm_ierror("SASL client negotiation failed: %s", sasl_errstring(result, NULL, NULL)); + if (outbuf) + free(outbuf); return NOTOK; } - status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); + CHECKB64SIZE(buflen, outbuf, outbufsize); + status = sasl_encode64(buf, buflen, outbuf, outbufsize, NULL); if (status != SASL_OK) { smtalk(SM_AUTH, "*"); sm_ierror("SASL base64 encode failed: %s", sasl_errstring(status, NULL, NULL)); + if (outbuf) + free(outbuf); return NOTOK; } status = smtalk(SM_AUTH, outbuf); } + if (outbuf) + free(outbuf); + /* * Make sure that we got the correct response */ @@ -1059,7 +1083,9 @@ sm_get_user(void *context, int id, const char **result, unsigned *len) * That's used when those values really don't matter, and only * with legacy/.netrc, i.e., with a credentials profile entry. */ - nmh_get_credentials (creds->host, creds->user, 1, creds); + if (nmh_get_credentials (creds->host, creds->user, 1, creds) != OK) { + return SASL_BADPARAM; + } } *result = creds->user; @@ -1086,9 +1112,11 @@ sm_get_pass(sasl_conn_t *conn, void *context, int id, * Pass the 0 third argument to nmh_get_credentials() so * that the default password isn't used. With legacy/.netrc * credentials support, we'll only get here if the -user - * switch to send(1)/post(8) wasn used. + * switch to send(1)/post(8) wasn't used. */ - nmh_get_credentials (creds->host, creds->user, 0, creds); + if (nmh_get_credentials (creds->host, creds->user, 0, creds) != OK) { + return SASL_BADPARAM; + } } len = strlen (creds->password); @@ -1124,12 +1152,22 @@ smtalk (int time, char *fmt, ...) { va_list ap; int result; - char buffer[BUFSIZ]; + char *buffer; + size_t bufsize = BUFSIZ; + + buffer = mh_xmalloc(bufsize); va_start(ap, fmt); - vsnprintf (buffer, sizeof(buffer), fmt, ap); + result = vsnprintf (buffer, bufsize, fmt, ap); va_end(ap); + if (result > (int) bufsize) { + buffer = mh_xrealloc(buffer, bufsize = result + 1); + va_start(ap, fmt); + vsnprintf (buffer, bufsize, fmt, ap); + va_end(ap); + } + if (sm_debug) { if (sasl_ssf) printf("(sasl-encrypted) "); @@ -1145,6 +1183,8 @@ smtalk (int time, char *fmt, ...) result = smhear (); alarm (0); + free(buffer); + return result; } @@ -1183,7 +1223,7 @@ sm_wstream (char *buffer, int len) return (ferror (sm_wfp) ? sm_werror () : OK); } - for (bp = buffer; len > 0; bp++, len--) { + for (bp = buffer; bp && len > 0; bp++, len--) { switch (*bp) { case '\n': sm_nl = TRUE; @@ -1232,7 +1272,9 @@ sm_fwrite(char *buffer, int len) } } else #endif /* TLS_SUPPORT */ - fwrite(buffer, sizeof(*buffer), len, sm_wfp); + if ((int) fwrite(buffer, sizeof(*buffer), len, sm_wfp) < len) { + advise ("sm_fwrite", "fwrite"); + } #ifdef CYRUS_SASL } else { while (len >= maxoutbuf - sasl_outbuflen) { @@ -1248,7 +1290,10 @@ sm_fwrite(char *buffer, int len) return NOTOK; } - fwrite(output, sizeof(*output), outputlen, sm_wfp); + if (fwrite(output, sizeof(*output), outputlen, sm_wfp) < + outputlen) { + advise ("sm_fwrite", "fwrite"); + } } if (len > 0) { @@ -1395,7 +1440,9 @@ sm_fflush(void) return; } - fwrite(output, sizeof(*output), outputlen, sm_wfp); + if (fwrite(output, sizeof(*output), outputlen, sm_wfp) < outputlen) { + advise ("sm_fflush", "fwrite"); + } sasl_outbuflen = 0; } #endif /* CYRUS_SASL */ @@ -1427,7 +1474,7 @@ smhear (void) int i, code, cont, bc = 0, rc, more; unsigned char *bp; char *rp; - char **ehlo = NULL, buffer[BUFSIZ]; + char **ehlo = EHLOkeys, buffer[BUFSIZ]; if (doingEHLO) { static int at_least_once = 0;