From: Wietse Venema Date: Sun, 22 Apr 2018 05:00:00 +0000 (-0500) Subject: postfix-3.4-20180422-nonprod X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2F20180422-nonprod;p=thirdparty%2Fpostfix.git postfix-3.4-20180422-nonprod --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 04e7f01fd..71ea22d32 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -23396,3 +23396,35 @@ Apologies for any names omitted. Bugfix: missing error tls_server_start() error handling in tlsproxy(8). File: tlsproxy/tlsproxy.c. + + Connection reuse for TLS-encrypted SMTP sessions. This is + work-in-progress, #ifdef USE_TLSPROXY, to avoid contamination + of existing code. + + The idea is to have smtp(8) talk plaintext while tlsproxy(8) + converts between local plaintext and remote ciphertext. + Then, smtp(8) can save plaintext connections to the cache, + and scache(8) holds the handles to the tlsproxy(8) processes. + + This preliminary implementation does not yet support proxying + of DANE attributes from smtp(8) to tlsproxy(8). tlsproxy(8) + does not have permissions to read private key files that + smtp(8) can read. And the name of a connection cache entry + does not yet depend on whether the cached connection uses + TLS, nor does it depend on DANE information. + + Files: global/mail_proto.h, postscreen/postscreen_starttls.c, + posttls-finger/posttls-finger.c, smtp/smtp.c, smtp/smtp.h, + smtp/smtp_params.c, smtp/smtp_proto.c, smtp/smtp_session.c, + smtpd/smtpd.c, tls/tls.h, tls/tls_client.c, tls/tls_proxy.h, + tls/tls_proxy_client_init_print.c, + tls/tls_proxy_client_init_scan.c, + tls/tls_proxy_client_start_print.c, + tls/tls_proxy_client_start_scan.c, tls/tls_proxy_clnt.c, + tls/tls_proxy_context_print.c, tls/tls_proxy_context_scan.c, + tls/tls_proxy_server_init_print.c, + tls/tls_proxy_server_init_scan.c, + tls/tls_proxy_server_start_print.c, + tls/tls_proxy_server_start_scan.c, tlsproxy/tlsproxy.c, + tlsproxy/tlsproxy.h, tlsproxy/tlsproxy_state.c, util/argv_attr.h, + util/argv_attr_print.c, util/argv_attr_scan.c. diff --git a/postfix/makedefs b/postfix/makedefs index 5449732b0..26e950d4b 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -878,7 +878,7 @@ CCARGS="$CCARGS -DSNAPSHOT" # Non-production: needs thorough testing, or major changes are still # needed before the code stabilizes. -#CCARGS="$CCARGS -DNONPROD" +CCARGS="$CCARGS -DNONPROD" # Workaround: prepend Postfix include files before other include files. CCARGS="-I. -I../../include $CCARGS" diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index 363bc71ec..9fc9ab68e 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -276,25 +276,6 @@ extern char *mail_pathname(const char *, const char *); #define MAIL_ATTR_DSN_ORCPT "dsn_orig_rcpt" /* dsn original recipient */ #define MAIL_ATTR_SMTPUTF8 "smtputf8" /* RFC6531 support */ - /* - * TLSPROXY support. - */ -#define MAIL_ATTR_REMOTE_ENDPT "remote_endpoint" /* name[addr]:port */ -#define MAIL_ATTR_ROLE "role" /* requested role */ -#define MAIL_ATTR_ROLE_SERVER "server" -#define MAIL_ATTR_ROLE_CLIENT "client" -#define MAIL_ATTR_TIMEOUT "timeout" -#define MAIL_ATTR_PEER_CN "peer_CN" -#define MAIL_ATTR_ISSUER_CN "issuer_CN" -#define MAIL_ATTR_PEER_CERT_FPT "peer_fingerprint" -#define MAIL_ATTR_PEER_PKEY_FPT "peer_pubkey_fingerprint" -#define MAIL_ATTR_PEER_STATUS "peer_status" -#define MAIL_ATTR_CIPHER_PROTOCOL "cipher_protocol" -#define MAIL_ATTR_CIPHER_NAME "cipher_name" -#define MAIL_ATTR_CIPHER_USEBITS "cipher_usebits" -#define MAIL_ATTR_CIPHER_ALGBITS "cipher_algbits" -#define MAIL_ATTR_SERVER_ID "server_id" - /* * SMTP reply footer support. */ diff --git a/postfix/src/postscreen/postscreen_starttls.c b/postfix/src/postscreen/postscreen_starttls.c index a5d6906e6..863ba8c23 100644 --- a/postfix/src/postscreen/postscreen_starttls.c +++ b/postfix/src/postscreen/postscreen_starttls.c @@ -226,10 +226,10 @@ void psc_starttls_open(PSC_STATE *smtp_state, EVENT_NOTIFY_FN resume_event) vstring_sprintf(remote_endpt, "[%s]:%s", smtp_state->smtp_client_addr, smtp_state->smtp_client_port); attr_print(tlsproxy_stream, ATTR_FLAG_NONE, - SEND_ATTR_STR(MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt)), - SEND_ATTR_INT(MAIL_ATTR_FLAGS, TLS_PROXY_FLAG_ROLE_SERVER), - SEND_ATTR_INT(MAIL_ATTR_TIMEOUT, psc_normal_cmd_time_limit), - SEND_ATTR_STR(MAIL_ATTR_SERVER_ID, MAIL_SERVICE_SMTPD), /* XXX */ + SEND_ATTR_STR(TLS_ATTR_REMOTE_ENDPT, STR(remote_endpt)), + SEND_ATTR_INT(TLS_ATTR_FLAGS, TLS_PROXY_FLAG_ROLE_SERVER), + SEND_ATTR_INT(TLS_ATTR_TIMEOUT, psc_normal_cmd_time_limit), + SEND_ATTR_STR(TLS_ATTR_SERVERID, MAIL_SERVICE_SMTPD), /* XXX */ ATTR_TYPE_END); if (vstream_fflush(tlsproxy_stream) != 0) { msg_warn("error sending request to %s service: %m", psc_tlsp_service); diff --git a/postfix/src/posttls-finger/posttls-finger.c b/postfix/src/posttls-finger/posttls-finger.c index 5f559b4fd..565e7ddb1 100644 --- a/postfix/src/posttls-finger/posttls-finger.c +++ b/postfix/src/posttls-finger/posttls-finger.c @@ -747,6 +747,7 @@ static int starttls(STATE *state) TLS_CLIENT_START(&tls_props, ctx = state->tls_ctx, stream = stream, + fd = -1, timeout = smtp_tmout, tls_level = state->level, nexthop = state->nexthop, diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index acd830264..7d4556496 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -101,8 +101,10 @@ smtp.o: ../../include/flush_clnt.h smtp.o: ../../include/header_body_checks.h smtp.o: ../../include/header_opts.h smtp.o: ../../include/htable.h +smtp.o: ../../include/iostuff.h smtp.o: ../../include/mail_conf.h smtp.o: ../../include/mail_params.h +smtp.o: ../../include/mail_proto.h smtp.o: ../../include/mail_server.h smtp.o: ../../include/mail_version.h smtp.o: ../../include/maps.h @@ -124,6 +126,7 @@ smtp.o: ../../include/string_list.h smtp.o: ../../include/stringops.h smtp.o: ../../include/sys_defs.h smtp.o: ../../include/tls.h +smtp.o: ../../include/tls_proxy.h smtp.o: ../../include/tok822.h smtp.o: ../../include/vbuf.h smtp.o: ../../include/vstream.h @@ -168,6 +171,7 @@ smtp_addr.o: ../../include/string_list.h smtp_addr.o: ../../include/stringops.h smtp_addr.o: ../../include/sys_defs.h smtp_addr.o: ../../include/tls.h +smtp_addr.o: ../../include/tls_proxy.h smtp_addr.o: ../../include/tok822.h smtp_addr.o: ../../include/vbuf.h smtp_addr.o: ../../include/vstream.h @@ -217,6 +221,7 @@ smtp_chat.o: ../../include/string_list.h smtp_chat.o: ../../include/stringops.h smtp_chat.o: ../../include/sys_defs.h smtp_chat.o: ../../include/tls.h +smtp_chat.o: ../../include/tls_proxy.h smtp_chat.o: ../../include/tok822.h smtp_chat.o: ../../include/vbuf.h smtp_chat.o: ../../include/vstream.h @@ -266,6 +271,7 @@ smtp_connect.o: ../../include/stringops.h smtp_connect.o: ../../include/sys_defs.h smtp_connect.o: ../../include/timed_connect.h smtp_connect.o: ../../include/tls.h +smtp_connect.o: ../../include/tls_proxy.h smtp_connect.o: ../../include/tok822.h smtp_connect.o: ../../include/vbuf.h smtp_connect.o: ../../include/vstream.h @@ -305,6 +311,7 @@ smtp_key.o: ../../include/sock_addr.h smtp_key.o: ../../include/string_list.h smtp_key.o: ../../include/sys_defs.h smtp_key.o: ../../include/tls.h +smtp_key.o: ../../include/tls_proxy.h smtp_key.o: ../../include/tok822.h smtp_key.o: ../../include/vbuf.h smtp_key.o: ../../include/vstream.h @@ -344,6 +351,7 @@ smtp_map11.o: ../../include/sock_addr.h smtp_map11.o: ../../include/string_list.h smtp_map11.o: ../../include/sys_defs.h smtp_map11.o: ../../include/tls.h +smtp_map11.o: ../../include/tls_proxy.h smtp_map11.o: ../../include/tok822.h smtp_map11.o: ../../include/vbuf.h smtp_map11.o: ../../include/vstream.h @@ -405,6 +413,7 @@ smtp_proto.o: ../../include/string_list.h smtp_proto.o: ../../include/stringops.h smtp_proto.o: ../../include/sys_defs.h smtp_proto.o: ../../include/tls.h +smtp_proto.o: ../../include/tls_proxy.h smtp_proto.o: ../../include/tok822.h smtp_proto.o: ../../include/uxtext.h smtp_proto.o: ../../include/vbuf.h @@ -450,6 +459,7 @@ smtp_rcpt.o: ../../include/string_list.h smtp_rcpt.o: ../../include/stringops.h smtp_rcpt.o: ../../include/sys_defs.h smtp_rcpt.o: ../../include/tls.h +smtp_rcpt.o: ../../include/tls_proxy.h smtp_rcpt.o: ../../include/tok822.h smtp_rcpt.o: ../../include/vbuf.h smtp_rcpt.o: ../../include/vstream.h @@ -487,6 +497,7 @@ smtp_reuse.o: ../../include/string_list.h smtp_reuse.o: ../../include/stringops.h smtp_reuse.o: ../../include/sys_defs.h smtp_reuse.o: ../../include/tls.h +smtp_reuse.o: ../../include/tls_proxy.h smtp_reuse.o: ../../include/tok822.h smtp_reuse.o: ../../include/vbuf.h smtp_reuse.o: ../../include/vstream.h @@ -527,6 +538,7 @@ smtp_sasl_auth_cache.o: ../../include/string_list.h smtp_sasl_auth_cache.o: ../../include/stringops.h smtp_sasl_auth_cache.o: ../../include/sys_defs.h smtp_sasl_auth_cache.o: ../../include/tls.h +smtp_sasl_auth_cache.o: ../../include/tls_proxy.h smtp_sasl_auth_cache.o: ../../include/tok822.h smtp_sasl_auth_cache.o: ../../include/vbuf.h smtp_sasl_auth_cache.o: ../../include/vstream.h @@ -569,6 +581,7 @@ smtp_sasl_glue.o: ../../include/string_list.h smtp_sasl_glue.o: ../../include/stringops.h smtp_sasl_glue.o: ../../include/sys_defs.h smtp_sasl_glue.o: ../../include/tls.h +smtp_sasl_glue.o: ../../include/tls_proxy.h smtp_sasl_glue.o: ../../include/tok822.h smtp_sasl_glue.o: ../../include/vbuf.h smtp_sasl_glue.o: ../../include/vstream.h @@ -609,6 +622,7 @@ smtp_sasl_proto.o: ../../include/string_list.h smtp_sasl_proto.o: ../../include/stringops.h smtp_sasl_proto.o: ../../include/sys_defs.h smtp_sasl_proto.o: ../../include/tls.h +smtp_sasl_proto.o: ../../include/tls_proxy.h smtp_sasl_proto.o: ../../include/tok822.h smtp_sasl_proto.o: ../../include/vbuf.h smtp_sasl_proto.o: ../../include/vstream.h @@ -648,6 +662,7 @@ smtp_session.o: ../../include/string_list.h smtp_session.o: ../../include/stringops.h smtp_session.o: ../../include/sys_defs.h smtp_session.o: ../../include/tls.h +smtp_session.o: ../../include/tls_proxy.h smtp_session.o: ../../include/tok822.h smtp_session.o: ../../include/vbuf.h smtp_session.o: ../../include/vstream.h @@ -685,6 +700,7 @@ smtp_state.o: ../../include/sock_addr.h smtp_state.o: ../../include/string_list.h smtp_state.o: ../../include/sys_defs.h smtp_state.o: ../../include/tls.h +smtp_state.o: ../../include/tls_proxy.h smtp_state.o: ../../include/tok822.h smtp_state.o: ../../include/vbuf.h smtp_state.o: ../../include/vstream.h @@ -724,6 +740,7 @@ smtp_tls_policy.o: ../../include/string_list.h smtp_tls_policy.o: ../../include/stringops.h smtp_tls_policy.o: ../../include/sys_defs.h smtp_tls_policy.o: ../../include/tls.h +smtp_tls_policy.o: ../../include/tls_proxy.h smtp_tls_policy.o: ../../include/tok822.h smtp_tls_policy.o: ../../include/valid_hostname.h smtp_tls_policy.o: ../../include/valid_utf8_hostname.h @@ -768,6 +785,7 @@ smtp_trouble.o: ../../include/string_list.h smtp_trouble.o: ../../include/stringops.h smtp_trouble.o: ../../include/sys_defs.h smtp_trouble.o: ../../include/tls.h +smtp_trouble.o: ../../include/tls_proxy.h smtp_trouble.o: ../../include/tok822.h smtp_trouble.o: ../../include/vbuf.h smtp_trouble.o: ../../include/vstream.h @@ -804,6 +822,7 @@ smtp_unalias.o: ../../include/sock_addr.h smtp_unalias.o: ../../include/string_list.h smtp_unalias.o: ../../include/sys_defs.h smtp_unalias.o: ../../include/tls.h +smtp_unalias.o: ../../include/tls_proxy.h smtp_unalias.o: ../../include/tok822.h smtp_unalias.o: ../../include/vbuf.h smtp_unalias.o: ../../include/vstream.h diff --git a/postfix/src/smtp/lmtp_params.c b/postfix/src/smtp/lmtp_params.c index 68d611e26..5bbe9cbc0 100644 --- a/postfix/src/smtp/lmtp_params.c +++ b/postfix/src/smtp/lmtp_params.c @@ -61,6 +61,7 @@ VAR_LMTP_DNS_RES_OPT, DEF_LMTP_DNS_RES_OPT, &var_smtp_dns_res_opt, 0, 0, VAR_LMTP_DSN_FILTER, DEF_LMTP_DSN_FILTER, &var_smtp_dsn_filter, 0, 0, VAR_LMTP_DNS_RE_FILTER, DEF_LMTP_DNS_RE_FILTER, &var_smtp_dns_re_filter, 0, 0, + VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0, 0, }; static const CONFIG_TIME_TABLE lmtp_time_table[] = { diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index ed27be96a..f5067e992 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -810,6 +810,7 @@ /* Global library. */ #include +#include #include #include #include @@ -895,6 +896,7 @@ bool var_smtp_enforce_tls; char *var_smtp_tls_per_site; char *var_smtp_tls_policy; bool var_smtp_tls_wrappermode; +char *var_tlsproxy_service; #ifdef USE_TLS char *var_smtp_sasl_tls_opts; @@ -978,7 +980,10 @@ HBC_CHECKS *smtp_body_checks; /* limited body checks */ /* * OpenSSL client state (opaque handle) */ +#ifndef USE_TLSPROXY TLS_APPL_STATE *smtp_tls_ctx; + +#endif int smtp_tls_insecure_mx_policy; #endif @@ -1211,6 +1216,7 @@ static void pre_init(char *unused_name, char **unused_argv) */ if (use_tls || var_smtp_tls_per_site[0] || var_smtp_tls_policy[0]) { #ifdef USE_TLS +#ifndef USE_TLSPROXY TLS_CLIENT_INIT_PROPS props; /* @@ -1235,6 +1241,7 @@ static void pre_init(char *unused_name, char **unused_argv) CAfile = var_smtp_tls_CAfile, CApath = var_smtp_tls_CApath, mdalg = var_smtp_tls_fpt_dgst); +#endif /* USE_TLSPROXY */ smtp_tls_list_init(); #else msg_warn("TLS has been selected, but TLS support is not compiled in"); diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 11beb4406..dceb3f6c1 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -38,6 +38,11 @@ */ #include + /* + * tlsproxy client. + */ +#include + /* * Global iterator support. This is updated by the connection-management * loop, and contains dynamic context that appears in lookup keys for SASL @@ -288,8 +293,10 @@ extern int smtp_ext_prop_mask; /* address externsion propagation */ extern unsigned smtp_dns_res_opt; /* DNS query flags */ #ifdef USE_TLS - +#ifndef USE_TLSPROXY extern TLS_APPL_STATE *smtp_tls_ctx; /* client-side TLS engine */ + +#endif extern int smtp_tls_insecure_mx_policy; /* DANE post insecure MX? */ #endif diff --git a/postfix/src/smtp/smtp_params.c b/postfix/src/smtp/smtp_params.c index ed5ea455b..35a67470f 100644 --- a/postfix/src/smtp/smtp_params.c +++ b/postfix/src/smtp/smtp_params.c @@ -62,6 +62,7 @@ VAR_SMTP_DNS_RES_OPT, DEF_SMTP_DNS_RES_OPT, &var_smtp_dns_res_opt, 0, 0, VAR_SMTP_DSN_FILTER, DEF_SMTP_DSN_FILTER, &var_smtp_dsn_filter, 0, 0, VAR_SMTP_DNS_RE_FILTER, DEF_SMTP_DNS_RE_FILTER, &var_smtp_dns_re_filter, 0, 0, + VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0, 0, }; static const CONFIG_TIME_TABLE smtp_time_table[] = { diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 15a15db17..74a2ecd95 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -757,7 +757,10 @@ int smtp_helo(SMTP_STATE *state) * Decide whether or not to send STARTTLS. */ if ((session->features & SMTP_FEATURE_STARTTLS) != 0 - && smtp_tls_ctx != 0 && state->tls->level >= TLS_LEV_MAY) { +#ifndef USE_TLSPROXY + && smtp_tls_ctx != 0 +#endif + && state->tls->level >= TLS_LEV_MAY) { /* * Prepare for disaster. @@ -818,10 +821,12 @@ int smtp_helo(SMTP_STATE *state) SMTP_RESP_FAKE(&fake, "4.7.4"), "TLS is required, but was not offered by host %s", session->namaddr)); +#ifndef USE_TLSPROXY } else if (smtp_tls_ctx == 0) { return (smtp_site_fail(state, DSN_BY_LOCAL_MTA, SMTP_RESP_FAKE(&fake, "4.7.5"), "TLS is required, but our TLS engine is unavailable")); +#endif } else { msg_warn("%s: TLS is required but unavailable, don't know why", myname); @@ -848,10 +853,17 @@ static int smtp_start_tls(SMTP_STATE *state) { SMTP_SESSION *session = state->session; SMTP_ITERATOR *iter = state->iterator; - TLS_CLIENT_START_PROPS tls_props; + TLS_CLIENT_START_PROPS start_props; VSTRING *serverid; SMTP_RESP fake; +#ifdef USE_TLSPROXY + TLS_CLIENT_INIT_PROPS init_props; + VSTREAM *tlsproxy; + +#endif + + /* * Turn off SMTP connection caching. When the TLS handshake succeeds, we * can't reuse the SMTP connection. Reason: we can't turn off TLS in one @@ -861,7 +873,9 @@ static int smtp_start_tls(SMTP_STATE *state) * SMTP connection either, because the conversation is in an unknown * state. */ +#ifndef USE_TLSPROXY DONT_CACHE_THIS_SESSION; +#endif /* * The following assumes sites that use TLS in a perverse configuration: @@ -894,6 +908,80 @@ static int smtp_start_tls(SMTP_STATE *state) | SMTP_KEY_FLAG_HOSTNAME | SMTP_KEY_FLAG_ADDR); +#ifdef USE_TLSPROXY + + /* + * Send all our wishes in one big request. + */ + TLS_PROXY_CLIENT_INIT_PROPS(&init_props, + log_param = VAR_LMTP_SMTP(TLS_LOGLEVEL), + log_level = var_smtp_tls_loglevel, + verifydepth = var_smtp_tls_scert_vd, + cache_type = LMTP_SMTP_SUFFIX(TLS_MGR_SCACHE), + cert_file = var_smtp_tls_cert_file, + key_file = var_smtp_tls_key_file, + dcert_file = var_smtp_tls_dcert_file, + dkey_file = var_smtp_tls_dkey_file, + eccert_file = var_smtp_tls_eccert_file, + eckey_file = var_smtp_tls_eckey_file, + CAfile = var_smtp_tls_CAfile, + CApath = var_smtp_tls_CApath, + mdalg = var_smtp_tls_fpt_dgst); + TLS_PROXY_CLIENT_START_PROPS(&start_props, + timeout = var_smtp_starttls_tmout, + tls_level = state->tls->level, + nexthop = session->tls_nexthop, + host = STR(iter->host), + namaddr = session->namaddrport, + serverid = vstring_str(serverid), + helo = session->helo, + protocols = state->tls->protocols, + cipher_grade = state->tls->grade, + cipher_exclusions + = vstring_str(state->tls->exclusions), + matchargv = state->tls->matchargv, + mdalg = var_smtp_tls_fpt_dgst); + +#define PROXY_OPEN_FLAGS \ + (TLS_PROXY_FLAG_ROLE_CLIENT | TLS_PROXY_FLAG_SEND_CONTEXT) + + tlsproxy = + tls_proxy_open(var_tlsproxy_service, PROXY_OPEN_FLAGS, + session->stream, STR(iter->host), + "25" /* TODO */ , var_smtp_starttls_tmout, + "smtp" /* TODO */ , &init_props, &start_props); + + /* + * To insert tlsproxy(8) between this process and the remote SMTP server, + * we swap the file descriptors between the tlsproxy and session->stream + * VSTREAMS, so that we don't lose all the user-configurable + * session->stream attributes (such as longjump buffers or timeouts). + * + * TODO: the tlsproxy RPCs should return more error detail than a "NO" + * result. + */ + if (tlsproxy == 0) { + session->tls_context = 0; + } else { + vstream_control(tlsproxy, + CA_VSTREAM_CTL_DOUBLE, + CA_VSTREAM_CTL_END); + vstream_control(session->stream, + CA_VSTREAM_CTL_SWAP_FD(tlsproxy), + CA_VSTREAM_CTL_END); + (void) vstream_fclose(tlsproxy); /* direct-to-server stream! */ + + /* + * After plumbing the plaintext stream, receive the TLS context + * object. For this we must use the same VSTREAM buffer that we also + * use to receive subsequent SMTP commands. The attribute protocol is + * robust enough that an adversary cannot inject their own bogus TLS + * context attributes into the stream. + */ + session->tls_context = tls_proxy_context_receive(session->stream); + } +#else /* USE_TLS_PROXY */ + /* * As of Postfix 2.5, tls_client_start() tries hard to always complete * the TLS handshake. It records the verification and match status in the @@ -908,9 +996,10 @@ static int smtp_start_tls(SMTP_STATE *state) * that C does not have natively: named parameter lists. */ session->tls_context = - TLS_CLIENT_START(&tls_props, + TLS_CLIENT_START(&start_props, ctx = smtp_tls_ctx, stream = session->stream, + fd = -1, timeout = var_smtp_starttls_tmout, tls_level = state->tls->level, nexthop = session->tls_nexthop, @@ -925,6 +1014,7 @@ static int smtp_start_tls(SMTP_STATE *state) matchargv = state->tls->matchargv, mdalg = var_smtp_tls_fpt_dgst, dane = state->tls->dane); +#endif /* USE_TLS_PROXY */ vstring_free(serverid); if (session->tls_context == 0) { diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index 806d8de06..416a67d1c 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -84,6 +84,11 @@ /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/* /* Viktor Dukhovni /*--*/ @@ -176,9 +181,14 @@ void smtp_session_free(SMTP_SESSION *session) #ifdef USE_TLS if (session->stream) { vstream_fflush(session->stream); - if (session->tls_context) - tls_client_stop(smtp_tls_ctx, session->stream, - var_smtp_starttls_tmout, 0, session->tls_context); + } + if (session->tls_context) { +#ifdef USE_TLSPROXY + tls_proxy_context_free(session->tls_context); +#else /* USE_TLSPROXY */ + tls_client_stop(smtp_tls_ctx, session->stream, + var_smtp_starttls_tmout, 0, session->tls_context); +#endif /* USE_TLSPROXY */ } #endif if (session->stream) diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 20598992b..5006e7449 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -1496,9 +1496,11 @@ static void tls_reset(SMTPD_STATE *); /* * TLS initialization status. */ +#ifndef USE_TLSPROXY static TLS_APPL_STATE *smtpd_tls_ctx; static int ask_client_cert; +#endif /* USE_TLSPROXY */ #endif /* @@ -4704,9 +4706,11 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) #define PROXY_OPEN_FLAGS \ (TLS_PROXY_FLAG_ROLE_SERVER | TLS_PROXY_FLAG_SEND_CONTEXT) - state->tlsproxy = tls_proxy_open(var_tlsproxy_service, PROXY_OPEN_FLAGS, - state->client, state->addr, - state->port, var_smtpd_tmout); + state->tlsproxy = + tls_proxy_legacy_open(var_tlsproxy_service, PROXY_OPEN_FLAGS, + state->client, state->addr, + state->port, var_smtpd_tmout, + state->service); if (state->tlsproxy == 0) { state->error_mask |= MAIL_ERROR_SOFTWARE; /* RFC 3207 Section 4. */ @@ -4963,10 +4967,12 @@ static void smtpd_proto(SMTPD_STATE *state) if (SMTPD_STAND_ALONE(state) == 0 && var_smtpd_tls_wrappermode) { #ifdef USE_TLSPROXY /* We garbage-collect the VSTREAM in smtpd_state_reset() */ - state->tlsproxy = tls_proxy_open(var_tlsproxy_service, - PROXY_OPEN_FLAGS, - state->client, state->addr, - state->port, var_smtpd_tmout); + state->tlsproxy = + tls_proxy_legacy_open(var_tlsproxy_service, + PROXY_OPEN_FLAGS, + state->client, state->addr, + state->port, var_smtpd_tmout, + state->service); if (state->tlsproxy == 0) { msg_warn("Wrapper-mode request dropped from %s for service %s." " TLS context initialization failed. For details see" diff --git a/postfix/src/tls/Makefile.in b/postfix/src/tls/Makefile.in index 55dfd1ecc..dea34b08c 100644 --- a/postfix/src/tls/Makefile.in +++ b/postfix/src/tls/Makefile.in @@ -4,13 +4,21 @@ SRCS = tls_prng_dev.c tls_prng_egd.c tls_prng_file.c tls_fprint.c \ tls_rsa.c tls_verify.c tls_dane.c tls_certkey.c tls_session.c \ tls_client.c tls_server.c tls_scache.c tls_mgr.c tls_seed.c \ tls_level.c \ - tls_proxy_clnt.c tls_proxy_print.c tls_proxy_scan.c + tls_proxy_clnt.c tls_proxy_context_print.c tls_proxy_context_scan.c \ + tls_proxy_client_init_print.c tls_proxy_client_init_scan.c \ + tls_proxy_server_init_print.c tls_proxy_server_init_scan.c \ + tls_proxy_client_start_print.c tls_proxy_client_start_scan.c \ + tls_proxy_server_start_print.c tls_proxy_server_start_scan.c OBJS = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o tls_fprint.o \ tls_prng_exch.o tls_stream.o tls_bio_ops.o tls_misc.o tls_dh.o \ tls_rsa.o tls_verify.o tls_dane.o tls_certkey.o tls_session.o \ tls_client.o tls_server.o tls_scache.o tls_mgr.o tls_seed.o \ tls_level.o \ - tls_proxy_clnt.o tls_proxy_print.o tls_proxy_scan.o + tls_proxy_clnt.o tls_proxy_context_print.o tls_proxy_context_scan.o \ + tls_proxy_client_init_print.o tls_proxy_client_init_scan.o \ + tls_proxy_server_init_print.o tls_proxy_server_init_scan.o \ + tls_proxy_client_start_print.o tls_proxy_client_start_scan.o \ + tls_proxy_server_start_print.o tls_proxy_server_start_scan.o HDRS = tls.h tls_prng.h tls_scache.h tls_mgr.h tls_proxy.h TESTSRC = DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) @@ -294,6 +302,80 @@ tls_prng_file.o: ../../include/mymalloc.h tls_prng_file.o: ../../include/sys_defs.h tls_prng_file.o: tls_prng.h tls_prng_file.o: tls_prng_file.c +tls_proxy_client_init_print.o: ../../include/argv.h +tls_proxy_client_init_print.o: ../../include/attr.h +tls_proxy_client_init_print.o: ../../include/check_arg.h +tls_proxy_client_init_print.o: ../../include/dns.h +tls_proxy_client_init_print.o: ../../include/htable.h +tls_proxy_client_init_print.o: ../../include/myaddrinfo.h +tls_proxy_client_init_print.o: ../../include/mymalloc.h +tls_proxy_client_init_print.o: ../../include/name_code.h +tls_proxy_client_init_print.o: ../../include/name_mask.h +tls_proxy_client_init_print.o: ../../include/nvtable.h +tls_proxy_client_init_print.o: ../../include/sock_addr.h +tls_proxy_client_init_print.o: ../../include/sys_defs.h +tls_proxy_client_init_print.o: ../../include/vbuf.h +tls_proxy_client_init_print.o: ../../include/vstream.h +tls_proxy_client_init_print.o: ../../include/vstring.h +tls_proxy_client_init_print.o: tls.h +tls_proxy_client_init_print.o: tls_proxy.h +tls_proxy_client_init_print.o: tls_proxy_client_init_print.c +tls_proxy_client_init_scan.o: ../../include/argv.h +tls_proxy_client_init_scan.o: ../../include/attr.h +tls_proxy_client_init_scan.o: ../../include/check_arg.h +tls_proxy_client_init_scan.o: ../../include/dns.h +tls_proxy_client_init_scan.o: ../../include/htable.h +tls_proxy_client_init_scan.o: ../../include/myaddrinfo.h +tls_proxy_client_init_scan.o: ../../include/mymalloc.h +tls_proxy_client_init_scan.o: ../../include/name_code.h +tls_proxy_client_init_scan.o: ../../include/name_mask.h +tls_proxy_client_init_scan.o: ../../include/nvtable.h +tls_proxy_client_init_scan.o: ../../include/sock_addr.h +tls_proxy_client_init_scan.o: ../../include/sys_defs.h +tls_proxy_client_init_scan.o: ../../include/vbuf.h +tls_proxy_client_init_scan.o: ../../include/vstream.h +tls_proxy_client_init_scan.o: ../../include/vstring.h +tls_proxy_client_init_scan.o: tls.h +tls_proxy_client_init_scan.o: tls_proxy.h +tls_proxy_client_init_scan.o: tls_proxy_client_init_scan.c +tls_proxy_client_start_print.o: ../../include/argv.h +tls_proxy_client_start_print.o: ../../include/argv_attr.h +tls_proxy_client_start_print.o: ../../include/attr.h +tls_proxy_client_start_print.o: ../../include/check_arg.h +tls_proxy_client_start_print.o: ../../include/dns.h +tls_proxy_client_start_print.o: ../../include/htable.h +tls_proxy_client_start_print.o: ../../include/myaddrinfo.h +tls_proxy_client_start_print.o: ../../include/mymalloc.h +tls_proxy_client_start_print.o: ../../include/name_code.h +tls_proxy_client_start_print.o: ../../include/name_mask.h +tls_proxy_client_start_print.o: ../../include/nvtable.h +tls_proxy_client_start_print.o: ../../include/sock_addr.h +tls_proxy_client_start_print.o: ../../include/sys_defs.h +tls_proxy_client_start_print.o: ../../include/vbuf.h +tls_proxy_client_start_print.o: ../../include/vstream.h +tls_proxy_client_start_print.o: ../../include/vstring.h +tls_proxy_client_start_print.o: tls.h +tls_proxy_client_start_print.o: tls_proxy.h +tls_proxy_client_start_print.o: tls_proxy_client_start_print.c +tls_proxy_client_start_scan.o: ../../include/argv.h +tls_proxy_client_start_scan.o: ../../include/argv_attr.h +tls_proxy_client_start_scan.o: ../../include/attr.h +tls_proxy_client_start_scan.o: ../../include/check_arg.h +tls_proxy_client_start_scan.o: ../../include/dns.h +tls_proxy_client_start_scan.o: ../../include/htable.h +tls_proxy_client_start_scan.o: ../../include/myaddrinfo.h +tls_proxy_client_start_scan.o: ../../include/mymalloc.h +tls_proxy_client_start_scan.o: ../../include/name_code.h +tls_proxy_client_start_scan.o: ../../include/name_mask.h +tls_proxy_client_start_scan.o: ../../include/nvtable.h +tls_proxy_client_start_scan.o: ../../include/sock_addr.h +tls_proxy_client_start_scan.o: ../../include/sys_defs.h +tls_proxy_client_start_scan.o: ../../include/vbuf.h +tls_proxy_client_start_scan.o: ../../include/vstream.h +tls_proxy_client_start_scan.o: ../../include/vstring.h +tls_proxy_client_start_scan.o: tls.h +tls_proxy_client_start_scan.o: tls_proxy.h +tls_proxy_client_start_scan.o: tls_proxy_client_start_scan.c tls_proxy_clnt.o: ../../include/argv.h tls_proxy_clnt.o: ../../include/attr.h tls_proxy_clnt.o: ../../include/check_arg.h @@ -318,46 +400,114 @@ tls_proxy_clnt.o: ../../include/vstring.h tls_proxy_clnt.o: tls.h tls_proxy_clnt.o: tls_proxy.h tls_proxy_clnt.o: tls_proxy_clnt.c -tls_proxy_print.o: ../../include/argv.h -tls_proxy_print.o: ../../include/attr.h -tls_proxy_print.o: ../../include/check_arg.h -tls_proxy_print.o: ../../include/dns.h -tls_proxy_print.o: ../../include/htable.h -tls_proxy_print.o: ../../include/iostuff.h -tls_proxy_print.o: ../../include/mail_proto.h -tls_proxy_print.o: ../../include/myaddrinfo.h -tls_proxy_print.o: ../../include/mymalloc.h -tls_proxy_print.o: ../../include/name_code.h -tls_proxy_print.o: ../../include/name_mask.h -tls_proxy_print.o: ../../include/nvtable.h -tls_proxy_print.o: ../../include/sock_addr.h -tls_proxy_print.o: ../../include/sys_defs.h -tls_proxy_print.o: ../../include/vbuf.h -tls_proxy_print.o: ../../include/vstream.h -tls_proxy_print.o: ../../include/vstring.h -tls_proxy_print.o: tls.h -tls_proxy_print.o: tls_proxy.h -tls_proxy_print.o: tls_proxy_print.c -tls_proxy_scan.o: ../../include/argv.h -tls_proxy_scan.o: ../../include/attr.h -tls_proxy_scan.o: ../../include/check_arg.h -tls_proxy_scan.o: ../../include/dns.h -tls_proxy_scan.o: ../../include/htable.h -tls_proxy_scan.o: ../../include/iostuff.h -tls_proxy_scan.o: ../../include/mail_proto.h -tls_proxy_scan.o: ../../include/myaddrinfo.h -tls_proxy_scan.o: ../../include/mymalloc.h -tls_proxy_scan.o: ../../include/name_code.h -tls_proxy_scan.o: ../../include/name_mask.h -tls_proxy_scan.o: ../../include/nvtable.h -tls_proxy_scan.o: ../../include/sock_addr.h -tls_proxy_scan.o: ../../include/sys_defs.h -tls_proxy_scan.o: ../../include/vbuf.h -tls_proxy_scan.o: ../../include/vstream.h -tls_proxy_scan.o: ../../include/vstring.h -tls_proxy_scan.o: tls.h -tls_proxy_scan.o: tls_proxy.h -tls_proxy_scan.o: tls_proxy_scan.c +tls_proxy_context_print.o: ../../include/argv.h +tls_proxy_context_print.o: ../../include/attr.h +tls_proxy_context_print.o: ../../include/check_arg.h +tls_proxy_context_print.o: ../../include/dns.h +tls_proxy_context_print.o: ../../include/htable.h +tls_proxy_context_print.o: ../../include/myaddrinfo.h +tls_proxy_context_print.o: ../../include/mymalloc.h +tls_proxy_context_print.o: ../../include/name_code.h +tls_proxy_context_print.o: ../../include/name_mask.h +tls_proxy_context_print.o: ../../include/nvtable.h +tls_proxy_context_print.o: ../../include/sock_addr.h +tls_proxy_context_print.o: ../../include/sys_defs.h +tls_proxy_context_print.o: ../../include/vbuf.h +tls_proxy_context_print.o: ../../include/vstream.h +tls_proxy_context_print.o: ../../include/vstring.h +tls_proxy_context_print.o: tls.h +tls_proxy_context_print.o: tls_proxy.h +tls_proxy_context_print.o: tls_proxy_context_print.c +tls_proxy_context_scan.o: ../../include/argv.h +tls_proxy_context_scan.o: ../../include/attr.h +tls_proxy_context_scan.o: ../../include/check_arg.h +tls_proxy_context_scan.o: ../../include/dns.h +tls_proxy_context_scan.o: ../../include/htable.h +tls_proxy_context_scan.o: ../../include/myaddrinfo.h +tls_proxy_context_scan.o: ../../include/mymalloc.h +tls_proxy_context_scan.o: ../../include/name_code.h +tls_proxy_context_scan.o: ../../include/name_mask.h +tls_proxy_context_scan.o: ../../include/nvtable.h +tls_proxy_context_scan.o: ../../include/sock_addr.h +tls_proxy_context_scan.o: ../../include/sys_defs.h +tls_proxy_context_scan.o: ../../include/vbuf.h +tls_proxy_context_scan.o: ../../include/vstream.h +tls_proxy_context_scan.o: ../../include/vstring.h +tls_proxy_context_scan.o: tls.h +tls_proxy_context_scan.o: tls_proxy.h +tls_proxy_context_scan.o: tls_proxy_context_scan.c +tls_proxy_server_init_print.o: ../../include/argv.h +tls_proxy_server_init_print.o: ../../include/attr.h +tls_proxy_server_init_print.o: ../../include/check_arg.h +tls_proxy_server_init_print.o: ../../include/dns.h +tls_proxy_server_init_print.o: ../../include/htable.h +tls_proxy_server_init_print.o: ../../include/myaddrinfo.h +tls_proxy_server_init_print.o: ../../include/mymalloc.h +tls_proxy_server_init_print.o: ../../include/name_code.h +tls_proxy_server_init_print.o: ../../include/name_mask.h +tls_proxy_server_init_print.o: ../../include/nvtable.h +tls_proxy_server_init_print.o: ../../include/sock_addr.h +tls_proxy_server_init_print.o: ../../include/sys_defs.h +tls_proxy_server_init_print.o: ../../include/vbuf.h +tls_proxy_server_init_print.o: ../../include/vstream.h +tls_proxy_server_init_print.o: ../../include/vstring.h +tls_proxy_server_init_print.o: tls.h +tls_proxy_server_init_print.o: tls_proxy.h +tls_proxy_server_init_print.o: tls_proxy_server_init_print.c +tls_proxy_server_init_scan.o: ../../include/argv.h +tls_proxy_server_init_scan.o: ../../include/attr.h +tls_proxy_server_init_scan.o: ../../include/check_arg.h +tls_proxy_server_init_scan.o: ../../include/dns.h +tls_proxy_server_init_scan.o: ../../include/htable.h +tls_proxy_server_init_scan.o: ../../include/myaddrinfo.h +tls_proxy_server_init_scan.o: ../../include/mymalloc.h +tls_proxy_server_init_scan.o: ../../include/name_code.h +tls_proxy_server_init_scan.o: ../../include/name_mask.h +tls_proxy_server_init_scan.o: ../../include/nvtable.h +tls_proxy_server_init_scan.o: ../../include/sock_addr.h +tls_proxy_server_init_scan.o: ../../include/sys_defs.h +tls_proxy_server_init_scan.o: ../../include/vbuf.h +tls_proxy_server_init_scan.o: ../../include/vstream.h +tls_proxy_server_init_scan.o: ../../include/vstring.h +tls_proxy_server_init_scan.o: tls.h +tls_proxy_server_init_scan.o: tls_proxy.h +tls_proxy_server_init_scan.o: tls_proxy_server_init_scan.c +tls_proxy_server_start_print.o: ../../include/argv.h +tls_proxy_server_start_print.o: ../../include/attr.h +tls_proxy_server_start_print.o: ../../include/check_arg.h +tls_proxy_server_start_print.o: ../../include/dns.h +tls_proxy_server_start_print.o: ../../include/htable.h +tls_proxy_server_start_print.o: ../../include/myaddrinfo.h +tls_proxy_server_start_print.o: ../../include/mymalloc.h +tls_proxy_server_start_print.o: ../../include/name_code.h +tls_proxy_server_start_print.o: ../../include/name_mask.h +tls_proxy_server_start_print.o: ../../include/nvtable.h +tls_proxy_server_start_print.o: ../../include/sock_addr.h +tls_proxy_server_start_print.o: ../../include/sys_defs.h +tls_proxy_server_start_print.o: ../../include/vbuf.h +tls_proxy_server_start_print.o: ../../include/vstream.h +tls_proxy_server_start_print.o: ../../include/vstring.h +tls_proxy_server_start_print.o: tls.h +tls_proxy_server_start_print.o: tls_proxy.h +tls_proxy_server_start_print.o: tls_proxy_server_start_print.c +tls_proxy_server_start_scan.o: ../../include/argv.h +tls_proxy_server_start_scan.o: ../../include/attr.h +tls_proxy_server_start_scan.o: ../../include/check_arg.h +tls_proxy_server_start_scan.o: ../../include/dns.h +tls_proxy_server_start_scan.o: ../../include/htable.h +tls_proxy_server_start_scan.o: ../../include/myaddrinfo.h +tls_proxy_server_start_scan.o: ../../include/mymalloc.h +tls_proxy_server_start_scan.o: ../../include/name_code.h +tls_proxy_server_start_scan.o: ../../include/name_mask.h +tls_proxy_server_start_scan.o: ../../include/nvtable.h +tls_proxy_server_start_scan.o: ../../include/sock_addr.h +tls_proxy_server_start_scan.o: ../../include/sys_defs.h +tls_proxy_server_start_scan.o: ../../include/vbuf.h +tls_proxy_server_start_scan.o: ../../include/vstream.h +tls_proxy_server_start_scan.o: ../../include/vstring.h +tls_proxy_server_start_scan.o: tls.h +tls_proxy_server_start_scan.o: tls_proxy.h +tls_proxy_server_start_scan.o: tls_proxy_server_start_scan.c tls_rsa.o: ../../include/argv.h tls_rsa.o: ../../include/check_arg.h tls_rsa.o: ../../include/dns.h diff --git a/postfix/src/tls/tls.h b/postfix/src/tls/tls.h index 79b8d73a3..01419cb56 100644 --- a/postfix/src/tls/tls.h +++ b/postfix/src/tls/tls.h @@ -448,6 +448,7 @@ typedef struct { typedef struct { TLS_APPL_STATE *ctx; VSTREAM *stream; + int fd; /* Event-driven file descriptor */ int timeout; int tls_level; /* Security level */ const char *nexthop; /* destination domain */ @@ -465,6 +466,8 @@ typedef struct { extern TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *); extern TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *); +extern TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *, + const TLS_CLIENT_START_PROPS *); #define tls_client_stop(ctx, stream, timeout, failure, TLScontext) \ tls_session_stop(ctx, (stream), (timeout), (failure), (TLScontext)) @@ -477,11 +480,12 @@ extern TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *); ((props)->a12), ((props)->a13), (props))) #define TLS_CLIENT_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \ - a10, a11, a12, a13, a14, a15) \ + a10, a11, a12, a13, a14, a15, a16) \ tls_client_start((((props)->a1), ((props)->a2), ((props)->a3), \ ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \ ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \ - ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), (props))) + ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \ + ((props)->a16), (props))) /* * tls_server.c diff --git a/postfix/src/tls/tls_client.c b/postfix/src/tls/tls_client.c index bbe18f905..09e523364 100644 --- a/postfix/src/tls/tls_client.c +++ b/postfix/src/tls/tls_client.c @@ -12,6 +12,10 @@ /* TLS_SESS_STATE *tls_client_start(start_props) /* const TLS_CLIENT_START_PROPS *start_props; /* +/* TLS_SESS_STATE *tls_client_post_connect(TLScontext, start_props) +/* TLS_SESS_STATE *TLScontext; +/* const TLS_CLIENT_START_PROPS *start_props; +/* /* void tls_client_stop(app_ctx, stream, failure, TLScontext) /* TLS_APPL_STATE *app_ctx; /* VSTREAM *stream; @@ -96,6 +100,31 @@ /* the fingerprint of the certificate. /* .PP /* If no peer certificate is presented the peer_status is set to 0. +/* EVENT_DRIVEN APPLICATIONS +/* .ad +/* .fi +/* Event-driven programs manage multiple I/O channels. Such +/* programs cannot use the synchronous VSTREAM-over-TLS +/* implementation that the current TLS library provides, +/* including tls_client_stop() and the underlying tls_stream(3) +/* and tls_bio_ops(3) routines. +/* +/* With the current TLS library implementation, this means +/* that an event-driven application is responsible for calling +/* and retrying SSL_connect(), SSL_read(), SSL_write() and +/* SSL_shutdown(). +/* +/* To maintain control over TLS I/O, an event-driven client +/* invokes tls_client_start() with a null VSTREAM argument and +/* with an fd argument that specifies the I/O file descriptor. +/* Then, tls_client_start() performs all the necessary +/* preparations before the TLS handshake and returns a partially +/* populated TLS context. The event-driven application is then +/* responsible for invoking SSL_connect(), and if successful, +/* for invoking tls_client_post_connect() to finish the work +/* that was started by tls_client_start(). In case of unrecoverable +/* failure, tls_client_post_connect() destroys the TLS context +/* and returns a null pointer value. /* LICENSE /* .ad /* .fi @@ -837,8 +866,6 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) int protomask; const char *cipher_list; SSL_SESSION *session = 0; - SSL_CIPHER_const SSL_CIPHER *cipher; - X509 *peercert; TLS_SESS_STATE *TLScontext; TLS_APPL_STATE *app_ctx = props->ctx; char *myserverid; @@ -1018,7 +1045,8 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) /* * Connect the SSL connection with the network socket. */ - if (SSL_set_fd(TLScontext->con, vstream_fileno(props->stream)) != 1) { + if (SSL_set_fd(TLScontext->con, props->stream == 0 ? props->fd : + vstream_fileno(props->stream)) != 1) { msg_info("SSL_set_fd error to %s", props->namaddr); tls_print_errors(); uncache_session(app_ctx->ssl_ctx, TLScontext); @@ -1026,12 +1054,6 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) return (0); } - /* - * Turn on non-blocking I/O so that we can enforce timeouts on network - * I/O. - */ - non_blocking(vstream_fileno(props->stream), NON_BLOCKING); - /* * If the debug level selected is high enough, all of the data is dumped: * TLS_LOG_TLSPKTS will dump the SSL negotiation, TLS_LOG_ALLPKTS will @@ -1046,6 +1068,19 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) tls_dane_set_callback(app_ctx->ssl_ctx, TLScontext); + /* + * If we don't trigger the handshake in the library, leave control over + * SSL_connect/read/write/etc with the application. + */ + if (props->stream == 0) + return (TLScontext); + + /* + * Turn on non-blocking I/O so that we can enforce timeouts on network + * I/O. + */ + non_blocking(vstream_fileno(props->stream), NON_BLOCKING); + /* * Start TLS negotiations. This process is a black box that invokes our * call-backs for certificate verification. @@ -1069,8 +1104,19 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) tls_free_context(TLScontext); return (0); } + return (tls_client_post_connect(TLScontext, props)); +} + +/* tls_client_post_connect - post-handshake processing */ + +TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *TLScontext, + const TLS_CLIENT_START_PROPS *props) +{ + SSL_CIPHER_const SSL_CIPHER *cipher; + X509 *peercert; + /* Turn off packet dump if only dumping the handshake */ - if ((log_mask & TLS_LOG_ALLPKTS) == 0) + if ((TLScontext->log_mask & TLS_LOG_ALLPKTS) == 0) BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); /* @@ -1078,7 +1124,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) * session was negotiated. */ TLScontext->session_reused = SSL_session_reused(TLScontext->con); - if ((log_mask & TLS_LOG_CACHE) && TLScontext->session_reused) + if ((TLScontext->log_mask & TLS_LOG_CACHE) && TLScontext->session_reused) msg_info("%s: Reusing old session", TLScontext->namaddr); /* @@ -1125,7 +1171,8 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) * The TLS engine is active. Switch to the tls_timed_read/write() * functions and make the TLScontext available to those functions. */ - tls_stream_start(props->stream, TLScontext); + if (TLScontext->stream != 0) + tls_stream_start(props->stream, TLScontext); /* * Fully secured only if trusted, matched and not insecure like halfdane. @@ -1142,7 +1189,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) /* * All the key facts in a single log entry. */ - if (log_mask & TLS_LOG_SUMMARY) + if (TLScontext->log_mask & TLS_LOG_SUMMARY) msg_info("%s TLS connection established to %s: %s with cipher %s " "(%d/%d bits)", !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" : diff --git a/postfix/src/tls/tls_proxy.h b/postfix/src/tls/tls_proxy.h index e677c67ab..921d3c765 100644 --- a/postfix/src/tls/tls_proxy.h +++ b/postfix/src/tls/tls_proxy.h @@ -31,13 +31,139 @@ #ifdef USE_TLS +#define tls_proxy_legacy_open(service, flags, peer_stream, peer_addr, \ + peer_port, timeout, serverid) \ + tls_proxy_open((service), (flags), (peer_stream), (peer_addr), \ + (peer_port), (timeout), (serverid), (void *) 0, (void *) 0) + extern VSTREAM *tls_proxy_open(const char *, int, VSTREAM *, const char *, - const char *, int); + const char *, int, const char *, + void *, void *); + +#define TLS_PROXY_CLIENT_INIT_PROPS(props, a1, a2, a3, a4, a5, a6, a7, a8, \ + a9, a10, a11, a12, a13) \ + (((props)->a1), ((props)->a2), ((props)->a3), \ + ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \ + ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \ + ((props)->a12), ((props)->a13)) + +#define TLS_PROXY_CLIENT_START_PROPS(props, a1, a2, a3, a4, a5, a6, a7, a8, \ + a9, a10, a11, a12) \ + (((props)->a1), ((props)->a2), ((props)->a3), \ + ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \ + ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \ + ((props)->a12)) + extern TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *); extern void tls_proxy_context_free(TLS_SESS_STATE *); extern int tls_proxy_context_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *); extern int tls_proxy_context_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *); +extern int tls_proxy_client_init_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *); +extern int tls_proxy_client_init_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *); +extern void tls_proxy_client_init_free(TLS_CLIENT_INIT_PROPS *); +extern char *tls_proxy_client_init_to_string(VSTRING *, TLS_CLIENT_INIT_PROPS *); + +extern int tls_proxy_client_start_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *); +extern int tls_proxy_client_start_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *); +extern void tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *); + +extern int tls_proxy_server_init_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *); +extern int tls_proxy_server_init_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *); +extern void tls_proxy_server_init_free(TLS_SERVER_INIT_PROPS *); + +extern int tls_proxy_server_start_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *); +extern int tls_proxy_server_start_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *); +extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *); + + /* + * TLSPROXY attributes + */ +#define TLS_ATTR_REMOTE_ENDPT "remote_endpoint" /* name[addr]:port */ +#define TLS_ATTR_FLAGS "flags" +#define TLS_ATTR_TIMEOUT "timeout" +#define TLS_ATTR_SERVERID "serverid" + + /* + * TLS_SESS_STATE attributes. + */ +#define TLS_ATTR_PEER_CN "peer_CN" +#define TLS_ATTR_ISSUER_CN "issuer_CN" +#define TLS_ATTR_PEER_CERT_FPT "peer_fingerprint" +#define TLS_ATTR_PEER_PKEY_FPT "peer_pubkey_fingerprint" +#define TLS_ATTR_PEER_STATUS "peer_status" +#define TLS_ATTR_CIPHER_PROTOCOL "cipher_protocol" +#define TLS_ATTR_CIPHER_NAME "cipher_name" +#define TLS_ATTR_CIPHER_USEBITS "cipher_usebits" +#define TLS_ATTR_CIPHER_ALGBITS "cipher_algbits" + + /* + * TLS_SERVER_INIT_PROPS attributes. + */ +#define TLS_ATTR_LOG_PARAM "log_param" +#define TLS_ATTR_LOG_LEVEL "log_level" +#define TLS_ATTR_VERIFYDEPTH "verifydepth" +#define TLS_ATTR_CACHE_TYPE "cache_type" +#define TLS_ATTR_SET_SESSID "set_sessid" +#define TLS_ATTR_CERT_FILE "cert_file" +#define TLS_ATTR_KEY_FILE "key_file" +#define TLS_ATTR_DCERT_FILE "dcert_file" +#define TLS_ATTR_DKEY_FILE "dkey_file" +#define TLS_ATTR_ECCERT_FILE "eccert_file" +#define TLS_ATTR_ECKEY_FILE "eckey_file" +#define TLS_ATTR_CAFILE "CAfile" +#define TLS_ATTR_CAPATH "CApath" +#define TLS_ATTR_PROTOCOLS "protocols" +#define TLS_ATTR_EECDH_GRADE "eecdh_grade" +#define TLS_ATTR_DH1K_PARAM_FILE "dh1024_param_file" +#define TLS_ATTR_DH512_PARAM_FILE "dh512_param_file" +#define TLS_ATTR_ASK_CCERT "ask_ccert" +#define TLS_ATTR_MDALG "mdalg" + + /* + * TLS_SERVER_START_PROPS attributes. + */ +#define TLS_ATTR_TIMEOUT "timeout" +#define TLS_ATTR_REQUIRECERT "requirecert" +#define TLS_ATTR_SERVERID "serverid" +#define TLS_ATTR_NAMADDR "namaddr" +#define TLS_ATTR_CIPHER_GRADE "cipher_grade" +#define TLS_ATTR_CIPHER_EXCLUSIONS "cipher_exclusions" +#define TLS_ATTR_MDALG "mdalg" + + /* + * TLS_CLIENT_INIT_PROPS attributes. + */ +#define TLS_ATTR_LOG_PARAM "log_param" +#define TLS_ATTR_LOG_LEVEL "log_level" +#define TLS_ATTR_VERIFYDEPTH "verifydepth" +#define TLS_ATTR_CACHE_TYPE "cache_type" +#define TLS_ATTR_CERT_FILE "cert_file" +#define TLS_ATTR_KEY_FILE "key_file" +#define TLS_ATTR_DCERT_FILE "dcert_file" +#define TLS_ATTR_DKEY_FILE "dkey_file" +#define TLS_ATTR_ECCERT_FILE "eccert_file" +#define TLS_ATTR_ECKEY_FILE "eckey_file" +#define TLS_ATTR_CAFILE "CAfile" +#define TLS_ATTR_CAPATH "CApath" +#define TLS_ATTR_MDALG "mdalg" + + /* + * TLS_CLIENT_START_PROPS attributes. + */ +#define TLS_ATTR_TIMEOUT "timeout" +#define TLS_ATTR_TLS_LEVEL "tls_level" +#define TLS_ATTR_NEXTHOP "nexthop" +#define TLS_ATTR_HOST "host" +#define TLS_ATTR_NAMADDR "namaddr" +#define TLS_ATTR_SERVERID "serverid" +#define TLS_ATTR_HELO "helo" +#define TLS_ATTR_PROTOCOLS "protocols" +#define TLS_ATTR_CIPHER_GRADE "cipher_grade" +#define TLS_ATTR_CIPHER_EXCLUSIONS "cipher_exclusions" +#define TLS_ATTR_MATCHARGV "matchargv" +#define TLS_ATTR_MDALG "mdalg" + #endif /* LICENSE diff --git a/postfix/src/tls/tls_proxy_client_init_print.c b/postfix/src/tls/tls_proxy_client_init_print.c new file mode 100644 index 000000000..00157c2fe --- /dev/null +++ b/postfix/src/tls/tls_proxy_client_init_print.c @@ -0,0 +1,90 @@ +/*++ +/* NAME +/* tls_proxy_client_init_print.c +/* SUMMARY +/* write TLS_CLIENT_INIT_PROPS structure to stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_client_init_print(print_fn, stream, flags, ptr) +/* ATTR_PRINT_MASTER_FN print_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* DESCRIPTION +/* tls_proxy_client_init_print() writes a full TLS_CLIENT_INIT_PROPS +/* structure to the named stream using the specified attribute +/* print routine. tls_proxy_client_init_print() is meant to +/* be passed as a call-back to attr_print(), thusly: +/* +/* SEND_ATTR_FUNC(tls_proxy_client_init_print, (void *) tls_context), ... +/* DIAGNOSTICS +/* Fatal: out of memory. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_client_init_print - send TLS_CLIENT_INIT_PROPS over stream */ + +int tls_proxy_client_init_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_CLIENT_INIT_PROPS *props = (TLS_CLIENT_INIT_PROPS *) ptr; + int ret; + +#define STRING_OR_EMPTY(s) ((s) ? (s) : "") + + ret = print_fn(fp, flags | ATTR_FLAG_MORE, + SEND_ATTR_STR(TLS_ATTR_LOG_PARAM, + STRING_OR_EMPTY(props->log_param)), + SEND_ATTR_STR(TLS_ATTR_LOG_LEVEL, + STRING_OR_EMPTY(props->log_level)), + SEND_ATTR_INT(TLS_ATTR_VERIFYDEPTH, props->verifydepth), + SEND_ATTR_STR(TLS_ATTR_CACHE_TYPE, + STRING_OR_EMPTY(props->cache_type)), + SEND_ATTR_STR(TLS_ATTR_CERT_FILE, + STRING_OR_EMPTY(props->cert_file)), + SEND_ATTR_STR(TLS_ATTR_KEY_FILE, + STRING_OR_EMPTY(props->key_file)), + SEND_ATTR_STR(TLS_ATTR_DCERT_FILE, + STRING_OR_EMPTY(props->dcert_file)), + SEND_ATTR_STR(TLS_ATTR_DKEY_FILE, + STRING_OR_EMPTY(props->dkey_file)), + SEND_ATTR_STR(TLS_ATTR_ECCERT_FILE, + STRING_OR_EMPTY(props->eccert_file)), + SEND_ATTR_STR(TLS_ATTR_ECKEY_FILE, + STRING_OR_EMPTY(props->eckey_file)), + SEND_ATTR_STR(TLS_ATTR_CAFILE, + STRING_OR_EMPTY(props->CAfile)), + SEND_ATTR_STR(TLS_ATTR_CAPATH, + STRING_OR_EMPTY(props->CApath)), + SEND_ATTR_STR(TLS_ATTR_MDALG, + STRING_OR_EMPTY(props->mdalg)), + ATTR_TYPE_END); + /* Do not flush the stream. */ + return (ret); +} + +#endif diff --git a/postfix/src/tls/tls_proxy_client_init_scan.c b/postfix/src/tls/tls_proxy_client_init_scan.c new file mode 100644 index 000000000..a7dedec81 --- /dev/null +++ b/postfix/src/tls/tls_proxy_client_init_scan.c @@ -0,0 +1,161 @@ +/*++ +/* NAME +/* tls_proxy_client_init_scan +/* SUMMARY +/* read TLS_CLIENT_INIT_PROPS from stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_client_init_scan(scan_fn, stream, flags, ptr) +/* ATTR_SCAN_MASTER_FN scan_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* +/* char *tls_proxy_client_init_to_string(buf, props) +/* VSTRING *buf; +/* TLS_CLIENT_INIT_PROPS *props; +/* +/* void tls_proxy_client_init_free(props) +/* TLS_CLIENT_INIT_PROPS *props; +/* DESCRIPTION +/* tls_proxy_client_init_scan() reads a full TLS_CLIENT_INIT_PROPS +/* structure from the named stream using the specified attribute +/* scan routine. tls_proxy_client_init_scan() is meant to be passed +/* as a call-back function to attr_scan(), as shown below. +/* +/* tls_proxy_client_init_to_string() produces a lookup key +/* that is unique for the properties received by +/* tls_proxy_client_init_scan(). +/* +/* tls_proxy_client_init_free() destroys a TLS_CLIENT_INIT_PROPS +/* structure that was created by tls_proxy_client_init_scan(). +/* This must be called even if the tls_proxy_client_init_scan() +/* call returned an error. +/* +/* TLS_CLIENT_INIT_PROPS *props = 0; +/* ... +/* ... RECV_ATTR_FUNC(tls_proxy_client_init_scan, (void *) &props), ... +/* ... +/* if (props != 0) +/* tls_proxy_client_init_free(props); +/* DIAGNOSTICS +/* Fatal: out of memory. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_client_init_scan - receive TLS_CLIENT_INIT_PROPS from stream */ + +int tls_proxy_client_init_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_CLIENT_INIT_PROPS *props + = (TLS_CLIENT_INIT_PROPS *) mymalloc(sizeof(*props)); + int ret; + VSTRING *log_param = vstring_alloc(25); + VSTRING *log_level = vstring_alloc(25); + VSTRING *cache_type = vstring_alloc(25); + VSTRING *cert_file = vstring_alloc(25); + VSTRING *key_file = vstring_alloc(25); + VSTRING *dcert_file = vstring_alloc(25); + VSTRING *dkey_file = vstring_alloc(25); + VSTRING *eccert_file = vstring_alloc(25); + VSTRING *eckey_file = vstring_alloc(25); + VSTRING *CAfile = vstring_alloc(25); + VSTRING *CApath = vstring_alloc(25); + VSTRING *mdalg = vstring_alloc(25); + + /* + * Note: memset() is not a portable way to initialize non-integer types. + */ + memset(props, 0, sizeof(*props)); + ret = scan_fn(fp, flags | ATTR_FLAG_MORE, + RECV_ATTR_STR(TLS_ATTR_LOG_PARAM, log_param), + RECV_ATTR_STR(TLS_ATTR_LOG_LEVEL, log_level), + RECV_ATTR_INT(TLS_ATTR_VERIFYDEPTH, &props->verifydepth), + RECV_ATTR_STR(TLS_ATTR_CACHE_TYPE, cache_type), + RECV_ATTR_STR(TLS_ATTR_CERT_FILE, cert_file), + RECV_ATTR_STR(TLS_ATTR_KEY_FILE, key_file), + RECV_ATTR_STR(TLS_ATTR_DCERT_FILE, dcert_file), + RECV_ATTR_STR(TLS_ATTR_DKEY_FILE, dkey_file), + RECV_ATTR_STR(TLS_ATTR_ECCERT_FILE, eccert_file), + RECV_ATTR_STR(TLS_ATTR_ECKEY_FILE, eckey_file), + RECV_ATTR_STR(TLS_ATTR_CAFILE, CAfile), + RECV_ATTR_STR(TLS_ATTR_CAPATH, CApath), + RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg), + ATTR_TYPE_END); + props->log_param = vstring_export(log_param); + props->log_level = vstring_export(log_level); + props->cache_type = vstring_export(cache_type); + props->cert_file = vstring_export(cert_file); + props->key_file = vstring_export(key_file); + props->dcert_file = vstring_export(dcert_file); + props->dkey_file = vstring_export(dkey_file); + props->eccert_file = vstring_export(eccert_file); + props->eckey_file = vstring_export(eckey_file); + props->CAfile = vstring_export(CAfile); + props->CApath = vstring_export(CApath); + props->mdalg = vstring_export(mdalg); + *(TLS_CLIENT_INIT_PROPS **) ptr = props; + return (ret == 13 ? 1 : -1); +} + +/* tls_proxy_client_init_to_string - serialize to string */ + +char *tls_proxy_client_init_to_string(VSTRING *buf, + TLS_CLIENT_INIT_PROPS *props) +{ + vstring_sprintf(buf, "%s\n%s\n%d\n%s\n%s\n%s\n%s\n%s\n" + "%s\n%s\n%s\n%s\n%s\n", props->log_param, + props->log_level, props->verifydepth, + props->cache_type, props->cert_file, props->key_file, + props->dcert_file, props->dkey_file, + props->eccert_file, props->eckey_file, + props->CAfile, props->CApath, props->mdalg); + return (vstring_str(buf)); +} + +/* tls_proxy_client_init_free - destroy TLS_CLIENT_INIT_PROPS structure */ + +void tls_proxy_client_init_free(TLS_CLIENT_INIT_PROPS *props) +{ + myfree((void *) props->log_param); + myfree((void *) props->log_level); + myfree((void *) props->cache_type); + myfree((void *) props->cert_file); + myfree((void *) props->key_file); + myfree((void *) props->dcert_file); + myfree((void *) props->dkey_file); + myfree((void *) props->eccert_file); + myfree((void *) props->eckey_file); + myfree((void *) props->CAfile); + myfree((void *) props->CApath); + myfree((void *) props->mdalg); + myfree((void *) props); +} + +#endif diff --git a/postfix/src/tls/tls_proxy_client_start_print.c b/postfix/src/tls/tls_proxy_client_start_print.c new file mode 100644 index 000000000..a04959517 --- /dev/null +++ b/postfix/src/tls/tls_proxy_client_start_print.c @@ -0,0 +1,89 @@ +/*++ +/* NAME +/* tls_proxy_client_start_print.c +/* SUMMARY +/* write TLS_CLIENT_START_PROPS structure to stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_client_start_print(print_fn, stream, flags, ptr) +/* ATTR_PRINT_MASTER_FN print_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* DESCRIPTION +/* tls_proxy_client_start_print() writes a TLS_CLIENT_START_PROPS +/* structure, without stream or file descriptor members, to +/* the named stream using the specified attribute print routine. +/* tls_proxy_client_start_print() is meant to be passed as a +/* call-back to attr_print(), thusly: +/* +/* SEND_ATTR_FUNC(tls_proxy_client_start_print, (void *) props), ... +/* DIAGNOSTICS +/* Fatal: out of memory. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_client_start_print - send TLS_CLIENT_START_PROPS over stream */ + +int tls_proxy_client_start_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_CLIENT_START_PROPS *props = (TLS_CLIENT_START_PROPS *) ptr; + int ret; + +#define STRING_OR_EMPTY(s) ((s) ? (s) : "") + + ret = print_fn(fp, flags | ATTR_FLAG_MORE, + SEND_ATTR_INT(TLS_ATTR_TIMEOUT, props->timeout), + SEND_ATTR_INT(TLS_ATTR_TLS_LEVEL, props->tls_level), + SEND_ATTR_STR(TLS_ATTR_NEXTHOP, + STRING_OR_EMPTY(props->nexthop)), + SEND_ATTR_STR(TLS_ATTR_HOST, + STRING_OR_EMPTY(props->host)), + SEND_ATTR_STR(TLS_ATTR_NAMADDR, + STRING_OR_EMPTY(props->namaddr)), + SEND_ATTR_STR(TLS_ATTR_SERVERID, + STRING_OR_EMPTY(props->serverid)), + SEND_ATTR_STR(TLS_ATTR_HELO, + STRING_OR_EMPTY(props->helo)), + SEND_ATTR_STR(TLS_ATTR_PROTOCOLS, + STRING_OR_EMPTY(props->protocols)), + SEND_ATTR_STR(TLS_ATTR_CIPHER_GRADE, + STRING_OR_EMPTY(props->cipher_grade)), + SEND_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS, + STRING_OR_EMPTY(props->cipher_exclusions)), + SEND_ATTR_FUNC(argv_attr_print, (void *) props->matchargv), + SEND_ATTR_STR(TLS_ATTR_MDALG, + STRING_OR_EMPTY(props->mdalg)), + /* TODO: DANE. */ + ATTR_TYPE_END); + /* Do not flush the stream. */ + return (ret); +} + +#endif diff --git a/postfix/src/tls/tls_proxy_client_start_scan.c b/postfix/src/tls/tls_proxy_client_start_scan.c new file mode 100644 index 000000000..04e519817 --- /dev/null +++ b/postfix/src/tls/tls_proxy_client_start_scan.c @@ -0,0 +1,138 @@ +/*++ +/* NAME +/* tls_proxy_client_start_scan +/* SUMMARY +/* read TLS_CLIENT_START_PROPS from stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_client_start_scan(scan_fn, stream, flags, ptr) +/* ATTR_SCAN_MASTER_FN scan_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* +/* void tls_proxy_client_start_free(props) +/* TLS_CLIENT_START_PROPS *props; +/* DESCRIPTION +/* tls_proxy_client_start_scan() reads a TLS_CLIENT_START_PROPS +/* structure, without the stream of file descriptor members, +/* from the named stream using the specified attribute scan +/* routine. tls_proxy_client_start_scan() is meant to be passed +/* as a call-back function to attr_scan(), as shown below. +/* +/* tls_proxy_client_start_free() destroys a TLS_CLIENT_START_PROPS +/* structure that was created by tls_proxy_client_start_scan(). +/* This must be called even if the tls_proxy_client_start_scan() +/* call returned an error. +/* +/* TLS_CLIENT_START_PROPS *props = 0; +/* ... +/* ... RECV_ATTR_FUNC(tls_proxy_client_start_scan, (void *) &props), ... +/* ... +/* if (props != 0) +/* tls_proxy_client_start_free(props); +/* DIAGNOSTICS +/* Fatal: out of memory. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_client_start_scan - receive TLS_CLIENT_START_PROPS from stream */ + +int tls_proxy_client_start_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_CLIENT_START_PROPS *props + = (TLS_CLIENT_START_PROPS *) mymalloc(sizeof(*props)); + int ret; + VSTRING *nexthop = vstring_alloc(25); + VSTRING *host = vstring_alloc(25); + VSTRING *namaddr = vstring_alloc(25); + VSTRING *serverid = vstring_alloc(25); + VSTRING *helo = vstring_alloc(25); + VSTRING *protocols = vstring_alloc(25); + VSTRING *cipher_grade = vstring_alloc(25); + VSTRING *cipher_exclusions = vstring_alloc(25); + VSTRING *mdalg = vstring_alloc(25); + + /* + * Note: memset() is not a portable way to initialize non-integer types. + */ + memset(props, 0, sizeof(*props)); + props->ctx = 0; + props->stream = 0; + props->fd = -1; + props->dane = 0; + ret = scan_fn(fp, flags | ATTR_FLAG_MORE, + RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &props->timeout), + RECV_ATTR_INT(TLS_ATTR_TLS_LEVEL, &props->tls_level), + RECV_ATTR_STR(TLS_ATTR_NEXTHOP, nexthop), + RECV_ATTR_STR(TLS_ATTR_HOST, host), + RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr), + RECV_ATTR_STR(TLS_ATTR_SERVERID, serverid), + RECV_ATTR_STR(TLS_ATTR_HELO, helo), + RECV_ATTR_STR(TLS_ATTR_PROTOCOLS, protocols), + RECV_ATTR_STR(TLS_ATTR_CIPHER_GRADE, cipher_grade), + RECV_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS, cipher_exclusions), + RECV_ATTR_FUNC(argv_attr_scan, &props->matchargv), + RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg), + /* TODO: DANE. */ + ATTR_TYPE_END); + props->nexthop = vstring_export(nexthop); + props->host = vstring_export(host); + props->namaddr = vstring_export(namaddr); + props->serverid = vstring_export(serverid); + props->helo = vstring_export(helo); + props->protocols = vstring_export(protocols); + props->cipher_grade = vstring_export(cipher_grade); + props->cipher_exclusions = vstring_export(cipher_exclusions); + props->mdalg = vstring_export(mdalg); + *(TLS_CLIENT_START_PROPS **) ptr = props; + return (ret == 12 ? 1 : -1); +} + +/* tls_proxy_client_start_free - destroy TLS_CLIENT_START_PROPS structure */ + +void tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props) +{ + /* TODO: stream and file descriptor. */ + myfree((void *) props->nexthop); + myfree((void *) props->host); + myfree((void *) props->namaddr); + myfree((void *) props->serverid); + myfree((void *) props->helo); + myfree((void *) props->protocols); + myfree((void *) props->cipher_grade); + myfree((void *) props->cipher_exclusions); + if (props->matchargv) + argv_free((ARGV *) props->matchargv); + myfree((void *) props->mdalg); + /* TODO: DANE. */ + myfree((void *) props); +} + +#endif diff --git a/postfix/src/tls/tls_proxy_clnt.c b/postfix/src/tls/tls_proxy_clnt.c index 97d096264..e000b57ea 100644 --- a/postfix/src/tls/tls_proxy_clnt.c +++ b/postfix/src/tls/tls_proxy_clnt.c @@ -2,24 +2,36 @@ /* NAME /* tlsproxy_clnt 3 /* SUMMARY -/* postscreen TLS proxy support +/* tlsproxy(8) client support /* SYNOPSIS /* #include /* /* VSTREAM *tls_proxy_open(service, flags, peer_stream, peer_addr, -/* peer_port, timeout) +/* peer_port, timeout, serverid, init_props, +/* start_props) /* const char *service; /* int flags; /* VSTREAM *peer_stream; /* const char *peer_addr; /* const char *peer_port; /* int timeout; +/* const char *serverid; +/* void *init_props; +/* void *start_props; /* /* TLS_SESS_STATE *tls_proxy_context_receive(proxy_stream) /* VSTREAM *proxy_stream; -/* -/* void tls_proxy_context_free(tls_context) -/* TLS_SESS_STATE *tls_context; +/* AUXILIARY FUNCTIONS +/* VSTREAM *tls_proxy_legacy_open(service, flags, peer_stream, +/* peer_addr, peer_port, +/* timeout, serverid) +/* const char *service; +/* int flags; +/* VSTREAM *peer_stream; +/* const char *peer_addr; +/* const char *peer_port; +/* int timeout; +/* const char *serverid; /* DESCRIPTION /* tls_proxy_open() prepares for inserting the tlsproxy(8) /* daemon between the current process and a remote peer (the @@ -44,8 +56,8 @@ /* /* After this, the proxy_stream is ready for plain-text I/O. /* -/* tls_proxy_context_free() destroys a TLS context object that -/* was received with tls_proxy_context_receive(). +/* tls_proxy_legacy_open() is a backwards-compatibility feature +/* that provides a historical interface. /* /* Arguments: /* .IP service @@ -68,6 +80,12 @@ /* Printable TCP port of the remote peer_stream endpoint. /* .IP timeout /* Time limit that the tlsproxy(8) daemon should use. +/* .IP serverid +/* Unique service identifier. +/* .IP init_props +/* Pointer to TLS_CLIENT_INIT_PROPS or TLS_SERVER_INIT_PROPS. +/* .IP start_props +/* Pointer to TLS_CLIENT_START_PROPS or TLS_SERVER_START_PROPS. /* .IP proxy_stream /* Stream from tls_proxy_open(). /* .IP tls_context @@ -81,6 +99,11 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA /*--*/ #ifdef USE_TLS @@ -119,8 +142,12 @@ VSTREAM *tls_proxy_open(const char *service, int flags, VSTREAM *peer_stream, const char *peer_addr, const char *peer_port, - int timeout) + int timeout, + const char *serverid, + void *init_props, + void *start_props) { + const char myname[] = "tls_proxy_open"; VSTREAM *tlsproxy_stream; int status; int fd; @@ -146,19 +173,42 @@ VSTREAM *tls_proxy_open(const char *service, int flags, } /* - * Initial handshake. Send the data attributes now, and send the client - * file descriptor in a later transaction. - * - * XXX The formatted endpoint should be a state member. Then, we can - * simplify all the format strings throughout the program. + * Initial handshake. Send common data attributes now, and send the + * remote peer file descriptor in a later transaction. */ tlsproxy_stream = vstream_fdopen(fd, O_RDWR); vstring_sprintf(remote_endpt, "[%s]:%s", peer_addr, peer_port); attr_print(tlsproxy_stream, ATTR_FLAG_NONE, - SEND_ATTR_STR(MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt)), - SEND_ATTR_INT(MAIL_ATTR_FLAGS, flags), - SEND_ATTR_INT(MAIL_ATTR_TIMEOUT, timeout), + SEND_ATTR_STR(TLS_ATTR_REMOTE_ENDPT, STR(remote_endpt)), + SEND_ATTR_INT(TLS_ATTR_FLAGS, flags), + SEND_ATTR_INT(TLS_ATTR_TIMEOUT, timeout), + SEND_ATTR_STR(TLS_ATTR_SERVERID, serverid), ATTR_TYPE_END); + /* Do not flush the stream yet. */ + if (vstream_ferror(tlsproxy_stream) != 0) { + msg_warn("error sending request to %s service: %m", + STR(tlsproxy_service)); + vstream_fclose(tlsproxy_stream); + return (0); + } + switch (flags & (TLS_PROXY_FLAG_ROLE_CLIENT | TLS_PROXY_FLAG_ROLE_SERVER)) { + case TLS_PROXY_FLAG_ROLE_CLIENT: + attr_print(tlsproxy_stream, ATTR_FLAG_NONE, + SEND_ATTR_FUNC(tls_proxy_client_init_print, init_props), + SEND_ATTR_FUNC(tls_proxy_client_start_print, start_props), + ATTR_TYPE_END); + break; + case TLS_PROXY_FLAG_ROLE_SERVER: +#if 0 + attr_print(tlsproxy_stream, ATTR_FLAG_NONE, + SEND_ATTR_FUNC(tls_proxy_server_init_print, init_props), + SEND_ATTR_FUNC(tls_proxy_server_start_print, start_props), + ATTR_TYPE_END); +#endif + break; + default: + msg_panic("%s: bad flags: 0x%x", myname, flags); + } if (vstream_fflush(tlsproxy_stream) != 0) { msg_warn("error sending request to %s service: %m", STR(tlsproxy_service)); @@ -170,7 +220,7 @@ VSTREAM *tls_proxy_open(const char *service, int flags, * Receive the "TLS is available" indication. * * This may seem out of order, but we must have a read transaction between - * sending the request attributes and sending the SMTP client file + * sending the request attributes and sending the plaintext file * descriptor. We can't assume UNIX-domain socket semantics here. */ if (attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT, @@ -191,7 +241,7 @@ VSTREAM *tls_proxy_open(const char *service, int flags, } /* - * Send the remote SMTP client file descriptor. + * Send the remote peer file descriptor. */ if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream), vstream_fileno(peer_stream)) < 0) { @@ -211,37 +261,17 @@ VSTREAM *tls_proxy_open(const char *service, int flags, TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *proxy_stream) { - TLS_SESS_STATE *tls_context; - - tls_context = (TLS_SESS_STATE *) mymalloc(sizeof(*tls_context)); + TLS_SESS_STATE *tls_context = 0; if (attr_scan(proxy_stream, ATTR_FLAG_STRICT, - RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) tls_context), + RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) &tls_context), ATTR_TYPE_END) != 1) { - tls_proxy_context_free(tls_context); + if (tls_context) + tls_proxy_context_free(tls_context); return (0); } else { return (tls_context); } } -/* tls_proxy_context_free - destroy object from tls_proxy_context_receive() */ - -void tls_proxy_context_free(TLS_SESS_STATE *tls_context) -{ - if (tls_context->peer_CN) - myfree(tls_context->peer_CN); - if (tls_context->issuer_CN) - myfree(tls_context->issuer_CN); - if (tls_context->peer_cert_fprint) - myfree(tls_context->peer_cert_fprint); - if (tls_context->peer_pkey_fprint) - myfree(tls_context->peer_pkey_fprint); - if (tls_context->protocol) - myfree((void *) tls_context->protocol); - if (tls_context->cipher_name) - myfree((void *) tls_context->cipher_name); - myfree((void *) tls_context); -} - #endif diff --git a/postfix/src/tls/tls_proxy_print.c b/postfix/src/tls/tls_proxy_context_print.c similarity index 63% rename from postfix/src/tls/tls_proxy_print.c rename to postfix/src/tls/tls_proxy_context_print.c index e30e8be88..a597024b2 100644 --- a/postfix/src/tls/tls_proxy_print.c +++ b/postfix/src/tls/tls_proxy_context_print.c @@ -1,8 +1,8 @@ /*++ /* NAME -/* tls_proxy_print +/* tls_proxy_context_print /* SUMMARY -/* write DSN structure to stream +/* write TLS_ATTR_STATE structure to stream /* SYNOPSIS /* #include /* @@ -12,10 +12,10 @@ /* int flags; /* void *ptr; /* DESCRIPTION -/* tls_proxy_context_print() writes a TLS_SESS_STATE structure -/* to the named stream using the specified attribute print -/* routine. TLS_SESS_STATE() is meant to be passed as a call-back -/* to attr_print(), thusly: +/* tls_proxy_context_print() writes the public members of a +/* TLS_ATTR_STATE structure to the named stream using the +/* specified attribute print routine. tls_proxy_context_print() +/* is meant to be passed as a call-back to attr_print(), thusly: /* /* ... SEND_ATTR_FUNC(tls_proxy_context_print, (void *) tls_context), ... /* DIAGNOSTICS @@ -29,6 +29,11 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA /*--*/ #ifdef USE_TLS @@ -41,10 +46,6 @@ #include -/* Global library. */ - -#include - /* TLS library. */ #include @@ -61,25 +62,26 @@ int tls_proxy_context_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, #define STRING_OR_EMPTY(s) ((s) ? (s) : "") ret = print_fn(fp, flags | ATTR_FLAG_MORE, - SEND_ATTR_STR(MAIL_ATTR_PEER_CN, + SEND_ATTR_STR(TLS_ATTR_PEER_CN, STRING_OR_EMPTY(tp->peer_CN)), - SEND_ATTR_STR(MAIL_ATTR_ISSUER_CN, + SEND_ATTR_STR(TLS_ATTR_ISSUER_CN, STRING_OR_EMPTY(tp->issuer_CN)), - SEND_ATTR_STR(MAIL_ATTR_PEER_CERT_FPT, + SEND_ATTR_STR(TLS_ATTR_PEER_CERT_FPT, STRING_OR_EMPTY(tp->peer_cert_fprint)), - SEND_ATTR_STR(MAIL_ATTR_PEER_PKEY_FPT, + SEND_ATTR_STR(TLS_ATTR_PEER_PKEY_FPT, STRING_OR_EMPTY(tp->peer_pkey_fprint)), - SEND_ATTR_INT(MAIL_ATTR_PEER_STATUS, + SEND_ATTR_INT(TLS_ATTR_PEER_STATUS, tp->peer_status), - SEND_ATTR_STR(MAIL_ATTR_CIPHER_PROTOCOL, + SEND_ATTR_STR(TLS_ATTR_CIPHER_PROTOCOL, STRING_OR_EMPTY(tp->protocol)), - SEND_ATTR_STR(MAIL_ATTR_CIPHER_NAME, + SEND_ATTR_STR(TLS_ATTR_CIPHER_NAME, STRING_OR_EMPTY(tp->cipher_name)), - SEND_ATTR_INT(MAIL_ATTR_CIPHER_USEBITS, + SEND_ATTR_INT(TLS_ATTR_CIPHER_USEBITS, tp->cipher_usebits), - SEND_ATTR_INT(MAIL_ATTR_CIPHER_ALGBITS, + SEND_ATTR_INT(TLS_ATTR_CIPHER_ALGBITS, tp->cipher_algbits), ATTR_TYPE_END); + /* Do not flush the stream. */ return (ret); } diff --git a/postfix/src/tls/tls_proxy_context_scan.c b/postfix/src/tls/tls_proxy_context_scan.c new file mode 100644 index 000000000..b2fe1d5f8 --- /dev/null +++ b/postfix/src/tls/tls_proxy_context_scan.c @@ -0,0 +1,128 @@ +/*++ +/* NAME +/* tls_proxy_context_scan +/* SUMMARY +/* read TLS session state from stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_context_scan(scan_fn, stream, flags, ptr) +/* ATTR_SCAN_MASTER_FN scan_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* +/* void tls_proxy_context_free(tls_context) +/* TLS_SESS_STATE *tls_context; +/* DESCRIPTION +/* tls_proxy_context_scan() reads the public members of a +/* TLS_ATTR_STATE structure from the named stream using the +/* specified attribute scan routine. tls_proxy_context_scan() +/* is meant to be passed as a call-back to attr_scan() as shown +/* below. +/* +/* tls_proxy_context_free() destroys a TLS context object that +/* was received with tls_proxy_context_scan(). +/* +/* TLS_ATTR_STATE *tls_context = 0; +/* ... +/* ... RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) &tls_context), ... +/* ... +/* if (tls_context) +/* tls_proxy_context_free(tls_context); +/* DIAGNOSTICS +/* Fatal: out of memory. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_context_scan - receive TLS session state from stream */ + +int tls_proxy_context_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_SESS_STATE *tls_context + = (TLS_SESS_STATE *) mymalloc(sizeof(*tls_context));; + int ret; + VSTRING *peer_CN = vstring_alloc(25); + VSTRING *issuer_CN = vstring_alloc(25); + VSTRING *peer_cert_fprint = vstring_alloc(60); /* 60 for SHA-1 */ + VSTRING *peer_pkey_fprint = vstring_alloc(60); /* 60 for SHA-1 */ + VSTRING *protocol = vstring_alloc(25); + VSTRING *cipher_name = vstring_alloc(25); + + /* + * Note: memset() is not a portable way to initialize non-integer types. + */ + memset(tls_context, 0, sizeof(*tls_context)); + ret = scan_fn(fp, flags | ATTR_FLAG_MORE, + RECV_ATTR_STR(TLS_ATTR_PEER_CN, peer_CN), + RECV_ATTR_STR(TLS_ATTR_ISSUER_CN, issuer_CN), + RECV_ATTR_STR(TLS_ATTR_PEER_CERT_FPT, peer_cert_fprint), + RECV_ATTR_STR(TLS_ATTR_PEER_PKEY_FPT, peer_pkey_fprint), + RECV_ATTR_INT(TLS_ATTR_PEER_STATUS, + &tls_context->peer_status), + RECV_ATTR_STR(TLS_ATTR_CIPHER_PROTOCOL, protocol), + RECV_ATTR_STR(TLS_ATTR_CIPHER_NAME, cipher_name), + RECV_ATTR_INT(TLS_ATTR_CIPHER_USEBITS, + &tls_context->cipher_usebits), + RECV_ATTR_INT(TLS_ATTR_CIPHER_ALGBITS, + &tls_context->cipher_algbits), + ATTR_TYPE_END); + tls_context->peer_CN = vstring_export(peer_CN); + tls_context->issuer_CN = vstring_export(issuer_CN); + tls_context->peer_cert_fprint = vstring_export(peer_cert_fprint); + tls_context->peer_pkey_fprint = vstring_export(peer_pkey_fprint); + tls_context->protocol = vstring_export(protocol); + tls_context->cipher_name = vstring_export(cipher_name); + *(TLS_SESS_STATE **) ptr = tls_context; + return (ret == 9 ? 1 : -1); +} + +/* tls_proxy_context_free - destroy object from tls_proxy_context_receive() */ + +void tls_proxy_context_free(TLS_SESS_STATE *tls_context) +{ + if (tls_context->peer_CN) + myfree(tls_context->peer_CN); + if (tls_context->issuer_CN) + myfree(tls_context->issuer_CN); + if (tls_context->peer_cert_fprint) + myfree(tls_context->peer_cert_fprint); + if (tls_context->peer_pkey_fprint) + myfree(tls_context->peer_pkey_fprint); + if (tls_context->protocol) + myfree((void *) tls_context->protocol); + if (tls_context->cipher_name) + myfree((void *) tls_context->cipher_name); + myfree((void *) tls_context); +} + +#endif diff --git a/postfix/src/tls/tls_proxy_scan.c b/postfix/src/tls/tls_proxy_scan.c deleted file mode 100644 index 29a0cd9f9..000000000 --- a/postfix/src/tls/tls_proxy_scan.c +++ /dev/null @@ -1,94 +0,0 @@ -/*++ -/* NAME -/* tls_proxy_scan -/* SUMMARY -/* read TLS session state from stream -/* SYNOPSIS -/* #include -/* -/* int tls_proxy_context_scan(scan_fn, stream, flags, ptr) -/* ATTR_SCAN_MASTER_FN scan_fn; -/* VSTREAM *stream; -/* int flags; -/* void *ptr; -/* DESCRIPTION -/* tls_proxy_context_scan() reads a TLS_SESS_STATE structure -/* from the named stream using the specified attribute scan -/* routine. tls_proxy_context_scan() is meant to be passed as -/* a call-back to attr_scan(), thusly: -/* -/* ... RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) tls_context), ... -/* DIAGNOSTICS -/* Fatal: out of memory. -/* LICENSE -/* .ad -/* .fi -/* The Secure Mailer license must be distributed with this software. -/* AUTHOR(S) -/* Wietse Venema -/* IBM T.J. Watson Research -/* P.O. Box 704 -/* Yorktown Heights, NY 10598, USA -/*--*/ - -#ifdef USE_TLS - -/* System library. */ - -#include - -/* Utility library */ - -#include - -/* Global library. */ - -#include - -/* TLS library. */ - -#include -#include - -/* tls_proxy_context_scan - receive TLS session state from stream */ - -int tls_proxy_context_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, - int flags, void *ptr) -{ - TLS_SESS_STATE *tls_context = (TLS_SESS_STATE *) ptr; - int ret; - VSTRING *peer_CN = vstring_alloc(25); - VSTRING *issuer_CN = vstring_alloc(25); - VSTRING *peer_cert_fprint = vstring_alloc(60); /* 60 for SHA-1 */ - VSTRING *peer_pkey_fprint = vstring_alloc(60); /* 60 for SHA-1 */ - VSTRING *protocol = vstring_alloc(25); - VSTRING *cipher_name = vstring_alloc(25); - - /* - * Note: memset() is not a portable way to initialize non-integer types. - */ - memset(ptr, 0, sizeof(TLS_SESS_STATE)); - ret = scan_fn(fp, flags | ATTR_FLAG_MORE, - RECV_ATTR_STR(MAIL_ATTR_PEER_CN, peer_CN), - RECV_ATTR_STR(MAIL_ATTR_ISSUER_CN, issuer_CN), - RECV_ATTR_STR(MAIL_ATTR_PEER_CERT_FPT, peer_cert_fprint), - RECV_ATTR_STR(MAIL_ATTR_PEER_PKEY_FPT, peer_pkey_fprint), - RECV_ATTR_INT(MAIL_ATTR_PEER_STATUS, - &tls_context->peer_status), - RECV_ATTR_STR(MAIL_ATTR_CIPHER_PROTOCOL, protocol), - RECV_ATTR_STR(MAIL_ATTR_CIPHER_NAME, cipher_name), - RECV_ATTR_INT(MAIL_ATTR_CIPHER_USEBITS, - &tls_context->cipher_usebits), - RECV_ATTR_INT(MAIL_ATTR_CIPHER_ALGBITS, - &tls_context->cipher_algbits), - ATTR_TYPE_END); - tls_context->peer_CN = vstring_export(peer_CN); - tls_context->issuer_CN = vstring_export(issuer_CN); - tls_context->peer_cert_fprint = vstring_export(peer_cert_fprint); - tls_context->peer_pkey_fprint = vstring_export(peer_pkey_fprint); - tls_context->protocol = vstring_export(protocol); - tls_context->cipher_name = vstring_export(cipher_name); - return (ret == 9 ? 1 : -1); -} - -#endif diff --git a/postfix/src/tls/tls_proxy_server_init_print.c b/postfix/src/tls/tls_proxy_server_init_print.c new file mode 100644 index 000000000..14a658729 --- /dev/null +++ b/postfix/src/tls/tls_proxy_server_init_print.c @@ -0,0 +1,100 @@ +/*++ +/* NAME +/* tls_proxy_server_init_print +/* SUMMARY +/* write TLS_SERVER_INIT_PROPS structure to stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_server_init_print(print_fn, stream, flags, ptr) +/* ATTR_PRINT_MASTER_FN print_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* DESCRIPTION +/* tls_proxy_server_init_print() writes a TLS_SERVER_INIT_PROPS +/* structure to the named stream using the specified attribute print +/* routine. tls_proxy_server_init_print() is meant to be passed as +/* a call-back to attr_print(), thusly: +/* +/* ... SEND_ATTR_FUNC(tls_proxy_server_init_print, (void *) props), ... +/* DIAGNOSTICS +/* Fatal: out of memory. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_server_init_print - send TLS_SERVER_INIT_PROPS over stream */ + +int tls_proxy_server_init_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_SERVER_INIT_PROPS *props = (TLS_SERVER_INIT_PROPS *) ptr; + int ret; + +#define STRING_OR_EMPTY(s) ((s) ? (s) : "") + + ret = print_fn(fp, flags | ATTR_FLAG_MORE, + SEND_ATTR_STR(TLS_ATTR_LOG_PARAM, + STRING_OR_EMPTY(props->log_param)), + SEND_ATTR_STR(TLS_ATTR_LOG_LEVEL, + STRING_OR_EMPTY(props->log_level)), + SEND_ATTR_INT(TLS_ATTR_VERIFYDEPTH, props->verifydepth), + SEND_ATTR_STR(TLS_ATTR_CACHE_TYPE, + STRING_OR_EMPTY(props->cache_type)), + SEND_ATTR_INT(TLS_ATTR_SET_SESSID, props->set_sessid), + SEND_ATTR_STR(TLS_ATTR_CERT_FILE, + STRING_OR_EMPTY(props->cert_file)), + SEND_ATTR_STR(TLS_ATTR_KEY_FILE, + STRING_OR_EMPTY(props->key_file)), + SEND_ATTR_STR(TLS_ATTR_DCERT_FILE, + STRING_OR_EMPTY(props->dcert_file)), + SEND_ATTR_STR(TLS_ATTR_DKEY_FILE, + STRING_OR_EMPTY(props->dkey_file)), + SEND_ATTR_STR(TLS_ATTR_ECCERT_FILE, + STRING_OR_EMPTY(props->eccert_file)), + SEND_ATTR_STR(TLS_ATTR_ECKEY_FILE, + STRING_OR_EMPTY(props->eckey_file)), + SEND_ATTR_STR(TLS_ATTR_CAFILE, + STRING_OR_EMPTY(props->CAfile)), + SEND_ATTR_STR(TLS_ATTR_CAPATH, + STRING_OR_EMPTY(props->CApath)), + SEND_ATTR_STR(TLS_ATTR_PROTOCOLS, + STRING_OR_EMPTY(props->protocols)), + SEND_ATTR_STR(TLS_ATTR_EECDH_GRADE, + STRING_OR_EMPTY(props->eecdh_grade)), + SEND_ATTR_STR(TLS_ATTR_DH1K_PARAM_FILE, + STRING_OR_EMPTY(props->dh1024_param_file)), + SEND_ATTR_STR(TLS_ATTR_DH512_PARAM_FILE, + STRING_OR_EMPTY(props->dh512_param_file)), + SEND_ATTR_INT(TLS_ATTR_ASK_CCERT, props->ask_ccert), + SEND_ATTR_STR(TLS_ATTR_MDALG, + STRING_OR_EMPTY(props->mdalg)), + ATTR_TYPE_END); + /* Do not flush the stream. */ + return (ret); +} + +#endif diff --git a/postfix/src/tls/tls_proxy_server_init_scan.c b/postfix/src/tls/tls_proxy_server_init_scan.c new file mode 100644 index 000000000..57b12ba21 --- /dev/null +++ b/postfix/src/tls/tls_proxy_server_init_scan.c @@ -0,0 +1,155 @@ +/*++ +/* NAME +/* tls_proxy_server_init_scan +/* SUMMARY +/* read TLS_SERVER_INIT_PROPS from stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_server_init_scan(scan_fn, stream, flags, ptr) +/* ATTR_SCAN_MASTER_FN scan_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* +/* tls_proxy_server_init_free(props) +/* TLS_SERVER_INIT_PROPS *props; +/* DESCRIPTION +/* tls_proxy_server_init_scan() reads a TLS_SERVER_INIT_PROPS +/* structure from the named stream using the specified attribute +/* scan routine. tls_proxy_server_init_scan() is meant to be passed +/* as a call-back function to attr_scan(), as shown below. +/* +/* tls_proxy_server_init_free() destroys a TLS_SERVER_INIT_PROPS +/* structure that was created by tls_proxy_server_init_scan(). +/* This must be called even if the tls_proxy_server_init_scan() +/* call returned an error. +/* +/* TLS_SERVER_INIT_PROPS *props = 0; +/* ... +/* ... RECV_ATTR_FUNC(tls_proxy_server_init_scan, (void *) &props), ... +/* ... +/* if (props) +/* tls_proxy_client_init_free(props); +/* DIAGNOSTICS +/* Fatal: out of memory. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_server_init_scan - receive TLS_SERVER_INIT_PROPS from stream */ + +int tls_proxy_server_init_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_SERVER_INIT_PROPS *props + = (TLS_SERVER_INIT_PROPS *) mymalloc(sizeof(*props)); + int ret; + VSTRING *log_param = vstring_alloc(25); + VSTRING *log_level = vstring_alloc(25); + VSTRING *cache_type = vstring_alloc(25); + VSTRING *cert_file = vstring_alloc(25); + VSTRING *key_file = vstring_alloc(25); + VSTRING *dcert_file = vstring_alloc(25); + VSTRING *dkey_file = vstring_alloc(25); + VSTRING *eccert_file = vstring_alloc(25); + VSTRING *eckey_file = vstring_alloc(25); + VSTRING *CAfile = vstring_alloc(25); + VSTRING *CApath = vstring_alloc(25); + VSTRING *protocols = vstring_alloc(25); + VSTRING *eecdh_grade = vstring_alloc(25); + VSTRING *dh1024_param_file = vstring_alloc(25); + VSTRING *dh512_param_file = vstring_alloc(25); + VSTRING *mdalg = vstring_alloc(25); + + /* + * Note: memset() is not a portable way to initialize non-integer types. + */ + memset(props, 0, sizeof(*props)); + ret = scan_fn(fp, flags | ATTR_FLAG_MORE, + RECV_ATTR_STR(TLS_ATTR_LOG_PARAM, log_param), + RECV_ATTR_STR(TLS_ATTR_LOG_LEVEL, log_level), + RECV_ATTR_INT(TLS_ATTR_VERIFYDEPTH, &props->verifydepth), + RECV_ATTR_STR(TLS_ATTR_CACHE_TYPE, cache_type), + RECV_ATTR_INT(TLS_ATTR_SET_SESSID, &props->set_sessid), + RECV_ATTR_STR(TLS_ATTR_CERT_FILE, cert_file), + RECV_ATTR_STR(TLS_ATTR_KEY_FILE, key_file), + RECV_ATTR_STR(TLS_ATTR_DCERT_FILE, dcert_file), + RECV_ATTR_STR(TLS_ATTR_DKEY_FILE, dkey_file), + RECV_ATTR_STR(TLS_ATTR_ECCERT_FILE, eccert_file), + RECV_ATTR_STR(TLS_ATTR_ECKEY_FILE, eckey_file), + RECV_ATTR_STR(TLS_ATTR_CAFILE, CAfile), + RECV_ATTR_STR(TLS_ATTR_CAPATH, CApath), + RECV_ATTR_STR(TLS_ATTR_PROTOCOLS, protocols), + RECV_ATTR_STR(TLS_ATTR_EECDH_GRADE, eecdh_grade), + RECV_ATTR_STR(TLS_ATTR_DH1K_PARAM_FILE, dh1024_param_file), + RECV_ATTR_STR(TLS_ATTR_DH512_PARAM_FILE, dh512_param_file), + RECV_ATTR_INT(TLS_ATTR_ASK_CCERT, &props->ask_ccert), + RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg), + ATTR_TYPE_END); + props->log_param = vstring_export(log_param); + props->log_level = vstring_export(log_level); + props->cache_type = vstring_export(cache_type); + props->cert_file = vstring_export(cert_file); + props->key_file = vstring_export(key_file); + props->dcert_file = vstring_export(dcert_file); + props->dkey_file = vstring_export(dkey_file); + props->eccert_file = vstring_export(eccert_file); + props->eckey_file = vstring_export(eckey_file); + props->CAfile = vstring_export(CAfile); + props->CApath = vstring_export(CApath); + props->protocols = vstring_export(protocols); + props->eecdh_grade = vstring_export(eecdh_grade); + props->dh1024_param_file = vstring_export(dh1024_param_file); + props->dh512_param_file = vstring_export(dh512_param_file); + props->mdalg = vstring_export(mdalg); + *(TLS_SERVER_INIT_PROPS **) ptr = props; + return (ret == 19 ? 1 : -1); +} + +/* tls_proxy_server_init_free - destroy TLS_SERVER_INIT_PROPS structure */ + +void tls_proxy_server_init_free(TLS_SERVER_INIT_PROPS *props) +{ + myfree((void *) props->log_param); + myfree((void *) props->log_level); + myfree((void *) props->cache_type); + myfree((void *) props->cert_file); + myfree((void *) props->key_file); + myfree((void *) props->dcert_file); + myfree((void *) props->dkey_file); + myfree((void *) props->eccert_file); + myfree((void *) props->eckey_file); + myfree((void *) props->CAfile); + myfree((void *) props->CApath); + myfree((void *) props->protocols); + myfree((void *) props->eecdh_grade); + myfree((void *) props->dh1024_param_file); + myfree((void *) props->dh512_param_file); + myfree((void *) props->mdalg); + myfree((void *) props); +} + +#endif diff --git a/postfix/src/tls/tls_proxy_server_start_print.c b/postfix/src/tls/tls_proxy_server_start_print.c new file mode 100644 index 000000000..73498ad5f --- /dev/null +++ b/postfix/src/tls/tls_proxy_server_start_print.c @@ -0,0 +1,77 @@ +/*++ +/* NAME +/* tls_proxy_server_start_print.c +/* SUMMARY +/* write TLS_SERVER_START_PROPS structure to stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_server_start_print(print_fn, stream, flags, ptr) +/* ATTR_PRINT_MASTER_FN print_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* DESCRIPTION +/* tls_proxy_server_start_print() writes a TLS_SERVER_START_PROPS +/* structure to the named stream using the specified attribute print +/* routine. tls_proxy_server_start_print() is meant to be passed as +/* a call-back to attr_print(), thusly: +/* +/* ... SEND_ATTR_FUNC(tls_proxy_server_start_print, (void *) props), ... +/* DIAGNOSTICS +/* Fatal: out of memory. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_server_start_print - send TLS_SERVER_START_PROPS over stream */ + +int tls_proxy_server_start_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_SERVER_START_PROPS *props = (TLS_SERVER_START_PROPS *) ptr; + int ret; + +#define STRING_OR_EMPTY(s) ((s) ? (s) : "") + + ret = print_fn(fp, flags | ATTR_FLAG_MORE, + SEND_ATTR_INT(TLS_ATTR_TIMEOUT, props->timeout), + SEND_ATTR_INT(TLS_ATTR_REQUIRECERT, props->requirecert), + SEND_ATTR_STR(TLS_ATTR_SERVERID, + STRING_OR_EMPTY(props->serverid)), + SEND_ATTR_STR(TLS_ATTR_NAMADDR, + STRING_OR_EMPTY(props->namaddr)), + SEND_ATTR_STR(TLS_ATTR_CIPHER_GRADE, + STRING_OR_EMPTY(props->cipher_grade)), + SEND_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS, + STRING_OR_EMPTY(props->cipher_exclusions)), + SEND_ATTR_STR(TLS_ATTR_MDALG, + STRING_OR_EMPTY(props->mdalg)), + ATTR_TYPE_END); + /* Do not flush the stream. */ + return (ret); +} + +#endif diff --git a/postfix/src/tls/tls_proxy_server_start_scan.c b/postfix/src/tls/tls_proxy_server_start_scan.c new file mode 100644 index 000000000..352776e41 --- /dev/null +++ b/postfix/src/tls/tls_proxy_server_start_scan.c @@ -0,0 +1,114 @@ +/*++ +/* NAME +/* tls_proxy_server_start_scan +/* SUMMARY +/* read TLS_SERVER_START_PROPS from stream +/* SYNOPSIS +/* #include +/* +/* int tls_proxy_server_start_scan(scan_fn, stream, flags, ptr) +/* ATTR_SCAN_MASTER_FN scan_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* +/* void tls_proxy_server_start_free(props) +/* TLS_SERVER_START_PROPS *props; +/* DESCRIPTION +/* tls_proxy_server_start_scan() reads a TLS_SERVER_START_PROPS +/* structure from the named stream using the specified attribute +/* scan routine. tls_proxy_server_start_scan() is meant to be passed +/* as a call-back function to attr_scan(), as shown below. +/* +/* tls_proxy_server_start_free() destroys a TLS_SERVER_START_PROPS +/* structure that was created by tls_proxy_server_start_scan(). +/* This must be called even if the tls_proxy_server_start_scan() +/* call returned an error. +/* +/* TLS_SERVER_START_PROPS *props = 0; +/* ... +/* ... RECV_ATTR_FUNC(tls_proxy_server_start_scan, (void *) &props), ... +/* ... +/* if (props) +/* tls_proxy_server_start_free(props); +/* DIAGNOSTICS +/* Fatal: out of memory. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#ifdef USE_TLS + +/* System library. */ + +#include + +/* Utility library */ + +#include + +/* TLS library. */ + +#include +#include + +/* tls_proxy_server_start_scan - receive TLS_SERVER_START_PROPS from stream */ + +int tls_proxy_server_start_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, + int flags, void *ptr) +{ + TLS_SERVER_START_PROPS *props + = (TLS_SERVER_START_PROPS *) mymalloc(sizeof(*props)); + int ret; + VSTRING *serverid = vstring_alloc(25); + VSTRING *namaddr = vstring_alloc(25); + VSTRING *cipher_grade = vstring_alloc(25); + VSTRING *cipher_exclusions = vstring_alloc(25); + VSTRING *mdalg = vstring_alloc(25); + + /* + * Note: memset() is not a portable way to initialize non-integer types. + */ + memset(props, 0, sizeof(*props)); + props->ctx = 0; + props->stream = 0; + /* XXX Caller sets fd. */ + ret = scan_fn(fp, flags | ATTR_FLAG_MORE, + RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &props->timeout), + RECV_ATTR_INT(TLS_ATTR_REQUIRECERT, &props->requirecert), + RECV_ATTR_STR(TLS_ATTR_SERVERID, serverid), + RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr), + RECV_ATTR_STR(TLS_ATTR_CIPHER_GRADE, cipher_grade), + RECV_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS, cipher_exclusions), + RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg), + ATTR_TYPE_END); + props->serverid = vstring_export(serverid); + props->namaddr = vstring_export(namaddr); + props->cipher_grade = vstring_export(cipher_grade); + props->cipher_exclusions = vstring_export(cipher_exclusions); + props->mdalg = vstring_export(mdalg); + *(TLS_SERVER_START_PROPS **) ptr = props; + return (ret == 7 ? 1 : -1); +} + +/* tls_proxy_server_start_free - destroy TLS_SERVER_START_PROPS structure */ + +void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *props) +{ + /* XXX Caller closes fd. */ + myfree((void *) props->serverid); + myfree((void *) props->namaddr); + myfree((void *) props->cipher_grade); + myfree((void *) props->cipher_exclusions); + myfree((void *) props->mdalg); + myfree((void *) props); +} + +#endif diff --git a/postfix/src/tlsproxy/Makefile.in b/postfix/src/tlsproxy/Makefile.in index 087721bf7..e248f8501 100644 --- a/postfix/src/tlsproxy/Makefile.in +++ b/postfix/src/tlsproxy/Makefile.in @@ -61,6 +61,7 @@ depend: $(MAKES) @$(EXPORT) make -f Makefile.in Makefile 1>&2 # do not edit below this line - it is generated by 'make depend' +tls_client.o: tls_client.c tlsproxy.o: ../../include/argv.h tlsproxy.o: ../../include/attr.h tlsproxy.o: ../../include/check_arg.h @@ -90,9 +91,11 @@ tlsproxy.o: ../../include/vstring.h tlsproxy.o: tlsproxy.c tlsproxy.o: tlsproxy.h tlsproxy_state.o: ../../include/argv.h +tlsproxy_state.o: ../../include/attr.h tlsproxy_state.o: ../../include/check_arg.h tlsproxy_state.o: ../../include/dns.h tlsproxy_state.o: ../../include/events.h +tlsproxy_state.o: ../../include/htable.h tlsproxy_state.o: ../../include/mail_conf.h tlsproxy_state.o: ../../include/mail_server.h tlsproxy_state.o: ../../include/msg.h @@ -101,9 +104,11 @@ tlsproxy_state.o: ../../include/mymalloc.h tlsproxy_state.o: ../../include/name_code.h tlsproxy_state.o: ../../include/name_mask.h tlsproxy_state.o: ../../include/nbbio.h +tlsproxy_state.o: ../../include/nvtable.h tlsproxy_state.o: ../../include/sock_addr.h tlsproxy_state.o: ../../include/sys_defs.h tlsproxy_state.o: ../../include/tls.h +tlsproxy_state.o: ../../include/tls_proxy.h tlsproxy_state.o: ../../include/vbuf.h tlsproxy_state.o: ../../include/vstream.h tlsproxy_state.o: ../../include/vstring.h diff --git a/postfix/src/tlsproxy/tlsproxy.c b/postfix/src/tlsproxy/tlsproxy.c index 2c855ffcc..e4fc6aeb5 100644 --- a/postfix/src/tlsproxy/tlsproxy.c +++ b/postfix/src/tlsproxy/tlsproxy.c @@ -309,6 +309,17 @@ int var_tlsp_watchdog; static TLS_APPL_STATE *tlsp_server_ctx; static int ask_client_cert; + /* + * TLS per-client status. + */ +static HTABLE *tlsp_client_app_cache; + + /* + * Internal status API. + */ +#define TLSP_STAT_OK 0 +#define TLSP_STAT_ERR (-1) + /* * SLMs. */ @@ -406,7 +417,7 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err) state->timeout); state->ssl_last_err = SSL_ERROR_NONE; } - return (0); + return (TLSP_STAT_OK); /* * The TLS engine wants to write to the network. Turn on @@ -422,7 +433,7 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err) } event_request_timer(tlsp_ciphertext_event, (void *) state, state->timeout); - return (0); + return (TLSP_STAT_OK); /* * The TLS engine wants to read from the network. Turn on @@ -438,7 +449,7 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err) } event_request_timer(tlsp_ciphertext_event, (void *) state, state->timeout); - return (0); + return (TLSP_STAT_OK); /* * Some error. Self-destruct. This automagically cleans up all @@ -450,7 +461,7 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err) /* FALLTHROUGH */ default: tlsp_state_free(state); - return (-1); + return (TLSP_STAT_ERR); } } @@ -471,14 +482,22 @@ static void tlsp_strategy(TLSP_STATE *state) * pending read/write and timeout event requests. */ if (state->flags & TLSP_FLAG_DO_HANDSHAKE) { - ssl_stat = SSL_accept(tls_context->con); + if (state->is_server_role) + ssl_stat = SSL_accept(tls_context->con); + else + ssl_stat = SSL_connect(tls_context->con); if (ssl_stat != 1) { handshake_err = SSL_get_error(tls_context->con, ssl_stat); tlsp_eval_tls_error(state, handshake_err); /* At this point, state could be a dangling pointer. */ return; } - if ((state->tls_context = tls_server_post_accept(tls_context)) == 0) { + if (state->is_server_role) + state->tls_context = tls_server_post_accept(tls_context); + else + state->tls_context = tls_client_post_connect(tls_context, + state->client_start_props); + if (state->tls_context == 0) { tlsp_state_free(state); return; } @@ -661,9 +680,46 @@ static void tlsp_ciphertext_event(int event, void *context) } } -/* tlsp_start_tls - turn on TLS or force disconnect */ +/* tlsp_start_client_pre_handshake - turn on TLS or force disconnect */ + +static int tlsp_start_client_pre_handshake(TLSP_STATE *state) +{ + VSTRING *buf; + char *key; + + /* + * Share a TLS_APPL_STATE object among multiple requests that specify the + * same TLS_CLIENT_INIT_PROPS. TLS_APPL_STATE owns an SSL_CTX which is + * expensive. + */ + buf = vstring_alloc(100); + key = tls_proxy_client_init_to_string(buf, state->client_init_props); + if ((state->appl_state = (TLS_APPL_STATE *) + htable_find(tlsp_client_app_cache, key)) == 0 + && (state->appl_state = + tls_client_init(state->client_init_props)) != 0) + (void) htable_enter(tlsp_client_app_cache, key, + (void *) state->appl_state); + vstring_free(buf); + + if (state->appl_state != 0) { + state->client_start_props->ctx = state->appl_state; + state->client_start_props->fd = state->ciphertext_fd; + state->tls_context = tls_client_start(state->client_start_props); + if (state->tls_context != 0) + return (TLSP_STAT_OK); + } + + /* + * TLS client initialization failed. + */ + tlsp_state_free(state); + return (TLSP_STAT_ERR); +} + +/* tlsp_start_server_pre_handshake - turn on TLS or force disconnect */ -static int tlsp_start_tls(TLSP_STATE *state) +static int tlsp_start_server_pre_handshake(TLSP_STATE *state) { TLS_SERVER_START_PROPS props; static char *cipher_grade; @@ -676,8 +732,8 @@ static int tlsp_start_tls(TLSP_STATE *state) */ /* - * Perform the before-handshake portion of the per-session initialization. - * Pass a null VSTREAM to indicate that this program, will do the + * Perform the before-handshake portion of per-session initialization. + * Pass a null VSTREAM to indicate that this program will do the * ciphertext I/O, not libtls. * * The cipher grade and exclusions don't change between sessions. Compute @@ -716,7 +772,7 @@ static int tlsp_start_tls(TLSP_STATE *state) if (state->tls_context == 0) { tlsp_state_free(state); - return (-1); + return (TLSP_STAT_ERR); } /* @@ -729,16 +785,17 @@ static int tlsp_start_tls(TLSP_STATE *state) * XXX Do we care about certificate verification results? Not as long as * postscreen(8) doesn't actually receive email. */ - return (0); + return (TLSP_STAT_OK); } -/* tlsp_get_fd_event - receive final postscreen(8) hand-off information */ +/* tlsp_get_fd_event - receive final connection hand-off information */ static void tlsp_get_fd_event(int event, void *context) { const char *myname = "tlsp_get_fd_event"; TLSP_STATE *state = (TLSP_STATE *) context; int plaintext_fd = vstream_fileno(state->plaintext_stream); + int status; /* * At this point we still manually manage plaintext read/write/timeout @@ -751,6 +808,25 @@ static void tlsp_get_fd_event(int event, void *context) else errno = ETIMEDOUT; + if (event != EVENT_READ + || (state->ciphertext_fd = LOCAL_RECV_FD(plaintext_fd)) < 0) { + msg_warn("%s: receive remote SMTP peer file descriptor: %m", myname); + tlsp_state_free(state); + return; + } + + /* + * Perform the TLS layer before-handshake initialization. We perform the + * remainder after the actual TLS handshake completes. If this fails then + * state is a dangling pointer. + */ + if (state->is_server_role) + status = tlsp_start_server_pre_handshake(state); + else + status = tlsp_start_client_pre_handshake(state); + if (status != TLSP_STAT_OK) + return; + /* * Initialize plaintext-related session state. Once we have this behind * us, the TLSP_STATE destructor will automagically clean up requests for @@ -760,33 +836,32 @@ static void tlsp_get_fd_event(int event, void *context) * destructor. Insert the NBBIO event-driven I/O layer between the * postscreen(8) server and the TLS engine. */ - if (event != EVENT_READ - || (state->ciphertext_fd = LOCAL_RECV_FD(plaintext_fd)) < 0) { - msg_warn("%s: receive SMTP client file descriptor: %m", myname); - tlsp_state_free(state); - return; - } non_blocking(state->ciphertext_fd, NON_BLOCKING); state->ciphertext_timer = tlsp_ciphertext_event; state->plaintext_buf = nbbio_create(plaintext_fd, - VSTREAM_BUFSIZE, "postscreen", + VSTREAM_BUFSIZE, state->server_id, tlsp_plaintext_event, (void *) state); - /* - * Perform the TLS layer before-handshake initialization. We perform the - * remainder after the TLS handshake completes. - */ - if (tlsp_start_tls(state) < 0) - return; - /* * Trigger the initial proxy server I/Os. */ tlsp_strategy(state); } -/* tlsp_get_request_event - receive initial postscreen(8) hand-off info */ +/* tlsp_close_event - handle plaintext-client close event */ + +static void tlsp_close_event(int event, void *context) +{ + TLSP_STATE *state = (TLSP_STATE *) context; + int plaintext_fd = vstream_fileno(state->plaintext_stream); + + event_cancel_timer(tlsp_close_event, (void *) state); + event_disable_readwrite(plaintext_fd); + tlsp_state_free(state); +} + +/* tlsp_get_request_event - receive initial hand-off info */ static void tlsp_get_request_event(int event, void *context) { @@ -798,7 +873,7 @@ static void tlsp_get_request_event(int event, void *context) static VSTRING *server_id; int req_flags; int timeout; - int ready; + int ready = 0; /* * One-time initialization. @@ -825,10 +900,10 @@ static void tlsp_get_request_event(int event, void *context) */ if (event != EVENT_READ || attr_scan(plaintext_stream, ATTR_FLAG_STRICT, - RECV_ATTR_STR(MAIL_ATTR_REMOTE_ENDPT, remote_endpt), - RECV_ATTR_INT(MAIL_ATTR_FLAGS, &req_flags), - RECV_ATTR_INT(MAIL_ATTR_TIMEOUT, &timeout), - RECV_ATTR_STR(MAIL_ATTR_SERVER_ID, server_id), + RECV_ATTR_STR(TLS_ATTR_REMOTE_ENDPT, remote_endpt), + RECV_ATTR_INT(TLS_ATTR_FLAGS, &req_flags), + RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &timeout), + RECV_ATTR_STR(TLS_ATTR_SERVERID, server_id), ATTR_TYPE_END) != 4) { msg_warn("%s: receive request attributes: %m", myname); event_disable_readwrite(plaintext_fd); @@ -836,38 +911,66 @@ static void tlsp_get_request_event(int event, void *context) return; } + /* + * XXX We use the same fixed timeout throughout the entire session for + * both plaintext and ciphertext communication. This timeout is just a + * safety feature; the real timeout will be enforced by our plaintext + * peer. + */ + state->remote_endpt = mystrdup(STR(remote_endpt)); + state->server_id = mystrdup(STR(server_id)); + msg_info("CONNECT %s %s", + (req_flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "from" : + (req_flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "to" : + "(bogus_direction)", state->remote_endpt); + state->req_flags = req_flags; + /* state->is_server_role is set below. */ + state->timeout = timeout + 10; /* XXX */ + + /* + * Receive the TLS preferences now, to reduce the number of protocol + * roundtrips. To call the pre-handshake tls_*_start() before receiving + * the ciphertext FD, pass in the FD through some other interface. + */ + switch (req_flags & (TLS_PROXY_FLAG_ROLE_CLIENT | TLS_PROXY_FLAG_ROLE_SERVER)) { + case TLS_PROXY_FLAG_ROLE_CLIENT: + state->is_server_role = 0; + if (attr_scan(plaintext_stream, ATTR_FLAG_STRICT, + RECV_ATTR_FUNC(tls_proxy_client_init_scan, + (void *) &state->client_init_props), + RECV_ATTR_FUNC(tls_proxy_client_start_scan, + (void *) &state->client_start_props), + ATTR_TYPE_END) != 2) { + msg_warn("%s: receive client TLS settings: %m", myname); + event_disable_readwrite(plaintext_fd); + tlsp_state_free(state); + return; + } + ready = 1; + break; + case TLS_PROXY_FLAG_ROLE_SERVER: + state->is_server_role = 1; + ready = (tlsp_server_ctx != 0); + break; + default: + state->is_server_role = 0; + msg_warn("%s: bad request flags: 0x%x", myname, req_flags); + ready = 0; + } + /* * If the requested TLS engine is unavailable, hang up after making sure * that the plaintext peer has received our "sorry" indication. */ - ready = ((req_flags & TLS_PROXY_FLAG_ROLE_SERVER) != 0 - && tlsp_server_ctx != 0); if (attr_print(plaintext_stream, ATTR_FLAG_NONE, SEND_ATTR_INT(MAIL_ATTR_STATUS, ready), ATTR_TYPE_END) != 0 || vstream_fflush(plaintext_stream) != 0 || ready == 0) { - read_wait(plaintext_fd, TLSP_INIT_TIMEOUT); /* XXX */ - event_disable_readwrite(plaintext_fd); - tlsp_state_free(state); + event_enable_read(plaintext_fd, tlsp_close_event, (void *) state); + event_request_timer(tlsp_close_event, (void *) state, TLSP_INIT_TIMEOUT); return; - } - - /* - * XXX We use the same fixed timeout throughout the entire session for - * both plaintext and ciphertext communication. This timeout is just a - * safety feature; the real timeout will be enforced by our plaintext - * peer. - */ - else { - state->remote_endpt = mystrdup(STR(remote_endpt)); - state->server_id = mystrdup(STR(server_id)); - msg_info("CONNECT %s %s", - (req_flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "from" : - (req_flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "to" : - "(bogus_direction)", state->remote_endpt); - state->req_flags = req_flags; - state->timeout = timeout + 10; /* XXX */ + } else { event_enable_read(plaintext_fd, tlsp_get_fd_event, (void *) state); event_request_timer(tlsp_get_fd_event, (void *) state, TLSP_INIT_TIMEOUT); @@ -1033,7 +1136,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) static void post_jail_init(char *unused_name, char **unused_argv) { - /* void */ ; + tlsp_client_app_cache = htable_create(10); } MAIL_VERSION_STAMP_DECLARE; diff --git a/postfix/src/tlsproxy/tlsproxy.h b/postfix/src/tlsproxy/tlsproxy.h index e3e1d11fa..336c58c69 100644 --- a/postfix/src/tlsproxy/tlsproxy.h +++ b/postfix/src/tlsproxy/tlsproxy.h @@ -25,6 +25,7 @@ typedef struct { int flags; /* see below */ int req_flags; /* request flags, see tls_proxy.h */ + int is_server_role; /* avoid clumsy handler code */ char *service; /* argv[0] */ VSTREAM *plaintext_stream; /* local peer: postscreen(8), etc. */ NBBIO *plaintext_buf; /* plaintext buffer */ @@ -33,8 +34,13 @@ typedef struct { int timeout; /* read/write time limit */ char *remote_endpt; /* printable remote endpoint */ char *server_id; /* cache management */ - TLS_SESS_STATE *tls_context; /* llibtls state */ + TLS_APPL_STATE *appl_state; /* libtls state */ + TLS_SESS_STATE *tls_context; /* libtls state */ int ssl_last_err; /* TLS I/O state */ + TLS_SERVER_INIT_PROPS *server_init_props; + TLS_SERVER_START_PROPS *server_start_props; + TLS_CLIENT_INIT_PROPS *client_init_props; + TLS_CLIENT_START_PROPS *client_start_props; } TLSP_STATE; #define TLSP_FLAG_DO_HANDSHAKE (1<<0) @@ -51,4 +57,9 @@ extern void tlsp_state_free(TLSP_STATE *); /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA /*--*/ diff --git a/postfix/src/tlsproxy/tlsproxy_state.c b/postfix/src/tlsproxy/tlsproxy_state.c index e32764920..adc2f2282 100644 --- a/postfix/src/tlsproxy/tlsproxy_state.c +++ b/postfix/src/tlsproxy/tlsproxy_state.c @@ -60,6 +60,11 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA /*--*/ /* @@ -85,6 +90,7 @@ #ifdef USE_TLS #define TLS_INTERNAL /* XXX */ #include +#include /* * Application-specific. @@ -108,6 +114,10 @@ TLSP_STATE *tlsp_state_create(const char *service, state->remote_endpt = 0; state->server_id = 0; state->tls_context = 0; + state->server_init_props = 0; + state->server_start_props = 0; + state->client_init_props = 0; + state->client_start_props = 0; return (state); } @@ -134,6 +144,14 @@ void tlsp_state_free(TLSP_STATE *state) myfree(state->server_id); if (state->tls_context) tls_free_context(state->tls_context); + if (state->server_init_props) + tls_proxy_server_init_free(state->server_init_props); + if (state->server_start_props) + tls_proxy_server_start_free(state->server_start_props); + if (state->client_init_props) + tls_proxy_client_init_free(state->client_init_props); + if (state->client_start_props) + tls_proxy_client_start_free(state->client_start_props); myfree((void *) state); } diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 32cefbc07..fad103280 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -40,7 +40,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \ poll_fd.c timecmp.c slmdb.c dict_pipe.c dict_random.c \ valid_utf8_hostname.c midna_domain.c argv_splitq.c balpar.c dict_union.c \ extpar.c dict_inline.c casefold.c dict_utf8.c strcasecmp_utf8.c \ - split_qnameval.c + split_qnameval.c argv_attr_print.c argv_attr_scan.c OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ @@ -82,7 +82,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ poll_fd.o timecmp.o $(NON_PLUGIN_MAP_OBJ) dict_pipe.o dict_random.o \ valid_utf8_hostname.o midna_domain.o argv_splitq.o balpar.o dict_union.o \ extpar.o dict_inline.o casefold.o dict_utf8.o strcasecmp_utf8.o \ - split_qnameval.o + split_qnameval.o argv_attr_print.o argv_attr_scan.o # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf. # When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ), # otherwise it sets the PLUGIN_* macros. @@ -111,7 +111,8 @@ HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ edit_file.h dict_cache.h dict_thash.h ip_match.h nbbio.h base32_code.h \ dict_fail.h warn_stat.h dict_sockmap.h line_number.h timecmp.h \ slmdb.h compat_va_copy.h dict_pipe.h dict_random.h \ - valid_utf8_hostname.h midna_domain.h dict_union.h dict_inline.h check_arg.h + valid_utf8_hostname.h midna_domain.h dict_union.h dict_inline.h \ + check_arg.h argv_attr.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c DEFS = -I. -D$(SYSTYPE) @@ -879,6 +880,31 @@ argv.o: argv.h argv.o: msg.h argv.o: mymalloc.h argv.o: sys_defs.h +argv_attr_print.o: argv.h +argv_attr_print.o: argv_attr.h +argv_attr_print.o: argv_attr_print.c +argv_attr_print.o: attr.h +argv_attr_print.o: check_arg.h +argv_attr_print.o: htable.h +argv_attr_print.o: mymalloc.h +argv_attr_print.o: nvtable.h +argv_attr_print.o: sys_defs.h +argv_attr_print.o: vbuf.h +argv_attr_print.o: vstream.h +argv_attr_print.o: vstring.h +argv_attr_scan.o: argv.h +argv_attr_scan.o: argv_attr.h +argv_attr_scan.o: argv_attr_scan.c +argv_attr_scan.o: attr.h +argv_attr_scan.o: check_arg.h +argv_attr_scan.o: htable.h +argv_attr_scan.o: msg.h +argv_attr_scan.o: mymalloc.h +argv_attr_scan.o: nvtable.h +argv_attr_scan.o: sys_defs.h +argv_attr_scan.o: vbuf.h +argv_attr_scan.o: vstream.h +argv_attr_scan.o: vstring.h argv_split.o: argv.h argv_split.o: argv_split.c argv_split.o: check_arg.h @@ -1785,6 +1811,8 @@ load_file.o: vbuf.h load_file.o: vstream.h load_file.o: warn_stat.h load_lib.o: load_lib.c +load_lib.o: load_lib.h +load_lib.o: msg.h load_lib.o: sys_defs.h lowercase.o: check_arg.h lowercase.o: lowercase.c @@ -2363,6 +2391,7 @@ vbuf.o: vbuf.c vbuf.o: vbuf.h vbuf_print.o: check_arg.h vbuf_print.o: msg.h +vbuf_print.o: mymalloc.h vbuf_print.o: sys_defs.h vbuf_print.o: vbuf.h vbuf_print.o: vbuf_print.c diff --git a/postfix/src/util/argv_attr.h b/postfix/src/util/argv_attr.h new file mode 100644 index 000000000..65cfa5541 --- /dev/null +++ b/postfix/src/util/argv_attr.h @@ -0,0 +1,43 @@ +#ifndef _ARGV_ATTR_H_INCLUDED_ +#define _ARGV_ATTR_H_INCLUDED_ + +/*++ +/* NAME +/* argv_attr 3h +/* SUMMARY +/* argv serialization/deserialization +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include +#include +#include +#include + + /* + * External API. + */ +#define ARGV_ATTR_SIZE "argv_size" +#define ARGV_ATTR_VALUE "argv_value" +#define ARGV_ATTR_MAX 1024 + +extern int argv_attr_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *); +extern int argv_attr_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *); + +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#endif diff --git a/postfix/src/util/argv_attr_print.c b/postfix/src/util/argv_attr_print.c new file mode 100644 index 000000000..1d4c576d8 --- /dev/null +++ b/postfix/src/util/argv_attr_print.c @@ -0,0 +1,73 @@ +/*++ +/* NAME +/* argv_attr_print +/* SUMMARY +/* write ARGV to stream +/* SYNOPSIS +/* #include +/* +/* int argv_attr_print(print_fn, stream, flags, ptr) +/* ATTR_PRINT_MASTER_FN print_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* DESCRIPTION +/* argv_attr_print() writes an ARGV to the named stream using +/* the specified attribute print routine. argv_attr_print() is meant +/* to be passed as a call-back to attr_print(), thusly: +/* +/* ... SEND_ATTR_FUNC(argv_attr_print, (void *) argv), ... +/* DIAGNOSTICS +/* Fatal: out of memory. +/* +/* The result value is zero in case of success, non-zero +/* otherwise. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + + /* + * System library. + */ +#include + + /* + * Utility library. + */ +#include +#include +#include +#include + +/* argv_attr_print - write ARGV to stream */ + +int argv_attr_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, + int flags, void *ptr) +{ + ARGV *argv = (ARGV *) ptr; + char **cpp; + int n; + int ret; + int argc = argv ? argv->argc : 0; + + if ((ret = print_fn(fp, flags | ATTR_FLAG_MORE, + SEND_ATTR_INT(ARGV_ATTR_SIZE, argc), + ATTR_TYPE_END)) != 0) + return (ret); + if (argc > 0) { + for (n = 0, cpp = argv->argv; n < argc; n++, cpp++) { + if ((ret = print_fn(fp, flags | ATTR_FLAG_MORE, + SEND_ATTR_STR(ARGV_ATTR_VALUE, *cpp), + ATTR_TYPE_END)) != 0) + break; + } + } + return (ret); +} diff --git a/postfix/src/util/argv_attr_scan.c b/postfix/src/util/argv_attr_scan.c new file mode 100644 index 000000000..2373343f5 --- /dev/null +++ b/postfix/src/util/argv_attr_scan.c @@ -0,0 +1,92 @@ +/*++ +/* NAME +/* argv_attr_scan +/* SUMMARY +/* read ARGV from stream +/* SYNOPSIS +/* #include +/* +/* int argv_attr_scan(scan_fn, stream, flags, ptr) +/* ATTR_SCAN_MASTER_FN scan_fn; +/* VSTREAM *stream; +/* int flags; +/* void *ptr; +/* DESCRIPTION +/* argv_attr_scan() creates an ARGV and reads its contents +/* from the named stream using the specified attribute scan +/* routine. argv_attr_scan() is meant to be passed as a call-back +/* to attr_scan(), thusly: +/* +/* ARGV *argv = 0; +/* ... +/* ... RECV_ATTR_FUNC(argv_attr_scan, (void *) &argv), ... +/* ... +/* if (argv) +/* argv_free(argv); +/* DIAGNOSTICS +/* Fatal: out of memory. +/* +/* In case of error, this function returns non-zero and creates +/* an ARGV null pointer. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + + /* + * System library. + */ +#include + + /* + * Utility library. + */ +#include +#include +#include +#include +#include +#include + +/* argv_attr_scan - write ARGV to stream */ + +int argv_attr_scan(ATTR_PRINT_MASTER_FN scan_fn, VSTREAM *fp, + int flags, void *ptr) +{ + ARGV *argv; + int size; + int ret; + + if ((ret = scan_fn(fp, flags | ATTR_FLAG_MORE, + RECV_ATTR_INT(ARGV_ATTR_SIZE, &size), + ATTR_TYPE_END)) != 0) { + argv = 0; + } else if (size < 0 || size > ARGV_ATTR_MAX) { + msg_warn("invalid size %d from %s while reading ARGV", + size, VSTREAM_PATH(fp)); + argv = 0; + } else if (size == 0) { + argv = 0; + } else { + VSTRING *buffer = vstring_alloc(100); + + argv = argv_alloc(size); + while (size-- > 0) { + if ((ret = scan_fn(fp, flags | ATTR_FLAG_MORE, + RECV_ATTR_STR(ARGV_ATTR_VALUE, buffer), + ATTR_TYPE_END)) != 0) + break; + argv_add(argv, vstring_str(buffer), ARGV_END); + } + argv_terminate(argv); + vstring_free(buffer); + } + *(ARGV **) ptr = argv; + return (ret); +}