Home | History | Annotate | Line # | Download | only in tls
      1 /*	$NetBSD: tls_proxy_client_scan.c,v 1.6 2026/05/09 18:49:21 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	tls_proxy_client_scan 3
      6 /* SUMMARY
      7 /*	read TLS_CLIENT_XXX structures from stream
      8 /* SYNOPSIS
      9 /*	#include <tls_proxy.h>
     10 /*
     11 /*	int	tls_proxy_client_param_scan(scan_fn, stream, flags, ptr)
     12 /*	ATTR_SCAN_COMMON_FN scan_fn;
     13 /*	VSTREAM	*stream;
     14 /*	int	flags;
     15 /*	void	*ptr;
     16 /*
     17 /*	void	tls_proxy_client_param_free(params)
     18 /*	TLS_CLIENT_PARAMS *params;
     19 /*
     20 /*	int	tls_proxy_client_init_scan(scan_fn, stream, flags, ptr)
     21 /*	ATTR_SCAN_COMMON_FN scan_fn;
     22 /*	VSTREAM	*stream;
     23 /*	int	flags;
     24 /*	void	*ptr;
     25 /*
     26 /*	void	tls_proxy_client_init_free(init_props)
     27 /*	TLS_CLIENT_INIT_PROPS *init_props;
     28 /*
     29 /*	int	tls_proxy_client_start_scan(scan_fn, stream, flags, ptr)
     30 /*	ATTR_SCAN_COMMON_FN scan_fn;
     31 /*	VSTREAM	*stream;
     32 /*	int	flags;
     33 /*	void	*ptr;
     34 /*
     35 /*	void	tls_proxy_client_start_free(start_props)
     36 /*	TLS_CLIENT_START_PROPS *start_props;
     37 /* DESCRIPTION
     38 /*	tls_proxy_client_param_scan() reads a TLS_CLIENT_PARAMS structure from
     39 /*	the named stream using the specified attribute scan routine.
     40 /*	tls_proxy_client_param_scan() is meant to be passed as a call-back
     41 /*	function to attr_scan(), as shown below.
     42 /*
     43 /*	tls_proxy_client_param_free() destroys a TLS_CLIENT_PARAMS structure
     44 /*	that was created by tls_proxy_client_param_scan().
     45 /*
     46 /*	TLS_CLIENT_PARAMS *param = 0;
     47 /*	...
     48 /*	... RECV_ATTR_FUNC(tls_proxy_client_param_scan, (void *) &param)
     49 /*	...
     50 /*	if (param != 0)
     51 /*	    tls_proxy_client_param_free(param);
     52 /*
     53 /*	tls_proxy_client_init_scan() reads a full TLS_CLIENT_INIT_PROPS
     54 /*	structure from the named stream using the specified attribute
     55 /*	scan routine. tls_proxy_client_init_scan() is meant to be passed
     56 /*	as a call-back function to attr_scan(), as shown below.
     57 /*
     58 /*	tls_proxy_client_init_free() destroys a TLS_CLIENT_INIT_PROPS
     59 /*	structure that was created by tls_proxy_client_init_scan().
     60 /*
     61 /*	TLS_CLIENT_INIT_PROPS *init_props = 0;
     62 /*	...
     63 /*	... RECV_ATTR_FUNC(tls_proxy_client_init_scan, (void *) &init_props)
     64 /*	...
     65 /*	if (init_props != 0)
     66 /*	    tls_proxy_client_init_free(init_props);
     67 /*
     68 /*	tls_proxy_client_start_scan() reads a TLS_CLIENT_START_PROPS
     69 /*	structure, without the stream of file descriptor members,
     70 /*	from the named stream using the specified attribute scan
     71 /*	routine. tls_proxy_client_start_scan() is meant to be passed
     72 /*	as a call-back function to attr_scan(), as shown below.
     73 /*
     74 /*	tls_proxy_client_start_free() destroys a TLS_CLIENT_START_PROPS
     75 /*	structure that was created by tls_proxy_client_start_scan().
     76 /*
     77 /*	TLS_CLIENT_START_PROPS *start_props = 0;
     78 /*	...
     79 /*	... RECV_ATTR_FUNC(tls_proxy_client_start_scan, (void *) &start_props)
     80 /*	...
     81 /*	if (start_props != 0)
     82 /*	    tls_proxy_client_start_free(start_props);
     83 /* DIAGNOSTICS
     84 /*	Fatal: out of memory.
     85 /* LICENSE
     86 /* .ad
     87 /* .fi
     88 /*	The Secure Mailer license must be distributed with this software.
     89 /* AUTHOR(S)
     90 /*	Wietse Venema
     91 /*	Google, Inc.
     92 /*	111 8th Avenue
     93 /*	New York, NY 10011, USA
     94 /*--*/
     95 
     96 #ifdef USE_TLS
     97 
     98 /* System library. */
     99 
    100 #include <sys_defs.h>
    101 
    102 /* Utility library */
    103 
    104 #include <argv_attr.h>
    105 #include <attr.h>
    106 #include <msg.h>
    107 #include <vstring.h>
    108 
    109 /* Global library. */
    110 
    111 #include <mail_params.h>
    112 
    113 /* TLS library. */
    114 
    115 #define TLS_INTERNAL
    116 #include <tls.h>
    117 #include <tls_proxy.h>
    118 #ifdef USE_TLSRPT
    119 #define TLSRPT_WRAPPER_INTERNAL
    120 #include <tlsrpt_wrapper.h>
    121 #endif
    122 
    123 #define STR(x) vstring_str(x)
    124 #define LEN(x) VSTRING_LEN(x)
    125 
    126 /* tls_proxy_client_param_free - destroy TLS_CLIENT_PARAMS structure */
    127 
    128 void    tls_proxy_client_param_free(TLS_CLIENT_PARAMS *params)
    129 {
    130     myfree(params->tls_cnf_file);
    131     myfree(params->tls_cnf_name);
    132     myfree(params->tls_high_clist);
    133     myfree(params->tls_medium_clist);
    134     myfree(params->tls_null_clist);
    135     myfree(params->tls_eecdh_auto);
    136     myfree(params->tls_eecdh_strong);
    137     myfree(params->tls_eecdh_ultra);
    138     myfree(params->tls_ffdhe_auto);
    139     myfree(params->tls_bug_tweaks);
    140     myfree(params->tls_ssl_options);
    141     myfree(params->tls_dane_digests);
    142     myfree(params->tls_mgr_service);
    143     myfree(params->tls_tkt_cipher);
    144     myfree((void *) params);
    145 }
    146 
    147 /* tls_proxy_client_param_scan - receive TLS_CLIENT_PARAMS from stream */
    148 
    149 int     tls_proxy_client_param_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
    150 				            int flags, void *ptr)
    151 {
    152     TLS_CLIENT_PARAMS *params
    153     = (TLS_CLIENT_PARAMS *) mymalloc(sizeof(*params));
    154     int     ret;
    155     VSTRING *cnf_file = vstring_alloc(25);
    156     VSTRING *cnf_name = vstring_alloc(25);
    157     VSTRING *tls_high_clist = vstring_alloc(25);
    158     VSTRING *tls_medium_clist = vstring_alloc(25);
    159     VSTRING *tls_null_clist = vstring_alloc(25);
    160     VSTRING *tls_eecdh_auto = vstring_alloc(25);
    161     VSTRING *tls_eecdh_strong = vstring_alloc(25);
    162     VSTRING *tls_eecdh_ultra = vstring_alloc(25);
    163     VSTRING *tls_ffdhe_auto = vstring_alloc(25);
    164     VSTRING *tls_bug_tweaks = vstring_alloc(25);
    165     VSTRING *tls_ssl_options = vstring_alloc(25);
    166     VSTRING *tls_dane_digests = vstring_alloc(25);
    167     VSTRING *tls_mgr_service = vstring_alloc(25);
    168     VSTRING *tls_tkt_cipher = vstring_alloc(25);
    169 
    170     if (msg_verbose)
    171 	msg_info("begin tls_proxy_client_param_scan");
    172 
    173     /*
    174      * Note: memset() is not a portable way to initialize non-integer types.
    175      */
    176     memset(params, 0, sizeof(*params));
    177     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
    178 		  RECV_ATTR_STR(TLS_ATTR_CNF_FILE, cnf_file),
    179 		  RECV_ATTR_STR(TLS_ATTR_CNF_NAME, cnf_name),
    180 		  RECV_ATTR_STR(VAR_TLS_HIGH_CLIST, tls_high_clist),
    181 		  RECV_ATTR_STR(VAR_TLS_MEDIUM_CLIST, tls_medium_clist),
    182 		  RECV_ATTR_STR(VAR_TLS_NULL_CLIST, tls_null_clist),
    183 		  RECV_ATTR_STR(VAR_TLS_EECDH_AUTO, tls_eecdh_auto),
    184 		  RECV_ATTR_STR(VAR_TLS_EECDH_STRONG, tls_eecdh_strong),
    185 		  RECV_ATTR_STR(VAR_TLS_EECDH_ULTRA, tls_eecdh_ultra),
    186 		  RECV_ATTR_STR(VAR_TLS_FFDHE_AUTO, tls_ffdhe_auto),
    187 		  RECV_ATTR_STR(VAR_TLS_BUG_TWEAKS, tls_bug_tweaks),
    188 		  RECV_ATTR_STR(VAR_TLS_SSL_OPTIONS, tls_ssl_options),
    189 		  RECV_ATTR_STR(VAR_TLS_DANE_DIGESTS, tls_dane_digests),
    190 		  RECV_ATTR_STR(VAR_TLS_MGR_SERVICE, tls_mgr_service),
    191 		  RECV_ATTR_STR(VAR_TLS_TKT_CIPHER, tls_tkt_cipher),
    192 		  RECV_ATTR_INT(VAR_TLS_DAEMON_RAND_BYTES,
    193 				&params->tls_daemon_rand_bytes),
    194 		  RECV_ATTR_INT(VAR_TLS_APPEND_DEF_CA,
    195 				&params->tls_append_def_CA),
    196 		  RECV_ATTR_INT(VAR_TLS_PREEMPT_CLIST,
    197 				&params->tls_preempt_clist),
    198 		  RECV_ATTR_INT(VAR_TLS_MULTI_WILDCARD,
    199 				&params->tls_multi_wildcard),
    200 		  ATTR_TYPE_END);
    201     /* Always construct a well-formed structure. */
    202     params->tls_cnf_file = vstring_export(cnf_file);
    203     params->tls_cnf_name = vstring_export(cnf_name);
    204     params->tls_high_clist = vstring_export(tls_high_clist);
    205     params->tls_medium_clist = vstring_export(tls_medium_clist);
    206     params->tls_null_clist = vstring_export(tls_null_clist);
    207     params->tls_eecdh_auto = vstring_export(tls_eecdh_auto);
    208     params->tls_eecdh_strong = vstring_export(tls_eecdh_strong);
    209     params->tls_eecdh_ultra = vstring_export(tls_eecdh_ultra);
    210     params->tls_ffdhe_auto = vstring_export(tls_ffdhe_auto);
    211     params->tls_bug_tweaks = vstring_export(tls_bug_tweaks);
    212     params->tls_ssl_options = vstring_export(tls_ssl_options);
    213     params->tls_dane_digests = vstring_export(tls_dane_digests);
    214     params->tls_mgr_service = vstring_export(tls_mgr_service);
    215     params->tls_tkt_cipher = vstring_export(tls_tkt_cipher);
    216 
    217     ret = (ret == 18 ? 1 : -1);
    218     if (ret != 1) {
    219 	tls_proxy_client_param_free(params);
    220 	params = 0;
    221     }
    222     *(TLS_CLIENT_PARAMS **) ptr = params;
    223     if (msg_verbose)
    224 	msg_info("tls_proxy_client_param_scan ret=%d", ret);
    225     return (ret);
    226 }
    227 
    228 /* tls_proxy_client_init_free - destroy TLS_CLIENT_INIT_PROPS structure */
    229 
    230 void    tls_proxy_client_init_free(TLS_CLIENT_INIT_PROPS *props)
    231 {
    232     myfree((void *) props->log_param);
    233     myfree((void *) props->log_level);
    234     myfree((void *) props->cache_type);
    235     myfree((void *) props->chain_files);
    236     myfree((void *) props->cert_file);
    237     myfree((void *) props->key_file);
    238     myfree((void *) props->dcert_file);
    239     myfree((void *) props->dkey_file);
    240     myfree((void *) props->eccert_file);
    241     myfree((void *) props->eckey_file);
    242     myfree((void *) props->CAfile);
    243     myfree((void *) props->CApath);
    244     myfree((void *) props->mdalg);
    245     myfree((void *) props);
    246 }
    247 
    248 /* tls_proxy_client_init_scan - receive TLS_CLIENT_INIT_PROPS from stream */
    249 
    250 int     tls_proxy_client_init_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
    251 				           int flags, void *ptr)
    252 {
    253     TLS_CLIENT_INIT_PROPS *props
    254     = (TLS_CLIENT_INIT_PROPS *) mymalloc(sizeof(*props));
    255     int     ret;
    256     VSTRING *log_param = vstring_alloc(25);
    257     VSTRING *log_level = vstring_alloc(25);
    258     VSTRING *cache_type = vstring_alloc(25);
    259     VSTRING *chain_files = vstring_alloc(25);
    260     VSTRING *cert_file = vstring_alloc(25);
    261     VSTRING *key_file = vstring_alloc(25);
    262     VSTRING *dcert_file = vstring_alloc(25);
    263     VSTRING *dkey_file = vstring_alloc(25);
    264     VSTRING *eccert_file = vstring_alloc(25);
    265     VSTRING *eckey_file = vstring_alloc(25);
    266     VSTRING *CAfile = vstring_alloc(25);
    267     VSTRING *CApath = vstring_alloc(25);
    268     VSTRING *mdalg = vstring_alloc(25);
    269 
    270     if (msg_verbose)
    271 	msg_info("begin tls_proxy_client_init_scan");
    272 
    273     /*
    274      * Note: memset() is not a portable way to initialize non-integer types.
    275      */
    276     memset(props, 0, sizeof(*props));
    277     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
    278 		  RECV_ATTR_STR(TLS_ATTR_LOG_PARAM, log_param),
    279 		  RECV_ATTR_STR(TLS_ATTR_LOG_LEVEL, log_level),
    280 		  RECV_ATTR_INT(TLS_ATTR_VERIFYDEPTH, &props->verifydepth),
    281 		  RECV_ATTR_STR(TLS_ATTR_CACHE_TYPE, cache_type),
    282 		  RECV_ATTR_STR(TLS_ATTR_CHAIN_FILES, chain_files),
    283 		  RECV_ATTR_STR(TLS_ATTR_CERT_FILE, cert_file),
    284 		  RECV_ATTR_STR(TLS_ATTR_KEY_FILE, key_file),
    285 		  RECV_ATTR_STR(TLS_ATTR_DCERT_FILE, dcert_file),
    286 		  RECV_ATTR_STR(TLS_ATTR_DKEY_FILE, dkey_file),
    287 		  RECV_ATTR_STR(TLS_ATTR_ECCERT_FILE, eccert_file),
    288 		  RECV_ATTR_STR(TLS_ATTR_ECKEY_FILE, eckey_file),
    289 		  RECV_ATTR_STR(TLS_ATTR_CAFILE, CAfile),
    290 		  RECV_ATTR_STR(TLS_ATTR_CAPATH, CApath),
    291 		  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
    292 		  ATTR_TYPE_END);
    293     /* Always construct a well-formed structure. */
    294     props->log_param = vstring_export(log_param);
    295     props->log_level = vstring_export(log_level);
    296     props->cache_type = vstring_export(cache_type);
    297     props->chain_files = vstring_export(chain_files);
    298     props->cert_file = vstring_export(cert_file);
    299     props->key_file = vstring_export(key_file);
    300     props->dcert_file = vstring_export(dcert_file);
    301     props->dkey_file = vstring_export(dkey_file);
    302     props->eccert_file = vstring_export(eccert_file);
    303     props->eckey_file = vstring_export(eckey_file);
    304     props->CAfile = vstring_export(CAfile);
    305     props->CApath = vstring_export(CApath);
    306     props->mdalg = vstring_export(mdalg);
    307     ret = (ret == 14 ? 1 : -1);
    308     if (ret != 1) {
    309 	tls_proxy_client_init_free(props);
    310 	props = 0;
    311     }
    312     *(TLS_CLIENT_INIT_PROPS **) ptr = props;
    313     if (msg_verbose)
    314 	msg_info("tls_proxy_client_init_scan ret=%d", ret);
    315     return (ret);
    316 }
    317 
    318 /* tls_proxy_client_start_free - destroy TLS_CLIENT_START_PROPS structure */
    319 
    320 void    tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
    321 {
    322     myfree((void *) props->nexthop);
    323     myfree((void *) props->host);
    324     myfree((void *) props->namaddr);
    325     myfree((void *) props->sni);
    326     myfree((void *) props->serverid);
    327     myfree((void *) props->helo);
    328     myfree((void *) props->protocols);
    329     myfree((void *) props->cipher_grade);
    330     myfree((void *) props->cipher_exclusions);
    331     if (props->matchargv)
    332 	argv_free((ARGV *) props->matchargv);
    333     myfree((void *) props->mdalg);
    334     if (props->dane)
    335 	tls_dane_free((TLS_DANE *) props->dane);
    336 #ifdef USE_TLSRPT
    337     if (props->tlsrpt)
    338 	trw_free(props->tlsrpt);
    339 #endif
    340     if (props->ffail_type)
    341 	myfree(props->ffail_type);
    342     myfree((void *) props);
    343 }
    344 
    345 /* tls_proxy_client_tlsa_scan - receive TLS_TLSA from stream */
    346 
    347 static int tls_proxy_client_tlsa_scan(ATTR_SCAN_COMMON_FN scan_fn,
    348 				          VSTREAM *fp, int flags, void *ptr)
    349 {
    350     static VSTRING *data;
    351     TLS_TLSA *head;
    352     int     count;
    353     int     ret;
    354 
    355     if (data == 0)
    356 	data = vstring_alloc(64);
    357 
    358     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
    359 		  RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
    360 		  ATTR_TYPE_END);
    361     if (ret == 1 && msg_verbose)
    362 	msg_info("tls_proxy_client_tlsa_scan count=%d", count);
    363 
    364     for (head = 0; ret == 1 && count > 0; --count) {
    365 	int     u, s, m;
    366 
    367 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
    368 		      RECV_ATTR_INT(TLS_ATTR_USAGE, &u),
    369 		      RECV_ATTR_INT(TLS_ATTR_SELECTOR, &s),
    370 		      RECV_ATTR_INT(TLS_ATTR_MTYPE, &m),
    371 		      RECV_ATTR_DATA(TLS_ATTR_DATA, data),
    372 		      ATTR_TYPE_END);
    373 	if (ret == 4) {
    374 	    ret = 1;
    375 	    /* This makes a copy of the static vstring content */
    376 	    head = tlsa_prepend(head, u, s, m, (unsigned char *) STR(data),
    377 				LEN(data));
    378 	} else
    379 	    ret = -1;
    380     }
    381 
    382     if (ret != 1) {
    383 	tls_tlsa_free(head);
    384 	head = 0;
    385     }
    386     *(TLS_TLSA **) ptr = head;
    387     if (msg_verbose)
    388 	msg_info("tls_proxy_client_tlsa_scan ret=%d", ret);
    389     return (ret);
    390 }
    391 
    392 /* tls_proxy_client_dane_scan - receive TLS_DANE from stream */
    393 
    394 static int tls_proxy_client_dane_scan(ATTR_SCAN_COMMON_FN scan_fn,
    395 				          VSTREAM *fp, int flags, void *ptr)
    396 {
    397     TLS_DANE *dane = 0;
    398     int     ret;
    399     int     have_dane = 0;
    400 
    401     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
    402 		  RECV_ATTR_INT(TLS_ATTR_DANE, &have_dane),
    403 		  ATTR_TYPE_END);
    404     if (msg_verbose)
    405 	msg_info("tls_proxy_client_dane_scan have_dane=%d", have_dane);
    406 
    407     if (ret == 1 && have_dane) {
    408 	VSTRING *base_domain = vstring_alloc(25);
    409 
    410 	dane = tls_dane_alloc();
    411 	/* We only need the base domain and TLSA RRs */
    412 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
    413 		      RECV_ATTR_STR(TLS_ATTR_DOMAIN, base_domain),
    414 		      RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
    415 				     &dane->tlsa),
    416 		      ATTR_TYPE_END);
    417 
    418 	/* Always construct a well-formed structure. */
    419 	dane->base_domain = vstring_export(base_domain);
    420 	ret = (ret == 2 ? 1 : -1);
    421 	if (ret != 1) {
    422 	    tls_dane_free(dane);
    423 	    dane = 0;
    424 	}
    425     }
    426     *(TLS_DANE **) ptr = dane;
    427     if (msg_verbose)
    428 	msg_info("tls_proxy_client_dane_scan ret=%d", ret);
    429     return (ret);
    430 }
    431 
    432 #define EXPORT_OR_NULL(str, vstr) do { \
    433 	if (LEN(vstr) > 0) { \
    434 	    (str) = vstring_export(vstr); \
    435 	} else { \
    436 	    (str) = 0; \
    437 	    vstring_free(vstr); \
    438 	} \
    439     } while (0)
    440 
    441 #ifdef USE_TLSRPT
    442 
    443 /* tls_proxy_client_tlsrpt_scan - receive TLSRPT_WRAPPER from stream */
    444 
    445 static int tls_proxy_client_tlsrpt_scan(ATTR_SCAN_COMMON_FN scan_fn,
    446 				          VSTREAM *fp, int flags, void *ptr)
    447 {
    448     TLSRPT_WRAPPER *trw = 0;
    449     int     ret;
    450     int     have_tlsrpt = 0;
    451 
    452     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
    453 		  RECV_ATTR_INT(TLS_ATTR_TLSRPT, &have_tlsrpt),
    454 		  ATTR_TYPE_END);
    455     if (msg_verbose)
    456 	msg_info("tls_proxy_client_tlsrpt_scan have_tlsrpt=%d", have_tlsrpt);
    457 
    458     if (ret == 1 && have_tlsrpt) {
    459 	VSTRING *rpt_socket_name = vstring_alloc(100);
    460 	VSTRING *rpt_policy_domain = vstring_alloc(100);
    461 	VSTRING *rpt_policy_string = vstring_alloc(100);
    462 	int     tls_policy_type;
    463 	ARGV   *tls_policy_strings = 0;
    464 	VSTRING *tls_policy_domain = vstring_alloc(100);
    465 	ARGV   *mx_host_patterns = 0;
    466 	VSTRING *snd_mta_addr = vstring_alloc(100);
    467 	VSTRING *rcv_mta_name = vstring_alloc(100);
    468 	VSTRING *rcv_mta_addr = vstring_alloc(100);
    469 	VSTRING *rcv_mta_ehlo = vstring_alloc(100);
    470 	int     skip_reused_hs;
    471 	int     trw_flags;
    472 
    473 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
    474 		      RECV_ATTR_STR(TRW_RPT_SOCKET_NAME, rpt_socket_name),
    475 		    RECV_ATTR_STR(TRW_RPT_POLICY_DOMAIN, rpt_policy_domain),
    476 		    RECV_ATTR_STR(TRW_RPT_POLICY_STRING, rpt_policy_string),
    477 		      RECV_ATTR_INT(TRW_TLS_POLICY_TYPE, &tls_policy_type),
    478 		      RECV_ATTR_FUNC(argv_attr_scan, &tls_policy_strings),
    479 		    RECV_ATTR_STR(TRW_TLS_POLICY_DOMAIN, tls_policy_domain),
    480 		      RECV_ATTR_FUNC(argv_attr_scan, &mx_host_patterns),
    481 		      RECV_ATTR_STR(TRW_SRC_MTA_ADDR, snd_mta_addr),
    482 		      RECV_ATTR_STR(TRW_DST_MTA_NAME, rcv_mta_name),
    483 		      RECV_ATTR_STR(TRW_DST_MTA_ADDR, rcv_mta_addr),
    484 		      RECV_ATTR_STR(TRW_DST_MTA_EHLO, rcv_mta_ehlo),
    485 		      RECV_ATTR_INT(TRW_SKIP_REUSED_HS, &skip_reused_hs),
    486 		      RECV_ATTR_INT(TRW_FLAGS, &trw_flags),
    487 		      ATTR_TYPE_END);
    488 
    489 	/* Always construct a well-formed structure. */
    490 	trw = (TLSRPT_WRAPPER *) mymalloc(sizeof(*trw));
    491 	trw->rpt_socket_name = vstring_export(rpt_socket_name);
    492 	trw->rpt_policy_domain = vstring_export(rpt_policy_domain);
    493 	trw->rpt_policy_string = vstring_export(rpt_policy_string);
    494 	trw->tls_policy_type = tls_policy_type;
    495 	trw->tls_policy_strings = tls_policy_strings;
    496 	EXPORT_OR_NULL(trw->tls_policy_domain, tls_policy_domain);
    497 	trw->mx_host_patterns = mx_host_patterns;
    498 	EXPORT_OR_NULL(trw->snd_mta_addr, snd_mta_addr);
    499 	EXPORT_OR_NULL(trw->rcv_mta_name, rcv_mta_name);
    500 	EXPORT_OR_NULL(trw->rcv_mta_addr, rcv_mta_addr);
    501 	EXPORT_OR_NULL(trw->rcv_mta_ehlo, rcv_mta_ehlo);
    502 	trw->skip_reused_hs = skip_reused_hs;
    503 	trw->flags = trw_flags;
    504 	ret = (ret == 13 ? 1 : -1);
    505 	if (ret != 1) {
    506 	    trw_free(trw);
    507 	    trw = 0;
    508 	}
    509     }
    510     *(TLSRPT_WRAPPER **) ptr = trw;
    511     if (msg_verbose)
    512 	msg_info("tls_proxy_client_tlsrpt_scan ret=%d", ret);
    513     return (ret);
    514 }
    515 
    516 #endif
    517 
    518 /* tls_proxy_client_start_scan - receive TLS_CLIENT_START_PROPS from stream */
    519 
    520 int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
    521 				            int flags, void *ptr)
    522 {
    523     TLS_CLIENT_START_PROPS *props
    524     = (TLS_CLIENT_START_PROPS *) mymalloc(sizeof(*props));
    525     int     ret;
    526     VSTRING *nexthop = vstring_alloc(25);
    527     VSTRING *host = vstring_alloc(25);
    528     VSTRING *namaddr = vstring_alloc(25);
    529     VSTRING *sni = vstring_alloc(25);
    530     VSTRING *serverid = vstring_alloc(25);
    531     VSTRING *helo = vstring_alloc(25);
    532     VSTRING *protocols = vstring_alloc(25);
    533     VSTRING *cipher_grade = vstring_alloc(25);
    534     VSTRING *cipher_exclusions = vstring_alloc(25);
    535     VSTRING *mdalg = vstring_alloc(25);
    536     VSTRING *ffail_type = vstring_alloc(25);
    537 
    538 #ifdef USE_TLSRPT
    539 #define EXPECT_START_SCAN_RETURN	17
    540 #else
    541 #define EXPECT_START_SCAN_RETURN	16
    542 #endif
    543 
    544     if (msg_verbose)
    545 	msg_info("begin tls_proxy_client_start_scan");
    546 
    547     /*
    548      * Note: memset() is not a portable way to initialize non-integer types.
    549      */
    550     memset(props, 0, sizeof(*props));
    551     props->ctx = 0;
    552     props->stream = 0;
    553     props->fd = -1;
    554     props->dane = 0;				/* scan_fn may return early */
    555     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
    556 		  RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &props->timeout),
    557 		  RECV_ATTR_INT(TLS_ATTR_ENABLE_RPK, &props->enable_rpk),
    558 		  RECV_ATTR_INT(TLS_ATTR_TLS_LEVEL, &props->tls_level),
    559 		  RECV_ATTR_STR(TLS_ATTR_NEXTHOP, nexthop),
    560 		  RECV_ATTR_STR(TLS_ATTR_HOST, host),
    561 		  RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
    562 		  RECV_ATTR_STR(TLS_ATTR_SNI, sni),
    563 		  RECV_ATTR_STR(TLS_ATTR_SERVERID, serverid),
    564 		  RECV_ATTR_STR(TLS_ATTR_HELO, helo),
    565 		  RECV_ATTR_STR(TLS_ATTR_PROTOCOLS, protocols),
    566 		  RECV_ATTR_STR(TLS_ATTR_CIPHER_GRADE, cipher_grade),
    567 		  RECV_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS,
    568 				cipher_exclusions),
    569 		  RECV_ATTR_FUNC(argv_attr_scan, &props->matchargv),
    570 		  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
    571 		  RECV_ATTR_FUNC(tls_proxy_client_dane_scan,
    572 				 &props->dane),
    573 #ifdef USE_TLSRPT
    574 		  RECV_ATTR_FUNC(tls_proxy_client_tlsrpt_scan,
    575 				 &props->tlsrpt),
    576 #endif
    577 		  RECV_ATTR_STR(TLS_ATTR_FFAIL_TYPE, ffail_type),
    578 		  ATTR_TYPE_END);
    579     /* Always construct a well-formed structure. */
    580     props->nexthop = vstring_export(nexthop);
    581     props->host = vstring_export(host);
    582     props->namaddr = vstring_export(namaddr);
    583     props->sni = vstring_export(sni);
    584     props->serverid = vstring_export(serverid);
    585     props->helo = vstring_export(helo);
    586     props->protocols = vstring_export(protocols);
    587     props->cipher_grade = vstring_export(cipher_grade);
    588     props->cipher_exclusions = vstring_export(cipher_exclusions);
    589     props->mdalg = vstring_export(mdalg);
    590     EXPORT_OR_NULL(props->ffail_type, ffail_type);
    591     ret = (ret == EXPECT_START_SCAN_RETURN ? 1 : -1);
    592     if (ret != 1) {
    593 	tls_proxy_client_start_free(props);
    594 	props = 0;
    595     }
    596     *(TLS_CLIENT_START_PROPS **) ptr = props;
    597     if (msg_verbose)
    598 	msg_info("tls_proxy_client_start_scan ret=%d", ret);
    599     return (ret);
    600 }
    601 
    602 #endif
    603