xref: /netbsd-src/external/ibm-public/postfix/dist/src/tls/tls_proxy_client_scan.c (revision c48c605c14fd8622b523d1d6a3f0c0bad133ea89)
1 /*	$NetBSD: tls_proxy_client_scan.c,v 1.4 2023/12/23 20:30:45 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 
119 #define STR(x) vstring_str(x)
120 #define LEN(x) VSTRING_LEN(x)
121 
122 /* tls_proxy_client_param_free - destroy TLS_CLIENT_PARAMS structure */
123 
tls_proxy_client_param_free(TLS_CLIENT_PARAMS * params)124 void    tls_proxy_client_param_free(TLS_CLIENT_PARAMS *params)
125 {
126     myfree(params->tls_cnf_file);
127     myfree(params->tls_cnf_name);
128     myfree(params->tls_high_clist);
129     myfree(params->tls_medium_clist);
130     myfree(params->tls_null_clist);
131     myfree(params->tls_eecdh_auto);
132     myfree(params->tls_eecdh_strong);
133     myfree(params->tls_eecdh_ultra);
134     myfree(params->tls_ffdhe_auto);
135     myfree(params->tls_bug_tweaks);
136     myfree(params->tls_ssl_options);
137     myfree(params->tls_dane_digests);
138     myfree(params->tls_mgr_service);
139     myfree(params->tls_tkt_cipher);
140     myfree((void *) params);
141 }
142 
143 /* tls_proxy_client_param_scan - receive TLS_CLIENT_PARAMS from stream */
144 
tls_proxy_client_param_scan(ATTR_SCAN_COMMON_FN scan_fn,VSTREAM * fp,int flags,void * ptr)145 int     tls_proxy_client_param_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
146 				            int flags, void *ptr)
147 {
148     TLS_CLIENT_PARAMS *params
149     = (TLS_CLIENT_PARAMS *) mymalloc(sizeof(*params));
150     int     ret;
151     VSTRING *cnf_file = vstring_alloc(25);
152     VSTRING *cnf_name = vstring_alloc(25);
153     VSTRING *tls_high_clist = vstring_alloc(25);
154     VSTRING *tls_medium_clist = vstring_alloc(25);
155     VSTRING *tls_null_clist = vstring_alloc(25);
156     VSTRING *tls_eecdh_auto = vstring_alloc(25);
157     VSTRING *tls_eecdh_strong = vstring_alloc(25);
158     VSTRING *tls_eecdh_ultra = vstring_alloc(25);
159     VSTRING *tls_ffdhe_auto = vstring_alloc(25);
160     VSTRING *tls_bug_tweaks = vstring_alloc(25);
161     VSTRING *tls_ssl_options = vstring_alloc(25);
162     VSTRING *tls_dane_digests = vstring_alloc(25);
163     VSTRING *tls_mgr_service = vstring_alloc(25);
164     VSTRING *tls_tkt_cipher = vstring_alloc(25);
165 
166     if (msg_verbose)
167 	msg_info("begin tls_proxy_client_param_scan");
168 
169     /*
170      * Note: memset() is not a portable way to initialize non-integer types.
171      */
172     memset(params, 0, sizeof(*params));
173     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
174 		  RECV_ATTR_STR(TLS_ATTR_CNF_FILE, cnf_file),
175 		  RECV_ATTR_STR(TLS_ATTR_CNF_NAME, cnf_name),
176 		  RECV_ATTR_STR(VAR_TLS_HIGH_CLIST, tls_high_clist),
177 		  RECV_ATTR_STR(VAR_TLS_MEDIUM_CLIST, tls_medium_clist),
178 		  RECV_ATTR_STR(VAR_TLS_NULL_CLIST, tls_null_clist),
179 		  RECV_ATTR_STR(VAR_TLS_EECDH_AUTO, tls_eecdh_auto),
180 		  RECV_ATTR_STR(VAR_TLS_EECDH_STRONG, tls_eecdh_strong),
181 		  RECV_ATTR_STR(VAR_TLS_EECDH_ULTRA, tls_eecdh_ultra),
182 		  RECV_ATTR_STR(VAR_TLS_FFDHE_AUTO, tls_ffdhe_auto),
183 		  RECV_ATTR_STR(VAR_TLS_BUG_TWEAKS, tls_bug_tweaks),
184 		  RECV_ATTR_STR(VAR_TLS_SSL_OPTIONS, tls_ssl_options),
185 		  RECV_ATTR_STR(VAR_TLS_DANE_DIGESTS, tls_dane_digests),
186 		  RECV_ATTR_STR(VAR_TLS_MGR_SERVICE, tls_mgr_service),
187 		  RECV_ATTR_STR(VAR_TLS_TKT_CIPHER, tls_tkt_cipher),
188 		  RECV_ATTR_INT(VAR_TLS_DAEMON_RAND_BYTES,
189 				&params->tls_daemon_rand_bytes),
190 		  RECV_ATTR_INT(VAR_TLS_APPEND_DEF_CA,
191 				&params->tls_append_def_CA),
192 		  RECV_ATTR_INT(VAR_TLS_BC_PKEY_FPRINT,
193 				&params->tls_bc_pkey_fprint),
194 		  RECV_ATTR_INT(VAR_TLS_PREEMPT_CLIST,
195 				&params->tls_preempt_clist),
196 		  RECV_ATTR_INT(VAR_TLS_MULTI_WILDCARD,
197 				&params->tls_multi_wildcard),
198 		  ATTR_TYPE_END);
199     /* Always construct a well-formed structure. */
200     params->tls_cnf_file = vstring_export(cnf_file);
201     params->tls_cnf_name = vstring_export(cnf_name);
202     params->tls_high_clist = vstring_export(tls_high_clist);
203     params->tls_medium_clist = vstring_export(tls_medium_clist);
204     params->tls_null_clist = vstring_export(tls_null_clist);
205     params->tls_eecdh_auto = vstring_export(tls_eecdh_auto);
206     params->tls_eecdh_strong = vstring_export(tls_eecdh_strong);
207     params->tls_eecdh_ultra = vstring_export(tls_eecdh_ultra);
208     params->tls_ffdhe_auto = vstring_export(tls_ffdhe_auto);
209     params->tls_bug_tweaks = vstring_export(tls_bug_tweaks);
210     params->tls_ssl_options = vstring_export(tls_ssl_options);
211     params->tls_dane_digests = vstring_export(tls_dane_digests);
212     params->tls_mgr_service = vstring_export(tls_mgr_service);
213     params->tls_tkt_cipher = vstring_export(tls_tkt_cipher);
214 
215     ret = (ret == 19 ? 1 : -1);
216     if (ret != 1) {
217 	tls_proxy_client_param_free(params);
218 	params = 0;
219     }
220     *(TLS_CLIENT_PARAMS **) ptr = params;
221     if (msg_verbose)
222 	msg_info("tls_proxy_client_param_scan ret=%d", ret);
223     return (ret);
224 }
225 
226 /* tls_proxy_client_init_free - destroy TLS_CLIENT_INIT_PROPS structure */
227 
tls_proxy_client_init_free(TLS_CLIENT_INIT_PROPS * props)228 void    tls_proxy_client_init_free(TLS_CLIENT_INIT_PROPS *props)
229 {
230     myfree((void *) props->log_param);
231     myfree((void *) props->log_level);
232     myfree((void *) props->cache_type);
233     myfree((void *) props->chain_files);
234     myfree((void *) props->cert_file);
235     myfree((void *) props->key_file);
236     myfree((void *) props->dcert_file);
237     myfree((void *) props->dkey_file);
238     myfree((void *) props->eccert_file);
239     myfree((void *) props->eckey_file);
240     myfree((void *) props->CAfile);
241     myfree((void *) props->CApath);
242     myfree((void *) props->mdalg);
243     myfree((void *) props);
244 }
245 
246 /* tls_proxy_client_init_scan - receive TLS_CLIENT_INIT_PROPS from stream */
247 
tls_proxy_client_init_scan(ATTR_SCAN_COMMON_FN scan_fn,VSTREAM * fp,int flags,void * ptr)248 int     tls_proxy_client_init_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
249 				           int flags, void *ptr)
250 {
251     TLS_CLIENT_INIT_PROPS *props
252     = (TLS_CLIENT_INIT_PROPS *) mymalloc(sizeof(*props));
253     int     ret;
254     VSTRING *log_param = vstring_alloc(25);
255     VSTRING *log_level = vstring_alloc(25);
256     VSTRING *cache_type = vstring_alloc(25);
257     VSTRING *chain_files = vstring_alloc(25);
258     VSTRING *cert_file = vstring_alloc(25);
259     VSTRING *key_file = vstring_alloc(25);
260     VSTRING *dcert_file = vstring_alloc(25);
261     VSTRING *dkey_file = vstring_alloc(25);
262     VSTRING *eccert_file = vstring_alloc(25);
263     VSTRING *eckey_file = vstring_alloc(25);
264     VSTRING *CAfile = vstring_alloc(25);
265     VSTRING *CApath = vstring_alloc(25);
266     VSTRING *mdalg = vstring_alloc(25);
267 
268     if (msg_verbose)
269 	msg_info("begin tls_proxy_client_init_scan");
270 
271     /*
272      * Note: memset() is not a portable way to initialize non-integer types.
273      */
274     memset(props, 0, sizeof(*props));
275     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
276 		  RECV_ATTR_STR(TLS_ATTR_LOG_PARAM, log_param),
277 		  RECV_ATTR_STR(TLS_ATTR_LOG_LEVEL, log_level),
278 		  RECV_ATTR_INT(TLS_ATTR_VERIFYDEPTH, &props->verifydepth),
279 		  RECV_ATTR_STR(TLS_ATTR_CACHE_TYPE, cache_type),
280 		  RECV_ATTR_STR(TLS_ATTR_CHAIN_FILES, chain_files),
281 		  RECV_ATTR_STR(TLS_ATTR_CERT_FILE, cert_file),
282 		  RECV_ATTR_STR(TLS_ATTR_KEY_FILE, key_file),
283 		  RECV_ATTR_STR(TLS_ATTR_DCERT_FILE, dcert_file),
284 		  RECV_ATTR_STR(TLS_ATTR_DKEY_FILE, dkey_file),
285 		  RECV_ATTR_STR(TLS_ATTR_ECCERT_FILE, eccert_file),
286 		  RECV_ATTR_STR(TLS_ATTR_ECKEY_FILE, eckey_file),
287 		  RECV_ATTR_STR(TLS_ATTR_CAFILE, CAfile),
288 		  RECV_ATTR_STR(TLS_ATTR_CAPATH, CApath),
289 		  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
290 		  ATTR_TYPE_END);
291     /* Always construct a well-formed structure. */
292     props->log_param = vstring_export(log_param);
293     props->log_level = vstring_export(log_level);
294     props->cache_type = vstring_export(cache_type);
295     props->chain_files = vstring_export(chain_files);
296     props->cert_file = vstring_export(cert_file);
297     props->key_file = vstring_export(key_file);
298     props->dcert_file = vstring_export(dcert_file);
299     props->dkey_file = vstring_export(dkey_file);
300     props->eccert_file = vstring_export(eccert_file);
301     props->eckey_file = vstring_export(eckey_file);
302     props->CAfile = vstring_export(CAfile);
303     props->CApath = vstring_export(CApath);
304     props->mdalg = vstring_export(mdalg);
305     ret = (ret == 14 ? 1 : -1);
306     if (ret != 1) {
307 	tls_proxy_client_init_free(props);
308 	props = 0;
309     }
310     *(TLS_CLIENT_INIT_PROPS **) ptr = props;
311     if (msg_verbose)
312 	msg_info("tls_proxy_client_init_scan ret=%d", ret);
313     return (ret);
314 }
315 
316 /* tls_proxy_client_start_free - destroy TLS_CLIENT_START_PROPS structure */
317 
tls_proxy_client_start_free(TLS_CLIENT_START_PROPS * props)318 void    tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
319 {
320     myfree((void *) props->nexthop);
321     myfree((void *) props->host);
322     myfree((void *) props->namaddr);
323     myfree((void *) props->sni);
324     myfree((void *) props->serverid);
325     myfree((void *) props->helo);
326     myfree((void *) props->protocols);
327     myfree((void *) props->cipher_grade);
328     myfree((void *) props->cipher_exclusions);
329     if (props->matchargv)
330 	argv_free((ARGV *) props->matchargv);
331     myfree((void *) props->mdalg);
332     if (props->dane)
333 	tls_dane_free((TLS_DANE *) props->dane);
334     myfree((void *) props);
335 }
336 
337 /* tls_proxy_client_tlsa_scan - receive TLS_TLSA from stream */
338 
tls_proxy_client_tlsa_scan(ATTR_SCAN_COMMON_FN scan_fn,VSTREAM * fp,int flags,void * ptr)339 static int tls_proxy_client_tlsa_scan(ATTR_SCAN_COMMON_FN scan_fn,
340 				          VSTREAM *fp, int flags, void *ptr)
341 {
342     static VSTRING *data;
343     TLS_TLSA *head;
344     int     count;
345     int     ret;
346 
347     if (data == 0)
348 	data = vstring_alloc(64);
349 
350     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
351 		  RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
352 		  ATTR_TYPE_END);
353     if (ret == 1 && msg_verbose)
354 	msg_info("tls_proxy_client_tlsa_scan count=%d", count);
355 
356     for (head = 0; ret == 1 && count > 0; --count) {
357 	int     u, s, m;
358 
359 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
360 		      RECV_ATTR_INT(TLS_ATTR_USAGE, &u),
361 		      RECV_ATTR_INT(TLS_ATTR_SELECTOR, &s),
362 		      RECV_ATTR_INT(TLS_ATTR_MTYPE, &m),
363 		      RECV_ATTR_DATA(TLS_ATTR_DATA, data),
364 		      ATTR_TYPE_END);
365 	if (ret == 4) {
366 	    ret = 1;
367 	    /* This makes a copy of the static vstring content */
368 	    head = tlsa_prepend(head, u, s, m, (unsigned char *) STR(data),
369 				LEN(data));
370 	} else
371 	    ret = -1;
372     }
373 
374     if (ret != 1) {
375 	tls_tlsa_free(head);
376 	head = 0;
377     }
378     *(TLS_TLSA **) ptr = head;
379     if (msg_verbose)
380 	msg_info("tls_proxy_client_tlsa_scan ret=%d", ret);
381     return (ret);
382 }
383 
384 /* tls_proxy_client_dane_scan - receive TLS_DANE from stream */
385 
tls_proxy_client_dane_scan(ATTR_SCAN_COMMON_FN scan_fn,VSTREAM * fp,int flags,void * ptr)386 static int tls_proxy_client_dane_scan(ATTR_SCAN_COMMON_FN scan_fn,
387 				          VSTREAM *fp, int flags, void *ptr)
388 {
389     TLS_DANE *dane = 0;
390     int     ret;
391     int     have_dane = 0;
392 
393     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
394 		  RECV_ATTR_INT(TLS_ATTR_DANE, &have_dane),
395 		  ATTR_TYPE_END);
396     if (msg_verbose)
397 	msg_info("tls_proxy_client_dane_scan have_dane=%d", have_dane);
398 
399     if (ret == 1 && have_dane) {
400 	VSTRING *base_domain = vstring_alloc(25);
401 
402 	dane = tls_dane_alloc();
403 	/* We only need the base domain and TLSA RRs */
404 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
405 		      RECV_ATTR_STR(TLS_ATTR_DOMAIN, base_domain),
406 		      RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
407 				     &dane->tlsa),
408 		      ATTR_TYPE_END);
409 
410 	/* Always construct a well-formed structure. */
411 	dane->base_domain = vstring_export(base_domain);
412 	ret = (ret == 2 ? 1 : -1);
413 	if (ret != 1) {
414 	    tls_dane_free(dane);
415 	    dane = 0;
416 	}
417     }
418     *(TLS_DANE **) ptr = dane;
419     if (msg_verbose)
420 	msg_info("tls_proxy_client_dane_scan ret=%d", ret);
421     return (ret);
422 }
423 
424 /* tls_proxy_client_start_scan - receive TLS_CLIENT_START_PROPS from stream */
425 
tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn,VSTREAM * fp,int flags,void * ptr)426 int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
427 				            int flags, void *ptr)
428 {
429     TLS_CLIENT_START_PROPS *props
430     = (TLS_CLIENT_START_PROPS *) mymalloc(sizeof(*props));
431     int     ret;
432     VSTRING *nexthop = vstring_alloc(25);
433     VSTRING *host = vstring_alloc(25);
434     VSTRING *namaddr = vstring_alloc(25);
435     VSTRING *sni = vstring_alloc(25);
436     VSTRING *serverid = vstring_alloc(25);
437     VSTRING *helo = vstring_alloc(25);
438     VSTRING *protocols = vstring_alloc(25);
439     VSTRING *cipher_grade = vstring_alloc(25);
440     VSTRING *cipher_exclusions = vstring_alloc(25);
441     VSTRING *mdalg = vstring_alloc(25);
442 
443     if (msg_verbose)
444 	msg_info("begin tls_proxy_client_start_scan");
445 
446     /*
447      * Note: memset() is not a portable way to initialize non-integer types.
448      */
449     memset(props, 0, sizeof(*props));
450     props->ctx = 0;
451     props->stream = 0;
452     props->fd = -1;
453     props->dane = 0;				/* scan_fn may return early */
454     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
455 		  RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &props->timeout),
456 		  RECV_ATTR_INT(TLS_ATTR_TLS_LEVEL, &props->tls_level),
457 		  RECV_ATTR_STR(TLS_ATTR_NEXTHOP, nexthop),
458 		  RECV_ATTR_STR(TLS_ATTR_HOST, host),
459 		  RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
460 		  RECV_ATTR_STR(TLS_ATTR_SNI, sni),
461 		  RECV_ATTR_STR(TLS_ATTR_SERVERID, serverid),
462 		  RECV_ATTR_STR(TLS_ATTR_HELO, helo),
463 		  RECV_ATTR_STR(TLS_ATTR_PROTOCOLS, protocols),
464 		  RECV_ATTR_STR(TLS_ATTR_CIPHER_GRADE, cipher_grade),
465 		  RECV_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS,
466 				cipher_exclusions),
467 		  RECV_ATTR_FUNC(argv_attr_scan, &props->matchargv),
468 		  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
469 		  RECV_ATTR_FUNC(tls_proxy_client_dane_scan,
470 				 &props->dane),
471 		  ATTR_TYPE_END);
472     /* Always construct a well-formed structure. */
473     props->nexthop = vstring_export(nexthop);
474     props->host = vstring_export(host);
475     props->namaddr = vstring_export(namaddr);
476     props->sni = vstring_export(sni);
477     props->serverid = vstring_export(serverid);
478     props->helo = vstring_export(helo);
479     props->protocols = vstring_export(protocols);
480     props->cipher_grade = vstring_export(cipher_grade);
481     props->cipher_exclusions = vstring_export(cipher_exclusions);
482     props->mdalg = vstring_export(mdalg);
483     ret = (ret == 14 ? 1 : -1);
484     if (ret != 1) {
485 	tls_proxy_client_start_free(props);
486 	props = 0;
487     }
488     *(TLS_CLIENT_START_PROPS **) ptr = props;
489     if (msg_verbose)
490 	msg_info("tls_proxy_client_start_scan ret=%d", ret);
491     return (ret);
492 }
493 
494 #endif
495