X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=mts%2Fsmtp%2Fsmtp.c;h=da02701f50ba34fc587296a4088f566b88f9f782;hp=ac6b32e990f13e685795717d0621e1e5afa9999e;hb=35c228531bc8e00d43be590255df9408a4fcbe19;hpb=cfc525a9b85207225cb4071d1d3b01e8d1db2424 diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c index ac6b32e..da02701 100644 --- a/mts/smtp/smtp.c +++ b/mts/smtp/smtp.c @@ -2,17 +2,31 @@ * smtp.c -- nmh SMTP interface * * $Id$ + * + * This code is Copyright (c) 2002, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. */ #include #include "smtp.h" -#include +#include #include #include #ifdef MPOP #include #endif +#ifdef CYRUS_SASL +#include +#include +#include +#include +#include +#include +#include +#endif /* CYRUS_SASL */ + /* * This module implements an interface to SendMail very similar * to the MMDF mm_(3) routines. The sm_() routines herein talk @@ -46,16 +60,17 @@ /* * these codes must all be different! */ -#define SM_OPEN 90 /* Changed from 30 in case of nameserver flakiness */ +#define SM_OPEN 300 /* Changed to 5 minutes to comply with a SHOULD in RFC 1123 */ #define SM_HELO 20 #define SM_RSET 15 -#define SM_MAIL 40 -#define SM_RCPT 120 -#define SM_DATA 20 -#define SM_TEXT 150 -#define SM_DOT 180 +#define SM_MAIL 301 /* changed to 5 minutes and a second (for uniqueness), see above */ +#define SM_RCPT 302 /* see above */ +#define SM_DATA 120 /* see above */ +#define SM_TEXT 180 /* see above */ +#define SM_DOT 600 /* see above */ #define SM_QUIT 30 #define SM_CLOS 10 +#define SM_AUTH 45 static int sm_addrs = 0; static int sm_alarmed = 0; @@ -72,6 +87,28 @@ static int sm_ispool = 0; static char sm_tmpfil[BUFSIZ]; #endif /* MPOP */ +#ifdef CYRUS_SASL +/* + * Some globals needed by SASL + */ + +static sasl_conn_t *conn = NULL; /* SASL connection state */ +static int sasl_complete = 0; /* Has authentication succeded? */ +static sasl_ssf_t sasl_ssf; /* Our security strength factor */ +static char *sasl_pw_context[2]; /* Context to pass into sm_get_pass */ +static int maxoutbuf; /* Maximum crypto output buffer */ +static int sm_get_user(void *, int, const char **, unsigned *); +static int sm_get_pass(sasl_conn_t *, void *, int, sasl_secret_t **); + +static sasl_callback_t callbacks[] = { + { SASL_CB_USER, sm_get_user, NULL }, +#define SM_SASL_N_CB_USER 0 + { SASL_CB_PASS, sm_get_pass, NULL }, +#define SM_SASL_N_CB_PASS 1 + { SASL_CB_LIST_END, NULL, NULL }, +}; +#endif /* CYRUS_SASL */ + static char *sm_noreply = "No reply text given"; static char *sm_moreply = "; "; @@ -85,7 +122,8 @@ char *EHLOkeys[MAXEHLO + 1]; /* * static prototypes */ -static int smtp_init (char *, char *, int, int, int, int, int); +static int smtp_init (char *, char *, int, int, int, int, int, int, + char *, char *); static int sendmail_init (char *, char *, int, int, int, int, int); static int rclient (char *, char *, char *); @@ -109,16 +147,25 @@ static int smail_brkany (char, char *); char **smail_copyip (char **, char **, int); #endif -/* from zotnet/mts/client.c */ +#ifdef CYRUS_SASL +/* + * Function prototypes needed for SASL + */ + +static int sm_auth_sasl(char *, char *, char *); +#endif /* CYRUS_SASL */ + +/* from mts/generic/client.c */ int client (char *, char *, char *, int, char *, int); int sm_init (char *client, char *server, int watch, int verbose, - int debug, int onex, int queued) + int debug, int onex, int queued, int sasl, char *saslmech, + char *user) { if (sm_mts == MTS_SMTP) return smtp_init (client, server, watch, verbose, - debug, onex, queued); + debug, onex, queued, sasl, saslmech, user); else return sendmail_init (client, server, watch, verbose, debug, onex, queued); @@ -126,8 +173,12 @@ sm_init (char *client, char *server, int watch, int verbose, static int smtp_init (char *client, char *server, int watch, int verbose, - int debug, int onex, int queued) + int debug, int onex, int queued, int sasl, char *saslmech, + char *user) { +#ifdef CYRUS_SASL + char *server_mechs; +#endif /* CYRUS_SASL */ int result, sd1, sd2; if (watch) @@ -226,6 +277,35 @@ all_done: ; } } +#ifdef CYRUS_SASL + /* + * If the user asked for SASL, then check to see if the SMTP server + * supports it. Otherwise, error out (because the SMTP server + * might have been spoofed; we don't want to just silently not + * do authentication + */ + + if (sasl) { + if (! (server_mechs = EHLOset("AUTH"))) { + sm_end(NOTOK); + return sm_ierror("SMTP server does not support SASL"); + } + + if (saslmech && stringdex(saslmech, server_mechs) == -1) { + sm_end(NOTOK); + return sm_ierror("Requested SASL mech \"%s\" is not in the " + "list of supported mechanisms:\n%s", + saslmech, server_mechs); + } + + if (sm_auth_sasl(user, saslmech ? saslmech : server_mechs, + server) != RP_OK) { + sm_end(NOTOK); + return NOTOK; + } + } +#endif /* CYRUS_SASL */ + send_options: ; if (watch && EHLOset ("XVRB")) smtalk (SM_HELO, "VERB on"); @@ -422,15 +502,6 @@ rclient (char *server, char *protocol, char *service) return NOTOK; } -#ifdef CYRUS_SASL -#include -#include -#include -#include -#include -#include -#endif /* CYRUS_SASL */ - int sm_winit (int mode, char *from) { @@ -651,9 +722,13 @@ sm_end (int type) alarm (0); } - if (sm_mts == MTS_SMTP) + if (sm_mts == MTS_SMTP) { status = 0; - else { +#ifdef CYRUS_SASL + if (conn) + sasl_dispose(&conn); +#endif /* CYRUS_SASL */ + } else { status = pidwait (sm_child, OK); sm_child = NOTOK; } @@ -884,7 +959,7 @@ bad_data: free (cp); { -#ifdef HAVE_ST_BLKSIZE +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE struct stat st; if (fstat (fileno (sm_wfp), &st) == NOTOK || (cc = st.st_blksize) < BUFSIZ) @@ -1025,12 +1100,11 @@ no_dice: static int sm_auth_sasl(char *user, char *mechlist, char *host) { - int result, status, outlen; - unsigned int buflen; + int result, status; + unsigned int buflen, outlen; char *buf, outbuf[BUFSIZ]; const char *chosen_mech; sasl_security_properties_t secprops; - sasl_external_properties_t extprops; sasl_ssf_t *ssf; int *outbufmax; @@ -1083,7 +1157,7 @@ sm_auth_sasl(char *user, char *mechlist, char *host) return NOTOK; } - result = sasl_client_new("smtp", host, NULL, SASL_SECURITY_LAYER, &conn); + result = sasl_client_new("smtp", host, NULL, NULL, NULL, 0, &conn); if (result != SASL_OK) { sm_ierror("SASL client initialization failed: %s", @@ -1098,7 +1172,6 @@ sm_auth_sasl(char *user, char *mechlist, char *host) memset(&secprops, 0, sizeof(secprops)); secprops.maxbufsize = BUFSIZ; secprops.max_ssf = 0; /* XXX change this when we do encryption */ - memset(&extprops, 0, sizeof(extprops)); result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops); @@ -1108,21 +1181,13 @@ sm_auth_sasl(char *user, char *mechlist, char *host) return NOTOK; } - result = sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); - - if (result != SASL_OK) { - sm_ierror("SASL external property initialization failed: %s", - sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - /* * Start the actual protocol. Feed the mech list into the library * and get out a possible initial challenge */ - result = sasl_client_start(conn, mechlist, NULL, NULL, &buf, &buflen, - &chosen_mech); + result = sasl_client_start(conn, mechlist, NULL, (const char **) &buf, + &buflen, (const char **) &chosen_mech); if (result != SASL_OK && result != SASL_CONTINUE) { sm_ierror("SASL client start failed: %s", @@ -1137,7 +1202,6 @@ sm_auth_sasl(char *user, char *mechlist, char *host) if (buflen) { status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); - free(buf); if (status != SASL_OK) { sm_ierror("SASL base64 encode failed: %s", sasl_errstring(status, NULL, NULL)); @@ -1180,7 +1244,7 @@ sm_auth_sasl(char *user, char *mechlist, char *host) outlen = 0; } else { result = sasl_decode64(sm_reply.text, sm_reply.length, - outbuf, &outlen); + outbuf, sizeof(outbuf), &outlen); if (result != SASL_OK) { smtalk(SM_AUTH, "*"); @@ -1190,7 +1254,8 @@ sm_auth_sasl(char *user, char *mechlist, char *host) } } - result = sasl_client_step(conn, outbuf, outlen, NULL, &buf, &buflen); + result = sasl_client_step(conn, outbuf, outlen, NULL, + (const char **) &buf, &buflen); if (result != SASL_OK && result != SASL_CONTINUE) { smtalk(SM_AUTH, "*"); @@ -1200,7 +1265,6 @@ sm_auth_sasl(char *user, char *mechlist, char *host) } status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); - free(buf); if (status != SASL_OK) { smtalk(SM_AUTH, "*"); @@ -1220,24 +1284,11 @@ sm_auth_sasl(char *user, char *mechlist, char *host) return RP_BHST; /* - * Depending on the mechanism, we need to do a FINAL call to - * sasl_client_step(). Do that now. - */ - - result = sasl_client_step(conn, NULL, 0, NULL, &buf, &buflen); - - if (result != SASL_OK) { - sm_ierror("SASL final client negotiation failed: %s", - sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - /* * We _should_ have completed the authentication successfully. * Get a few properties from the authentication exchange. */ - result = sasl_getprop(conn, SASL_MAXOUTBUF, (void **) &outbufmax); + result = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **) &outbufmax); if (result != SASL_OK) { sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s", @@ -1247,7 +1298,7 @@ sm_auth_sasl(char *user, char *mechlist, char *host) maxoutbuf = *outbufmax; - result = sasl_getprop(conn, SASL_SSF, (void **) &ssf); + result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf); sasl_ssf = *ssf; @@ -1307,7 +1358,7 @@ sm_get_pass(sasl_conn_t *conn, void *context, int id, } (*psecret)->len = len; - strcpy((*psecret)->data, pass); + strcpy((char *) (*psecret)->data, pass); /* free(pass); */ return SASL_OK;