/src/libwebsockets/lib/secure-streams/policy-common.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * libwebsockets - small server side websockets and web server implementation |
3 | | * |
4 | | * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com> |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | | * of this software and associated documentation files (the "Software"), to |
8 | | * deal in the Software without restriction, including without limitation the |
9 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
10 | | * sell copies of the Software, and to permit persons to whom the Software is |
11 | | * furnished to do so, subject to the following conditions: |
12 | | * |
13 | | * The above copyright notice and this permission notice shall be included in |
14 | | * all copies or substantial portions of the Software. |
15 | | * |
16 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
21 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
22 | | * IN THE SOFTWARE. |
23 | | * |
24 | | * This file contains the stuff related to secure streams policy, it's always |
25 | | * built if LWS_WITH_SECURE_STREAMS enabled. |
26 | | */ |
27 | | |
28 | | #include <private-lib-core.h> |
29 | | |
30 | | #if defined(LWS_WITH_SYS_SMD) |
31 | | const lws_ss_policy_t pol_smd = { |
32 | | .flags = 0, /* have to set something for windows */ |
33 | | }; |
34 | | #endif |
35 | | |
36 | | const lws_ss_policy_t * |
37 | | lws_ss_policy_lookup(const struct lws_context *context, const char *streamtype) |
38 | 0 | { |
39 | 0 | const lws_ss_policy_t *p = context->pss_policies; |
40 | |
|
41 | 0 | if (!streamtype) |
42 | 0 | return NULL; |
43 | | |
44 | 0 | #if defined(LWS_WITH_SYS_SMD) |
45 | 0 | if (!strcmp(streamtype, LWS_SMD_STREAMTYPENAME)) |
46 | 0 | return &pol_smd; |
47 | 0 | #endif |
48 | | |
49 | 0 | while (p) { |
50 | 0 | if (!strcmp(p->streamtype, streamtype)) |
51 | 0 | return p; |
52 | 0 | p = p->next; |
53 | 0 | } |
54 | | |
55 | 0 | return NULL; |
56 | 0 | } |
57 | | |
58 | | int |
59 | | _lws_ss_set_metadata(lws_ss_metadata_t *omd, const char *name, |
60 | | const void *value, size_t len) |
61 | 0 | { |
62 | | /* |
63 | | * If there was already a heap-based value, it's about to go out of |
64 | | * scope due to us trashing the pointer. So free it first and clear |
65 | | * its flag indicating it's heap-based. |
66 | | */ |
67 | |
|
68 | 0 | if (omd->value_on_lws_heap) { |
69 | 0 | lws_free_set_NULL(omd->value__may_own_heap); |
70 | 0 | omd->value_on_lws_heap = 0; |
71 | 0 | } |
72 | | |
73 | | // lwsl_notice("%s: %s %s\n", __func__, name, (const char *)value); |
74 | |
|
75 | 0 | omd->name = name; |
76 | 0 | omd->value__may_own_heap = (void *)value; |
77 | 0 | omd->length = len; |
78 | |
|
79 | 0 | return 0; |
80 | 0 | } |
81 | | |
82 | | int |
83 | | lws_ss_set_metadata(struct lws_ss_handle *h, const char *name, |
84 | | const void *value, size_t len) |
85 | 0 | { |
86 | 0 | lws_ss_metadata_t *omd = lws_ss_get_handle_metadata(h, name); |
87 | |
|
88 | 0 | lws_service_assert_loop_thread(h->context, h->tsi); |
89 | |
|
90 | 0 | if (omd) |
91 | 0 | return _lws_ss_set_metadata(omd, name, value, len); |
92 | | |
93 | | #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR) |
94 | | if (h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR) { |
95 | | omd = lws_ss_get_handle_instant_metadata(h, name); |
96 | | if (!omd) { |
97 | | omd = lws_zalloc(sizeof(*omd), "imetadata"); |
98 | | if (!omd) { |
99 | | lwsl_err("%s OOM\n", __func__); |
100 | | return 1; |
101 | | } |
102 | | omd->name = name; |
103 | | omd->next = h->instant_metadata; |
104 | | h->instant_metadata = omd; |
105 | | } |
106 | | omd->value__may_own_heap = (void *)value; |
107 | | omd->length = len; |
108 | | |
109 | | return 0; |
110 | | } |
111 | | #endif |
112 | | |
113 | 0 | lwsl_info("%s: unknown metadata %s\n", __func__, name); |
114 | 0 | return 1; |
115 | 0 | } |
116 | | |
117 | | int |
118 | | _lws_ss_alloc_set_metadata(lws_ss_metadata_t *omd, const char *name, |
119 | | const void *value, size_t len) |
120 | 0 | { |
121 | 0 | uint8_t *p; |
122 | 0 | int n; |
123 | |
|
124 | 0 | if (omd->value_on_lws_heap) { |
125 | 0 | lws_free_set_NULL(omd->value__may_own_heap); |
126 | 0 | omd->value_on_lws_heap = 0; |
127 | 0 | } |
128 | |
|
129 | 0 | p = lws_malloc(len, __func__); |
130 | 0 | if (!p) |
131 | 0 | return 1; |
132 | | |
133 | 0 | n = _lws_ss_set_metadata(omd, name, p, len); |
134 | 0 | if (n) { |
135 | 0 | lws_free(p); |
136 | 0 | return n; |
137 | 0 | } |
138 | | |
139 | 0 | memcpy(p, value, len); |
140 | |
|
141 | 0 | omd->value_on_lws_heap = 1; |
142 | |
|
143 | 0 | return 0; |
144 | 0 | } |
145 | | |
146 | | int |
147 | | lws_ss_alloc_set_metadata(struct lws_ss_handle *h, const char *name, |
148 | | const void *value, size_t len) |
149 | 0 | { |
150 | 0 | lws_ss_metadata_t *omd = lws_ss_get_handle_metadata(h, name); |
151 | |
|
152 | 0 | lws_service_assert_loop_thread(h->context, h->tsi); |
153 | |
|
154 | 0 | if (!omd) { |
155 | 0 | lwsl_info("%s: unknown metadata %s\n", __func__, name); |
156 | 0 | return 1; |
157 | 0 | } |
158 | | |
159 | 0 | return _lws_ss_alloc_set_metadata(omd, name, value, len); |
160 | 0 | } |
161 | | |
162 | | int |
163 | | lws_ss_get_metadata(struct lws_ss_handle *h, const char *name, |
164 | | const void **value, size_t *len) |
165 | 0 | { |
166 | 0 | lws_ss_metadata_t *omd = lws_ss_get_handle_metadata(h, name); |
167 | | #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR) |
168 | | int n; |
169 | | #endif |
170 | |
|
171 | 0 | lws_service_assert_loop_thread(h->context, h->tsi); |
172 | |
|
173 | 0 | if (omd) { |
174 | 0 | *value = omd->value__may_own_heap; |
175 | 0 | *len = omd->length; |
176 | |
|
177 | 0 | return 0; |
178 | 0 | } |
179 | | #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR) |
180 | | if (!(h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR) || !h->wsi) |
181 | | goto bail; |
182 | | |
183 | | n = lws_http_string_to_known_header(name, strlen(name)); |
184 | | if (n != LWS_HTTP_NO_KNOWN_HEADER) { |
185 | | *len = (size_t)lws_hdr_total_length(h->wsi, n); |
186 | | if (!*len) |
187 | | goto bail; |
188 | | *value = lws_hdr_simple_ptr(h->wsi, n); |
189 | | if (!*value) |
190 | | goto bail; |
191 | | |
192 | | return 0; |
193 | | } |
194 | | #if defined(LWS_WITH_CUSTOM_HEADERS) |
195 | | n = lws_hdr_custom_length(h->wsi, (const char *)name, |
196 | | (int)strlen(name)); |
197 | | if (n <= 0) |
198 | | goto bail; |
199 | | *value = lwsac_use(&h->imd_ac, (size_t)(n+1), (size_t)(n+1)); |
200 | | if (!*value) { |
201 | | lwsl_err("%s ac OOM\n", __func__); |
202 | | return 1; |
203 | | } |
204 | | if (lws_hdr_custom_copy(h->wsi, (char *)(*value), n+1, name, |
205 | | (int)strlen(name))) { |
206 | | /* waste n+1 bytes until ss is destryed */ |
207 | | goto bail; |
208 | | } |
209 | | *len = (size_t)n; |
210 | | |
211 | | return 0; |
212 | | #endif |
213 | | |
214 | | bail: |
215 | | #endif |
216 | 0 | lwsl_info("%s: unknown metadata %s\n", __func__, name); |
217 | |
|
218 | 0 | return 1; |
219 | 0 | } |
220 | | |
221 | | lws_ss_metadata_t * |
222 | | lws_ss_get_handle_metadata(struct lws_ss_handle *h, const char *name) |
223 | 0 | { |
224 | 0 | int n; |
225 | |
|
226 | 0 | lws_service_assert_loop_thread(h->context, h->tsi); |
227 | |
|
228 | 0 | for (n = 0; n < h->policy->metadata_count; n++) |
229 | 0 | if (!strcmp(name, h->metadata[n].name)) |
230 | 0 | return &h->metadata[n]; |
231 | | |
232 | 0 | return NULL; |
233 | 0 | } |
234 | | |
235 | | #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR) |
236 | | lws_ss_metadata_t * |
237 | | lws_ss_get_handle_instant_metadata(struct lws_ss_handle *h, const char *name) |
238 | | { |
239 | | lws_ss_metadata_t *imd = h->instant_metadata; |
240 | | |
241 | | while (imd) { |
242 | | if (!strcmp(name, imd->name)) |
243 | | return imd; |
244 | | imd = imd->next; |
245 | | } |
246 | | |
247 | | return NULL; |
248 | | } |
249 | | |
250 | | #endif |
251 | | |
252 | | |
253 | | lws_ss_metadata_t * |
254 | | lws_ss_policy_metadata(const lws_ss_policy_t *p, const char *name) |
255 | 0 | { |
256 | 0 | lws_ss_metadata_t *pmd = p->metadata; |
257 | |
|
258 | 0 | while (pmd) { |
259 | 0 | if (pmd->name && !strcmp(name, pmd->name)) |
260 | 0 | return pmd; |
261 | 0 | pmd = pmd->next; |
262 | 0 | } |
263 | | |
264 | 0 | return NULL; |
265 | 0 | } |
266 | | |
267 | | lws_ss_metadata_t * |
268 | | lws_ss_policy_metadata_index(const lws_ss_policy_t *p, size_t index) |
269 | 0 | { |
270 | 0 | lws_ss_metadata_t *pmd = p->metadata; |
271 | |
|
272 | 0 | while (pmd) { |
273 | 0 | if (pmd->length == index) |
274 | 0 | return pmd; |
275 | 0 | pmd = pmd->next; |
276 | 0 | } |
277 | | |
278 | 0 | return NULL; |
279 | 0 | } |
280 | | |
281 | | #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) |
282 | | static int |
283 | | fe_lws_ss_destroy(struct lws_dll2 *d, void *user) |
284 | 0 | { |
285 | 0 | lws_ss_handle_t *h = lws_container_of(d, lws_ss_handle_t, list); |
286 | |
|
287 | 0 | lws_ss_destroy(&h); |
288 | |
|
289 | 0 | return 0; |
290 | 0 | } |
291 | | #endif |
292 | | |
293 | | /* |
294 | | * Dynamic policy: we want to one-time create the vhost for the policy and the |
295 | | * trust store behind it. |
296 | | * |
297 | | * Static policy: We want to make use of a trust store / vhost from the policy and add to its |
298 | | * ss-refcount. |
299 | | */ |
300 | | |
301 | | struct lws_vhost * |
302 | | lws_ss_policy_ref_trust_store(struct lws_context *context, |
303 | | const lws_ss_policy_t *pol, char doref) |
304 | 0 | { |
305 | 0 | struct lws_context_creation_info i; |
306 | 0 | struct lws_vhost *v; |
307 | 0 | int n; |
308 | |
|
309 | 0 | memset(&i, 0, sizeof(i)); |
310 | |
|
311 | 0 | if (!pol->trust.store) { |
312 | 0 | v = lws_get_vhost_by_name(context, "_ss_default"); |
313 | 0 | if (!v) { |
314 | | /* corner case... there's no trust store used */ |
315 | 0 | i.options = context->options; |
316 | 0 | i.vhost_name = "_ss_default"; |
317 | 0 | i.port = CONTEXT_PORT_NO_LISTEN; |
318 | 0 | v = lws_create_vhost(context, &i); |
319 | 0 | if (!v) { |
320 | 0 | lwsl_err("%s: failed to create vhost %s\n", |
321 | 0 | __func__, i.vhost_name); |
322 | |
|
323 | 0 | return NULL; |
324 | 0 | } |
325 | 0 | } |
326 | | |
327 | 0 | goto accepted; |
328 | 0 | } |
329 | 0 | v = lws_get_vhost_by_name(context, pol->trust.store->name); |
330 | 0 | if (v) { |
331 | 0 | lwsl_debug("%s: vh already exists\n", __func__); |
332 | 0 | goto accepted; |
333 | 0 | } |
334 | | |
335 | 0 | i.options = context->options; |
336 | 0 | i.vhost_name = pol->trust.store->name; |
337 | 0 | lwsl_debug("%s: %s\n", __func__, i.vhost_name); |
338 | 0 | #if defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT) |
339 | 0 | i.client_ssl_ca_mem = pol->trust.store->ssx509[0]->ca_der; |
340 | 0 | i.client_ssl_ca_mem_len = (unsigned int) |
341 | 0 | pol->trust.store->ssx509[0]->ca_der_len; |
342 | 0 | #endif |
343 | | #if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS) |
344 | | lwsl_err("%s: ctx ext %p\n", __func__, context->extensions); |
345 | | i.extensions = context->extensions; |
346 | | #endif |
347 | 0 | i.port = CONTEXT_PORT_NO_LISTEN; |
348 | 0 | lwsl_info("%s: %s trust store initial '%s'\n", __func__, |
349 | 0 | i.vhost_name, pol->trust.store->ssx509[0]->vhost_name); |
350 | |
|
351 | 0 | v = lws_create_vhost(context, &i); |
352 | 0 | if (!v) { |
353 | 0 | lwsl_err("%s: failed to create vhost %s\n", |
354 | 0 | __func__, i.vhost_name); |
355 | 0 | return NULL; |
356 | 0 | } else |
357 | 0 | v->from_ss_policy = 1; |
358 | | |
359 | 0 | for (n = 1; v && n < pol->trust.store->count; n++) { |
360 | 0 | lwsl_info("%s: add '%s' to trust store\n", __func__, |
361 | 0 | pol->trust.store->ssx509[n]->vhost_name); |
362 | 0 | #if defined(LWS_WITH_TLS) |
363 | 0 | if (lws_tls_client_vhost_extra_cert_mem(v, |
364 | 0 | pol->trust.store->ssx509[n]->ca_der, |
365 | 0 | pol->trust.store->ssx509[n]->ca_der_len)) { |
366 | 0 | lwsl_err("%s: add extra cert failed\n", |
367 | 0 | __func__); |
368 | 0 | return NULL; |
369 | 0 | } |
370 | 0 | #endif |
371 | 0 | } |
372 | | |
373 | 0 | accepted: |
374 | | #if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) || defined(LWS_WITH_SECURE_STREAMS_CPP) |
375 | | if (doref) |
376 | | v->ss_refcount++; |
377 | | #endif |
378 | |
|
379 | 0 | return v; |
380 | 0 | } |
381 | | |
382 | | #if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) || defined(LWS_WITH_SECURE_STREAMS_CPP) |
383 | | int |
384 | | lws_ss_policy_unref_trust_store(struct lws_context *context, |
385 | | const lws_ss_policy_t *pol) |
386 | | { |
387 | | struct lws_vhost *v; |
388 | | const char *name = "_ss_default"; |
389 | | |
390 | | if (pol->trust.store) |
391 | | name = pol->trust.store->name; |
392 | | |
393 | | v = lws_get_vhost_by_name(context, name); |
394 | | if (!v || !v->from_ss_policy) |
395 | | return 0; |
396 | | |
397 | | assert(v->ss_refcount); |
398 | | |
399 | | v->ss_refcount--; |
400 | | if (!v->ss_refcount) { |
401 | | lwsl_notice("%s: destroying vh %s\n", __func__, name); |
402 | | lws_vhost_destroy(v); |
403 | | } |
404 | | |
405 | | return 1; |
406 | | } |
407 | | #endif |
408 | | |
409 | | int |
410 | | lws_ss_policy_set(struct lws_context *context, const char *name) |
411 | 0 | { |
412 | 0 | int ret = 0; |
413 | |
|
414 | 0 | #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) |
415 | 0 | struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args; |
416 | 0 | const lws_ss_policy_t *pol; |
417 | 0 | struct lws_vhost *v; |
418 | 0 | lws_ss_x509_t *x; |
419 | 0 | char buf[16]; |
420 | 0 | int m; |
421 | | |
422 | | /* |
423 | | * Parsing seems to have succeeded, and we're going to use the new |
424 | | * policy that's laid out in args->ac |
425 | | */ |
426 | |
|
427 | 0 | if (!args) |
428 | 0 | return 1; |
429 | | |
430 | 0 | lejp_destruct(&args->jctx); |
431 | |
|
432 | 0 | if (context->ac_policy) { |
433 | 0 | int n; |
434 | |
|
435 | | #if defined(LWS_WITH_SYS_METRICS) |
436 | | lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, |
437 | | context->owner_mtr_dynpol.head) { |
438 | | lws_metric_policy_dyn_t *dm = |
439 | | lws_container_of(d, lws_metric_policy_dyn_t, list); |
440 | | |
441 | | lws_metric_policy_dyn_destroy(dm, 1); /* keep */ |
442 | | |
443 | | } lws_end_foreach_dll_safe(d, d1); |
444 | | #endif |
445 | | |
446 | | /* |
447 | | * any existing ss created with the old policy have to go away |
448 | | * now, since they point to the shortly-to-be-destroyed old |
449 | | * policy |
450 | | */ |
451 | |
|
452 | 0 | for (n = 0; n < context->count_threads; n++) { |
453 | 0 | struct lws_context_per_thread *pt = &context->pt[n]; |
454 | |
|
455 | 0 | lws_dll2_foreach_safe(&pt->ss_owner, NULL, fe_lws_ss_destroy); |
456 | 0 | } |
457 | | |
458 | | /* |
459 | | * So this is a bit fun-filled, we already had a policy in |
460 | | * force, perhaps it was the default policy that's just good for |
461 | | * fetching the real policy, and we're doing that now. |
462 | | * |
463 | | * We can destroy all the policy-related direct allocations |
464 | | * easily because they're cleanly in a single lwsac... |
465 | | */ |
466 | 0 | lwsac_free(&context->ac_policy); |
467 | | |
468 | | /* |
469 | | * ...but when we did the trust stores, we created vhosts for |
470 | | * each. We need to destroy those now too, and recreate new |
471 | | * ones from the new policy, perhaps with different X.509s. |
472 | | * |
473 | | * Vhost destruction is inherently async, it can't be destroyed |
474 | | * until all of the wsi bound to it have closed, and, eg, libuv |
475 | | * means their closure is deferred until a later go around the |
476 | | * event loop. SMP means we also have to wait for all the pts |
477 | | * to close their wsis that are bound on the vhost too. |
478 | | * |
479 | | * This marks the vhost as being destroyed so new things won't |
480 | | * use it, and starts the close of all wsi on this pt that are |
481 | | * bound to the wsi, and deals with the listen socket if any. |
482 | | * "being-destroyed" vhosts can't be found using get_vhost_by_ |
483 | | * name(), so if a new vhost of the same name exists that isn't |
484 | | * being destroyed that will be the one found. |
485 | | * |
486 | | * When the number of wsi bound to the vhost gets to zero a |
487 | | * short time later, the vhost is actually destroyed. |
488 | | */ |
489 | |
|
490 | 0 | v = context->vhost_list; |
491 | 0 | while (v) { |
492 | 0 | if (v->from_ss_policy) { |
493 | 0 | struct lws_vhost *vh = v->vhost_next; |
494 | 0 | lwsl_debug("%s: destroying %s\n", __func__, lws_vh_tag(v)); |
495 | 0 | lws_vhost_destroy(v); |
496 | 0 | v = vh; |
497 | 0 | continue; |
498 | 0 | } |
499 | 0 | v = v->vhost_next; |
500 | 0 | } |
501 | 0 | } |
502 | |
|
503 | 0 | context->pss_policies = args->heads[LTY_POLICY].p; |
504 | 0 | context->ac_policy = args->ac; |
505 | |
|
506 | 0 | lws_humanize(buf, sizeof(buf), lwsac_total_alloc(args->ac), |
507 | 0 | humanize_schema_si_bytes); |
508 | 0 | if (lwsac_total_alloc(args->ac)) |
509 | 0 | m = (int)((lwsac_total_overhead(args->ac) * 100) / |
510 | 0 | lwsac_total_alloc(args->ac)); |
511 | 0 | else |
512 | 0 | m = 0; |
513 | |
|
514 | 0 | (void)m; |
515 | 0 | lwsl_info("%s: %s, pad %d%c: %s\n", __func__, buf, m, '%', name); |
516 | | |
517 | | /* Create vhosts for each type of trust store */ |
518 | | |
519 | | /* |
520 | | * We get called from context creation... instantiates |
521 | | * vhosts with client tls contexts set up for each unique CA. |
522 | | * |
523 | | * We create the vhosts by walking streamtype list and create vhosts |
524 | | * using trust store name if it's a client connection that doesn't |
525 | | * already exist. |
526 | | */ |
527 | |
|
528 | 0 | pol = context->pss_policies; |
529 | 0 | while (pol) { |
530 | 0 | if (!(pol->flags & LWSSSPOLF_SERVER)) { |
531 | 0 | v = lws_ss_policy_ref_trust_store(context, pol, |
532 | 0 | 0 /* no refcount inc */); |
533 | 0 | if (!v) |
534 | 0 | ret = 1; |
535 | 0 | } |
536 | |
|
537 | 0 | pol = pol->next; |
538 | 0 | } |
539 | |
|
540 | | #if defined(LWS_WITH_SOCKS5) |
541 | | |
542 | | /* |
543 | | * ... we need to go through every vhost updating its understanding of |
544 | | * which socks5 proxy to use... |
545 | | */ |
546 | | |
547 | | v = context->vhost_list; |
548 | | while (v) { |
549 | | lws_set_socks(v, args->socks5_proxy); |
550 | | v = v->vhost_next; |
551 | | } |
552 | | if (context->vhost_system) |
553 | | lws_set_socks(context->vhost_system, args->socks5_proxy); |
554 | | |
555 | | if (args->socks5_proxy) |
556 | | lwsl_notice("%s: global socks5 proxy: %s\n", __func__, |
557 | | args->socks5_proxy); |
558 | | #endif |
559 | | |
560 | | /* |
561 | | * For dynamic policy case, now we processed the x.509 CAs, we can free |
562 | | * all of our originals. For static policy, they're in .rodata, nothing |
563 | | * to free. |
564 | | */ |
565 | |
|
566 | 0 | x = args->heads[LTY_X509].x; |
567 | 0 | while (x) { |
568 | | /* |
569 | | * Free all the client DER buffers now they have been parsed |
570 | | * into tls library X.509 objects |
571 | | */ |
572 | 0 | if (!x->keep) { /* used for server */ |
573 | 0 | lws_free((void *)x->ca_der); |
574 | 0 | x->ca_der = NULL; |
575 | 0 | } |
576 | |
|
577 | 0 | x = x->next; |
578 | 0 | } |
579 | |
|
580 | 0 | context->last_policy = time(NULL); |
581 | | #if defined(LWS_WITH_SYS_METRICS) |
582 | | if (context->pss_policies) |
583 | | ((lws_ss_policy_t *)context->pss_policies)->metrics = |
584 | | args->heads[LTY_METRICS].m; |
585 | | #endif |
586 | | |
587 | | /* and we can discard the parsing args object now, invalidating args */ |
588 | |
|
589 | 0 | lws_free_set_NULL(context->pol_args); |
590 | 0 | #endif |
591 | |
|
592 | | #if defined(LWS_WITH_SYS_METRICS) |
593 | | lws_metric_rebind_policies(context); |
594 | | #endif |
595 | |
|
596 | 0 | #if defined(LWS_WITH_SYS_SMD) |
597 | 0 | (void)lws_smd_msg_printf(context, LWSSMDCL_SYSTEM_STATE, |
598 | 0 | "{\"policy\":\"updated\",\"ts\":%lu}", |
599 | 0 | (long)context->last_policy); |
600 | 0 | #endif |
601 | |
|
602 | 0 | return ret; |
603 | 0 | } |