X-Git-Url: http://git.marmaro.de/?a=blobdiff_plain;f=mts%2Fsmtp%2Fsmtp.c;h=404c463e82f059d418691ba0ac7d102358df5097;hb=572cac455e444c60c4f7803d3e4b69fff89b9af2;hp=e6bca9a9f1338f49d9a2ac6574cf285976a5fed9;hpb=da304a48a24d7cc7fafae13c994d94ad3d6483f2;p=mmh diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c index e6bca9a..404c463 100644 --- a/mts/smtp/smtp.c +++ b/mts/smtp/smtp.c @@ -1,8 +1,6 @@ /* * 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. @@ -72,7 +70,9 @@ #define SM_DOT 600 /* see above */ #define SM_QUIT 30 #define SM_CLOS 10 +#ifdef CYRUS_SASL #define SM_AUTH 45 +#endif /* CYRUS_SASL */ static int sm_addrs = 0; static int sm_alarmed = 0; @@ -118,6 +118,7 @@ static SSL_CTX *sslctx = NULL; static SSL *ssl = NULL; static BIO *sbior = NULL; static BIO *sbiow = NULL; +static BIO *io = NULL; #endif /* TLS_SUPPORT */ #if defined(CYRUS_SASL) || defined(TLS_SUPPORT) @@ -159,7 +160,7 @@ static int sm_werror (void); static int smhear (void); static int sm_rrecord (char *, int *); static int sm_rerror (int); -static RETSIGTYPE alrmser (int); +static void alrmser (int); static char *EHLOset (char *); static int sm_fwrite(char *, int); static int sm_fputs(char *); @@ -172,31 +173,38 @@ static int sm_fgets(char *, int, FILE *); * Function prototypes needed for SASL */ -static int sm_auth_sasl(char *, char *, char *); +static int sm_auth_sasl(char *, int, char *, char *); #endif /* CYRUS_SASL */ int sm_init (char *client, char *server, char *port, int watch, int verbose, - int debug, int onex, int queued, int sasl, char *saslmech, - char *user, int tls) + int debug, int queued, int sasl, int saslssf, + char *saslmech, char *user, int tls) { if (sm_mts == MTS_SMTP) return smtp_init (client, server, port, watch, verbose, - debug, onex, queued, sasl, saslmech, user, tls); + debug, queued, sasl, saslssf, saslmech, + user, tls); else return sendmail_init (client, server, watch, verbose, - debug, onex, queued, sasl, saslmech, user); + debug, queued, sasl, saslssf, saslmech, + user); } static int smtp_init (char *client, char *server, char *port, int watch, int verbose, - int debug, int onex, int queued, - int sasl, char *saslmech, char *user, int tls) + int debug, int queued, + int sasl, int saslssf, char *saslmech, char *user, int tls) { + int result, sd1, sd2; #ifdef CYRUS_SASL char *server_mechs; +#else /* CYRUS_SASL */ + NMH_UNUSED (sasl); + NMH_UNUSED (saslssf); + NMH_UNUSED (saslmech); + NMH_UNUSED (user); #endif /* CYRUS_SASL */ - int result, sd1, sd2; if (watch) verbose = TRUE; @@ -211,7 +219,7 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, if (clientname) { client = clientname; } else { - client = LocalName(); /* no clientname -> LocalName */ + client = LocalName(1); /* no clientname -> LocalName */ } } @@ -288,6 +296,8 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, */ if (tls) { + BIO *ssl_bio; + if (! EHLOset("STARTTLS")) { sm_end(NOTOK); return sm_ierror("SMTP server does not support TLS"); @@ -306,7 +316,7 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, */ if (! sslctx) { - SSL_METHOD *method; + const SSL_METHOD *method; SSL_library_init(); SSL_load_error_strings(); @@ -340,15 +350,43 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, } SSL_set_bio(ssl, sbior, sbiow); + SSL_set_connect_state(ssl); + + /* + * Set up a BIO to handle buffering for us + */ - if (SSL_connect(ssl) < 1) { + io = BIO_new(BIO_f_buffer()); + + if (! io) { + sm_end(NOTOK); + return sm_ierror("Unable to create a buffer BIO: %s", + ERR_error_string(ERR_get_error(), NULL)); + } + + ssl_bio = BIO_new(BIO_f_ssl()); + + if (! ssl_bio) { + sm_end(NOTOK); + return sm_ierror("Unable to create a SSL BIO: %s", + ERR_error_string(ERR_get_error(), NULL)); + } + + BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE); + BIO_push(io, ssl_bio); + + /* + * Try doing the handshake now + */ + + if (BIO_do_handshake(io) < 1) { sm_end(NOTOK); return sm_ierror("Unable to negotiate SSL connection: %s", ERR_error_string(ERR_get_error(), NULL)); } if (sm_debug) { - SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); + const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); printf("SSL negotiation successful: %s(%d) %s\n", SSL_CIPHER_get_name(cipher), SSL_CIPHER_get_bits(cipher, NULL), @@ -367,6 +405,8 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, return RP_RPLY; } } +#else /* TLS_SUPPORT */ + NMH_UNUSED (tls); #endif /* TLS_SUPPORT */ #ifdef CYRUS_SASL @@ -390,7 +430,7 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, saslmech, server_mechs); } - if (sm_auth_sasl(user, saslmech ? saslmech : server_mechs, + if (sm_auth_sasl(user, saslssf, saslmech ? saslmech : server_mechs, server) != RP_OK) { sm_end(NOTOK); return NOTOK; @@ -401,8 +441,6 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose, send_options: ; if (watch && EHLOset ("XVRB")) smtalk (SM_HELO, "VERB on"); - if (onex && EHLOset ("XONE")) - smtalk (SM_HELO, "ONEX"); if (queued && EHLOset ("XQUE")) smtalk (SM_HELO, "QUED"); @@ -411,15 +449,21 @@ send_options: ; int sendmail_init (char *client, char *server, int watch, int verbose, - int debug, int onex, int queued, - int sasl, char *saslmech, char *user) + int debug, int queued, + int sasl, int saslssf, char *saslmech, char *user) { + unsigned int i, result, vecp; + int pdi[2], pdo[2]; + char *vec[15]; #ifdef CYRUS_SASL char *server_mechs; +#else /* CYRUS_SASL */ + NMH_UNUSED (server); + NMH_UNUSED (sasl); + NMH_UNUSED (saslssf); + NMH_UNUSED (saslmech); + NMH_UNUSED (user); #endif /* CYRUS_SASL */ - int i, result, vecp; - int pdi[2], pdo[2]; - char *vec[15]; if (watch) verbose = TRUE; @@ -433,7 +477,7 @@ sendmail_init (char *client, char *server, int watch, int verbose, if (clientname) client = clientname; else - client = LocalName(); /* no clientname -> LocalName */ + client = LocalName(1); /* no clientname -> LocalName */ } /* @@ -443,12 +487,12 @@ sendmail_init (char *client, char *server, int watch, int verbose, if (client == NULL || *client == '\0') client = "localhost"; -#ifdef CYRUS_SASL +#if defined(CYRUS_SASL) || defined(TLS_SUPPORT) sasl_inbuffer = malloc(SASL_MAXRECVBUF); if (!sasl_inbuffer) return sm_ierror("Unable to allocate %d bytes for read buffer", SASL_MAXRECVBUF); -#endif /* CYRUS_SASL */ +#endif /* CYRUS_SASL || TLS_SUPPORT */ if (pipe (pdi) == NOTOK) return sm_ierror ("no pipes"); @@ -485,10 +529,8 @@ sendmail_init (char *client, char *server, int watch, int verbose, vec[vecp++] = watch ? "-odi" : queued ? "-odq" : "-odb"; vec[vecp++] = "-oem"; vec[vecp++] = "-om"; -# ifndef RAND if (verbose) vec[vecp++] = "-ov"; -# endif /* not RAND */ vec[vecp++] = NULL; setgid (getegid ()); @@ -561,7 +603,7 @@ sendmail_init (char *client, char *server, int watch, int verbose, saslmech, server_mechs); } - if (sm_auth_sasl(user, saslmech ? saslmech : server_mechs, + if (sm_auth_sasl(user, saslssf, saslmech ? saslmech : server_mechs, server) != RP_OK) { sm_end(NOTOK); return NOTOK; @@ -569,8 +611,6 @@ sendmail_init (char *client, char *server, int watch, int verbose, } #endif /* CYRUS_SASL */ - if (onex) - smtalk (SM_HELO, "ONEX"); if (watch) smtalk (SM_HELO, "VERB on"); @@ -593,33 +633,9 @@ rclient (char *server, char *service) } int -sm_winit (int mode, char *from) +sm_winit (char *from) { - char *smtpcom = NULL; - - switch (mode) { - case S_MAIL: - smtpcom = "MAIL"; - break; - - case S_SEND: - smtpcom = "SEND"; - break; - - case S_SOML: - smtpcom = "SOML"; - break; - - case S_SAML: - smtpcom = "SAML"; - break; - - default: - /* Hopefully, we do not get here. */ - break; - } - - switch (smtalk (SM_MAIL, "%s FROM:<%s>", smtpcom, from)) { + switch (smtalk (SM_MAIL, "MAIL FROM:<%s>", from)) { case 250: sm_addrs = 0; return RP_OK; @@ -746,7 +762,7 @@ sm_end (int type) int status; struct smtp sm_note; - if (sm_mts == MTS_SENDMAIL) { + if (sm_mts == MTS_SENDMAIL_SMTP) { switch (sm_child) { case NOTOK: case OK: @@ -787,10 +803,12 @@ sm_end (int type) break; } +#ifdef TLS_SUPPORT if (tls_active) { - SSL_shutdown(ssl); - SSL_free(ssl); + BIO_ssl_shutdown(io); + BIO_free_all(io); } +#endif /* TLS_SUPPORT */ if (sm_rfp != NULL) { alarm (SM_CLOS); @@ -831,7 +849,7 @@ sm_end (int type) * (optionally) negotiated a security layer. */ static int -sm_auth_sasl(char *user, char *mechlist, char *inhost) +sm_auth_sasl(char *user, int saslssf, char *mechlist, char *inhost) { int result, status; unsigned int buflen, outlen; @@ -909,7 +927,8 @@ sm_auth_sasl(char *user, char *mechlist, char *inhost) memset(&secprops, 0, sizeof(secprops)); secprops.maxbufsize = SASL_MAXRECVBUF; - secprops.max_ssf = tls_active ? 0 : UINT_MAX; + secprops.max_ssf = + tls_active ? 0 : (saslssf != -1 ? (unsigned int) saslssf : UINT_MAX); result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops); @@ -1094,6 +1113,8 @@ sm_get_pass(sasl_conn_t *conn, void *context, int id, char *pass = NULL; int len; + NMH_UNUSED (conn); + if (! psecret || id != SASL_CB_PASS) return SASL_BADPARAM; @@ -1235,9 +1256,9 @@ sm_fwrite(char *buffer, int len) if (tls_active) { int ret; - ret = SSL_write(ssl, buffer, len); + ret = BIO_write(io, buffer, len); - if (SSL_get_error(ssl, ret) != SSL_ERROR_NONE) { + if (ret <= 0) { sm_ierror("TLS error during write: %s", ERR_error_string(ERR_get_error(), NULL)); return NOTOK; @@ -1316,6 +1337,12 @@ sm_fflush(void) } #endif /* CYRUS_SASL */ +#ifdef TLS_SUPPORT + if (tls_active) { + (void) BIO_flush(io); + } +#endif /* TLS_SUPPORT */ + fflush(sm_wfp); } @@ -1463,7 +1490,7 @@ sm_rrecord (char *buffer, int *len) buffer[*len = 0] = 0; if ((retval = sm_fgets (buffer, BUFSIZ, sm_rfp)) != RP_OK) - return retval; + return sm_rerror (retval); *len = strlen (buffer); /* *len should be >0 except on EOF, but check for safety's sake */ if (*len == 0) @@ -1572,6 +1599,7 @@ sm_fgetc(FILE *f) * encryption working */ +#ifdef CYRUS_SASL if (sasl_complete == 0 || sasl_ssf == 0) { retbuf = tmpbuf; retbufsize = cc; @@ -1585,6 +1613,10 @@ sm_fgetc(FILE *f) return -2; } } +#else /* ! CYRUS_SASL */ + retbuf = tmpbuf; + retbufsize = cc; +#endif /* CYRUS_SASL */ } if (retbufsize > SASL_MAXRECVBUF) { @@ -1621,9 +1653,11 @@ sm_rerror (int rc) } -static RETSIGTYPE +static void alrmser (int i) { + NMH_UNUSED (i); + #ifndef RELIABLE_SIGNALS SIGNAL (SIGALRM, alrmser); #endif