1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2019 - 2020 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
25 #include <private-lib-core.h>
26
27 typedef struct backoffs {
28 struct backoffs *next;
29 const char *name;
30 lws_retry_bo_t r;
31 } backoff_t;
32
33 static const char * const lejp_tokens_policy[] = {
34 "release",
35 "product",
36 "schema-version",
37 "via-socks5",
38 "retry[].*.backoff",
39 "retry[].*.conceal",
40 "retry[].*.jitterpc",
41 "retry[].*.svalidping",
42 "retry[].*.svalidhup",
43 "retry[].*",
44 "certs[].*",
45 "trust_stores[].name",
46 "trust_stores[].stack",
47 "s[].*.endpoint",
48 "s[].*.via-socks5",
49 "s[].*.protocol",
50 "s[].*.port",
51 "s[].*.plugins",
52 "s[].*.tls",
53 "s[].*.client_cert",
54 "s[].*.opportunistic",
55 "s[].*.nailed_up",
56 "s[].*.urgent_tx",
57 "s[].*.urgent_rx",
58 "s[].*.long_poll",
59 "s[].*.retry",
60 "s[].*.tls_trust_store",
61 "s[].*.metadata",
62 "s[].*.metadata[].*",
63
64 "s[].*.http_auth_header",
65 "s[].*.http_dsn_header",
66 "s[].*.http_fwv_header",
67 "s[].*.http_devtype_header",
68
69 "s[].*.http_auth_preamble",
70
71 "s[].*.http_no_content_length",
72 "s[].*.rideshare", /* streamtype name this rides shotgun with */
73 "s[].*.payload_fmt",
74 "s[].*.http_method",
75 "s[].*.http_url",
76 "s[].*.nghttp2_quirk_end_stream",
77 "s[].*.h2q_oflow_txcr",
78 "s[].*.http_multipart_name",
79 "s[].*.http_multipart_filename",
80 "s[].*.http_mime_content_type",
81 "s[].*.http_www_form_urlencoded",
82 "s[].*.ws_subprotocol",
83 "s[].*.ws_binary",
84 "s[].*.local_sink",
85 "s[].*.mqtt_topic",
86 "s[].*.mqtt_subscribe",
87 "s[].*.mqtt_qos",
88 "s[].*.mqtt_keep_alive",
89 "s[].*.mqtt_clean_start",
90 "s[].*.mqtt_will_topic",
91 "s[].*.mqtt_will_message",
92 "s[].*.mqtt_will_qos",
93 "s[].*.mqtt_will_retain",
94 "s[].*",
95 };
96
97 typedef enum {
98 LSSPPT_RELEASE,
99 LSSPPT_PRODUCT,
100 LSSPPT_SCHEMA_VERSION,
101 LSSPPT_VIA_SOCKS5,
102 LSSPPT_BACKOFF,
103 LSSPPT_CONCEAL,
104 LSSPPT_JITTERPC,
105 LSSPPT_VALIDPING_S,
106 LSSPPT_VALIDHUP_S,
107 LSSPPT_RETRY,
108 LSSPPT_CERTS,
109 LSSPPT_TRUST_STORES_NAME,
110 LSSPPT_TRUST_STORES_STACK,
111 LSSPPT_ENDPOINT,
112 LSSPPT_VH_VIA_SOCKS5,
113 LSSPPT_PROTOCOL,
114 LSSPPT_PORT,
115 LSSPPT_PLUGINS,
116 LSSPPT_TLS,
117 LSSPPT_TLS_CLIENT_CERT,
118 LSSPPT_OPPORTUNISTIC,
119 LSSPPT_NAILED_UP,
120 LSSPPT_URGENT_TX,
121 LSSPPT_URGENT_RX,
122 LSSPPT_LONG_POLL,
123 LSSPPT_RETRYPTR,
124 LSSPPT_TRUST,
125 LSSPPT_METADATA,
126 LSSPPT_METADATA_ITEM,
127
128 LSSPPT_HTTP_AUTH_HEADER,
129 LSSPPT_HTTP_DSN_HEADER,
130 LSSPPT_HTTP_FWV_HEADER,
131 LSSPPT_HTTP_TYPE_HEADER,
132
133 LSSPPT_HTTP_AUTH_PREAMBLE,
134 LSSPPT_HTTP_NO_CONTENT_LENGTH,
135 LSSPPT_RIDESHARE,
136 LSSPPT_PAYLOAD_FORMAT,
137 LSSPPT_HTTP_METHOD,
138 LSSPPT_HTTP_URL,
139 LSSPPT_NGHTTP2_QUIRK_END_STREAM,
140 LSSPPT_H2_QUIRK_OVERFLOWS_TXCR,
141 LSSPPT_HTTP_MULTIPART_NAME,
142 LSSPPT_HTTP_MULTIPART_FILENAME,
143 LSSPPT_HTTP_MULTIPART_CONTENT_TYPE,
144 LSSPPT_HTTP_WWW_FORM_URLENCODED,
145 LSSPPT_WS_SUBPROTOCOL,
146 LSSPPT_WS_BINARY,
147 LSSPPT_LOCAL_SINK,
148 LSSPPT_MQTT_TOPIC,
149 LSSPPT_MQTT_SUBSCRIBE,
150 LSSPPT_MQTT_QOS,
151 LSSPPT_MQTT_KEEPALIVE,
152 LSSPPT_MQTT_CLEAN_START,
153 LSSPPT_MQTT_WILL_TOPIC,
154 LSSPPT_MQTT_WILL_MESSAGE,
155 LSSPPT_MQTT_WILL_QOS,
156 LSSPPT_MQTT_WILL_RETAIN,
157 LSSPPT_STREAMTYPES
158 } policy_token_t;
159
160 union u {
161 backoff_t *b;
162 lws_ss_x509_t *x;
163 lws_ss_trust_store_t *t;
164 lws_ss_policy_t *p;
165 };
166
167 enum {
168 LTY_BACKOFF,
169 LTY_X509,
170 LTY_TRUSTSTORE,
171 LTY_POLICY,
172
173 _LTY_COUNT /* always last */
174 };
175
176 struct policy_cb_args {
177 struct lejp_ctx jctx;
178 struct lws_context *context;
179 struct lwsac *ac;
180
181 const char *socks5_proxy;
182
183 struct lws_b64state b64;
184
185 union u heads[_LTY_COUNT];
186 union u curr[_LTY_COUNT];
187
188 uint8_t *p;
189
190 int count;
191 };
192
193 #define POL_AC_INITIAL 2048
194 #define POL_AC_GRAIN 800
195 #define MAX_CERT_TEMP 2048 /* used to discover actual cert size for realloc */
196
197 static uint8_t sizes[] = {
198 sizeof(backoff_t),
199 sizeof(lws_ss_x509_t),
200 sizeof(lws_ss_trust_store_t),
201 sizeof(lws_ss_policy_t),
202 };
203
204 static const char *protonames[] = {
205 "h1", /* LWSSSP_H1 */
206 "h2", /* LWSSSP_H2 */
207 "ws", /* LWSSSP_WS */
208 "mqtt", /* LWSSSP_MQTT */
209 };
210
211 lws_ss_metadata_t *
lws_ss_policy_metadata(const lws_ss_policy_t * p,const char * name)212 lws_ss_policy_metadata(const lws_ss_policy_t *p, const char *name)
213 {
214 lws_ss_metadata_t *pmd = p->metadata;
215
216 while (pmd) {
217 if (pmd->name && !strcmp(name, pmd->name))
218 return pmd;
219 pmd = pmd->next;
220 }
221
222 return NULL;
223 }
224
225 lws_ss_metadata_t *
lws_ss_policy_metadata_index(const lws_ss_policy_t * p,size_t index)226 lws_ss_policy_metadata_index(const lws_ss_policy_t *p, size_t index)
227 {
228 lws_ss_metadata_t *pmd = p->metadata;
229
230 while (pmd) {
231 if (pmd->length == index)
232 return pmd;
233 pmd = pmd->next;
234 }
235
236 return NULL;
237 }
238
239 int
lws_ss_set_metadata(struct lws_ss_handle * h,const char * name,void * value,size_t len)240 lws_ss_set_metadata(struct lws_ss_handle *h, const char *name,
241 void *value, size_t len)
242 {
243 lws_ss_metadata_t *omd = lws_ss_policy_metadata(h->policy, name);
244
245 if (!omd) {
246 lwsl_err("%s: unknown metadata %s\n", __func__, name);
247 return 1;
248 }
249
250 h->metadata[omd->length].name = name;
251 h->metadata[omd->length].value = value;
252 h->metadata[omd->length].length = len;
253
254 return 0;
255 }
256
257 lws_ss_metadata_t *
lws_ss_get_handle_metadata(struct lws_ss_handle * h,const char * name)258 lws_ss_get_handle_metadata(struct lws_ss_handle *h, const char *name)
259 {
260 lws_ss_metadata_t *omd = lws_ss_policy_metadata(h->policy, name);
261
262 if (!omd)
263 return NULL;
264
265 return &h->metadata[omd->length];
266 }
267
268 static signed char
lws_ss_policy_parser_cb(struct lejp_ctx * ctx,char reason)269 lws_ss_policy_parser_cb(struct lejp_ctx *ctx, char reason)
270 {
271 struct policy_cb_args *a = (struct policy_cb_args *)ctx->user;
272 const lws_ss_plugin_t **pin;
273 char **pp, dotstar[32], *q;
274 lws_ss_trust_store_t *ts;
275 lws_ss_metadata_t *pmd;
276 lws_retry_bo_t *b;
277 size_t inl, outl;
278 lws_ss_x509_t *x;
279 uint8_t *extant;
280 backoff_t *bot;
281 int n = -1;
282
283 lwsl_debug("%s: %d %d %s\n", __func__, reason, ctx->path_match - 1,
284 ctx->path);
285
286 switch (ctx->path_match - 1) {
287 case LSSPPT_RETRY:
288 n = LTY_BACKOFF;
289 break;
290 case LSSPPT_CERTS:
291 n = LTY_X509;
292 break;
293 case LSSPPT_TRUST_STORES_NAME:
294 case LSSPPT_TRUST_STORES_STACK:
295 n = LTY_TRUSTSTORE;
296 break;
297 case LSSPPT_STREAMTYPES:
298 n = LTY_POLICY;
299 break;
300 }
301
302 if (reason == LEJPCB_ARRAY_START &&
303 (ctx->path_match - 1 == LSSPPT_PLUGINS ||
304 ctx->path_match - 1 == LSSPPT_METADATA))
305 a->count = 0;
306
307 if (reason == LEJPCB_ARRAY_END &&
308 ctx->path_match - 1 == LSSPPT_TRUST_STORES_STACK && !a->count) {
309 lwsl_err("%s: at least one cert required in trust store\n",
310 __func__);
311 goto oom;
312 }
313
314 if (reason == LEJPCB_OBJECT_END && a->p) {
315 /*
316 * Allocate a just-the-right-size buf for the cert DER now
317 * we decoded it into the a->p temp buffer and know the exact
318 * size
319 */
320 a->curr[LTY_X509].x->ca_der = lws_malloc(a->count, "ssx509");
321 if (!a->curr[LTY_X509].x->ca_der)
322 goto oom;
323 memcpy((uint8_t *)a->curr[LTY_X509].x->ca_der, a->p, a->count);
324 a->curr[LTY_X509].x->ca_der_len = a->count;
325
326 /*
327 * ... and then we can free the temp buffer
328 */
329 lws_free_set_NULL(a->p);
330
331 return 0;
332 }
333
334 if (reason == LEJPCB_PAIR_NAME && n != -1 && n != LTY_TRUSTSTORE) {
335 /*
336 * We do the pointers always as .b, all of the participating
337 * structs begin with .next and .name
338 */
339 a->curr[n].b = lwsac_use_zero(&a->ac, sizes[n], POL_AC_GRAIN);
340 if (!a->curr[n].b)
341 goto oom;
342
343 if (n == LTY_X509) {
344 a->p = lws_malloc(MAX_CERT_TEMP, "cert temp");
345 if (!a->p)
346 goto oom;
347 memset(&a->b64, 0, sizeof(a->b64));
348 }
349
350 a->count = 0;
351 a->curr[n].b->next = a->heads[n].b;
352 a->heads[n].b = a->curr[n].b;
353 pp = (char **)&a->curr[n].b->name;
354
355 goto string1;
356 }
357
358 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
359 return 0;
360
361 switch (ctx->path_match - 1) {
362
363 /* strings */
364
365 case LSSPPT_RELEASE:
366 break;
367
368 case LSSPPT_PRODUCT:
369 break;
370
371 case LSSPPT_SCHEMA_VERSION:
372 break;
373
374 case LSSPPT_VIA_SOCKS5:
375 /* the global / default proxy */
376 pp = (char **)&a->socks5_proxy;
377 goto string2;
378
379 case LSSPPT_BACKOFF:
380 b = &a->curr[LTY_BACKOFF].b->r;
381 if (b->retry_ms_table_count == 8) {
382 lwsl_err("%s: > 8 backoff levels\n", __func__);
383 return 1;
384 }
385 if (!b->retry_ms_table_count) {
386 b->retry_ms_table = (uint32_t *)lwsac_use_zero(&a->ac,
387 sizeof(uint32_t) * 8, POL_AC_GRAIN);
388 if (!b->retry_ms_table)
389 goto oom;
390 }
391
392 ((uint32_t *)b->retry_ms_table)
393 [b->retry_ms_table_count++] = atoi(ctx->buf);
394 break;
395
396 case LSSPPT_CONCEAL:
397 a->curr[LTY_BACKOFF].b->r.conceal_count = atoi(ctx->buf);
398 break;
399
400 case LSSPPT_JITTERPC:
401 a->curr[LTY_BACKOFF].b->r.jitter_percent = atoi(ctx->buf);
402 break;
403
404 case LSSPPT_VALIDPING_S:
405 a->curr[LTY_BACKOFF].b->r.secs_since_valid_ping = atoi(ctx->buf);
406 break;
407
408 case LSSPPT_VALIDHUP_S:
409 a->curr[LTY_BACKOFF].b->r.secs_since_valid_hangup = atoi(ctx->buf);
410 break;
411
412 case LSSPPT_CERTS:
413 if (a->count + ctx->npos >= MAX_CERT_TEMP) {
414 lwsl_err("%s: cert too big\n", __func__);
415 goto oom;
416 }
417 inl = ctx->npos;
418 outl = MAX_CERT_TEMP - a->count;
419
420 lws_b64_decode_stateful(&a->b64, ctx->buf, &inl,
421 a->p + a->count, &outl,
422 reason == LEJPCB_VAL_STR_END);
423 a->count += outl;
424 if (inl != ctx->npos) {
425 lwsl_err("%s: b64 decode fail\n", __func__);
426 goto oom;
427 }
428 break;
429
430 case LSSPPT_TRUST_STORES_NAME:
431 /*
432 * We do the pointers always as .b, all of the participating
433 * structs begin with .next and .name
434 */
435 a->curr[LTY_TRUSTSTORE].b = lwsac_use_zero(&a->ac,
436 sizes[LTY_TRUSTSTORE], POL_AC_GRAIN);
437 if (!a->curr[LTY_TRUSTSTORE].b)
438 goto oom;
439
440 a->count = 0;
441 a->curr[LTY_TRUSTSTORE].b->next = a->heads[LTY_TRUSTSTORE].b;
442 a->heads[LTY_TRUSTSTORE].b = a->curr[LTY_TRUSTSTORE].b;
443 pp = (char **)&a->curr[LTY_TRUSTSTORE].b->name;
444
445 goto string2;
446
447 case LSSPPT_TRUST_STORES_STACK:
448 if (a->count >= (int)LWS_ARRAY_SIZE(
449 a->curr[LTY_TRUSTSTORE].t->ssx509)) {
450 lwsl_err("%s: trust store too big\n", __func__);
451 goto oom;
452 }
453 lwsl_debug("%s: trust stores stack %.*s\n", __func__,
454 ctx->npos, ctx->buf);
455 x = a->heads[LTY_X509].x;
456 while (x) {
457 if (!strncmp(x->vhost_name, ctx->buf, ctx->npos)) {
458 a->curr[LTY_TRUSTSTORE].t->ssx509[a->count++] = x;
459 a->curr[LTY_TRUSTSTORE].t->count++;
460
461 return 0;
462 }
463 x = x->next;
464 }
465 lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
466 lwsl_err("%s: unknown trust store entry %s\n", __func__,
467 dotstar);
468 goto oom;
469
470 case LSSPPT_ENDPOINT:
471 pp = (char **)&a->curr[LTY_POLICY].p->endpoint;
472 goto string2;
473
474 case LSSPPT_VH_VIA_SOCKS5:
475 pp = (char **)&a->curr[LTY_POLICY].p->socks5_proxy;
476 goto string2;
477
478 case LSSPPT_PORT:
479 a->curr[LTY_POLICY].p->port = atoi(ctx->buf);
480 break;
481
482 case LSSPPT_HTTP_METHOD:
483 pp = (char **)&a->curr[LTY_POLICY].p->u.http.method;
484 goto string2;
485
486 case LSSPPT_HTTP_URL:
487 pp = (char **)&a->curr[LTY_POLICY].p->u.http.url;
488 goto string2;
489
490 case LSSPPT_RIDESHARE:
491 pp = (char **)&a->curr[LTY_POLICY].p->rideshare_streamtype;
492 goto string2;
493
494 case LSSPPT_PAYLOAD_FORMAT:
495 pp = (char **)&a->curr[LTY_POLICY].p->payload_fmt;
496 goto string2;
497
498 case LSSPPT_PLUGINS:
499 pin = a->context->pss_plugins;
500 if (a->count ==
501 (int)LWS_ARRAY_SIZE(a->curr[LTY_POLICY].p->plugins)) {
502 lwsl_err("%s: too many plugins\n", __func__);
503
504 goto oom;
505 }
506 if (!pin)
507 break;
508 while (*pin) {
509 if (!strncmp((*pin)->name, ctx->buf, ctx->npos)) {
510 a->curr[LTY_POLICY].p->plugins[a->count++] = *pin;
511 return 0;
512 }
513 pin++;
514 }
515 lwsl_err("%s: unknown plugin\n", __func__);
516 goto oom;
517
518 case LSSPPT_TLS:
519 if (reason == LEJPCB_VAL_TRUE)
520 a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_TLS;
521 break;
522
523 case LSSPPT_TLS_CLIENT_CERT:
524 a->curr[LTY_POLICY].p->client_cert = atoi(ctx->buf) + 1;
525 break;
526
527 case LSSPPT_OPPORTUNISTIC:
528 if (reason == LEJPCB_VAL_TRUE)
529 a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_OPPORTUNISTIC;
530 break;
531 case LSSPPT_NAILED_UP:
532 if (reason == LEJPCB_VAL_TRUE)
533 a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_NAILED_UP;
534 break;
535 case LSSPPT_URGENT_TX:
536 if (reason == LEJPCB_VAL_TRUE)
537 a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_URGENT_TX;
538 break;
539 case LSSPPT_URGENT_RX:
540 if (reason == LEJPCB_VAL_TRUE)
541 a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_URGENT_RX;
542 break;
543 case LSSPPT_LONG_POLL:
544 if (reason == LEJPCB_VAL_TRUE)
545 a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_LONG_POLL;
546 break;
547 case LSSPPT_HTTP_WWW_FORM_URLENCODED:
548 if (reason == LEJPCB_VAL_TRUE)
549 a->curr[LTY_POLICY].p->flags |=
550 LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED;
551 break;
552
553 case LSSPPT_RETRYPTR:
554 bot = a->heads[LTY_BACKOFF].b;
555 while (bot) {
556 if (!strncmp(ctx->buf, bot->name, ctx->npos)) {
557 a->curr[LTY_POLICY].p->retry_bo = &bot->r;
558
559 return 0;
560 }
561 bot = bot->next;
562 }
563 lwsl_err("%s: unknown backoff scheme\n", __func__);
564
565 return -1;
566
567 case LSSPPT_TRUST:
568 ts = a->heads[LTY_TRUSTSTORE].t;
569 while (ts) {
570 if (!strncmp(ctx->buf, ts->name, ctx->npos)) {
571 a->curr[LTY_POLICY].p->trust_store = ts;
572 return 0;
573 }
574 ts = ts->next;
575 }
576 lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
577 lwsl_err("%s: unknown trust store name %s\n", __func__,
578 dotstar);
579
580 return -1;
581
582 case LSSPPT_METADATA:
583 break;
584
585 case LSSPPT_METADATA_ITEM:
586 pmd = a->curr[LTY_POLICY].p->metadata;
587 a->curr[LTY_POLICY].p->metadata = lwsac_use_zero(&a->ac,
588 sizeof(lws_ss_metadata_t) + ctx->npos +
589 (ctx->path_match_len - ctx->st[ctx->sp - 2].p + 1) + 2,
590 POL_AC_GRAIN);
591 a->curr[LTY_POLICY].p->metadata->next = pmd;
592
593 q = (char *)a->curr[LTY_POLICY].p->metadata +
594 sizeof(lws_ss_metadata_t);
595 a->curr[LTY_POLICY].p->metadata->name = q;
596 memcpy(q, ctx->path + ctx->st[ctx->sp - 2].p + 1,
597 ctx->path_match_len - ctx->st[ctx->sp - 2].p);
598
599 q += ctx->path_match_len - ctx->st[ctx->sp - 2].p;
600 a->curr[LTY_POLICY].p->metadata->value = q;
601 memcpy(q, ctx->buf, ctx->npos);
602
603 a->curr[LTY_POLICY].p->metadata->length = /* the index in handle->metadata */
604 a->curr[LTY_POLICY].p->metadata_count++;
605 break;
606
607 case LSSPPT_HTTP_AUTH_HEADER:
608 case LSSPPT_HTTP_DSN_HEADER:
609 case LSSPPT_HTTP_FWV_HEADER:
610 case LSSPPT_HTTP_TYPE_HEADER:
611 pp = (char **)&a->curr[LTY_POLICY].p->u.http.blob_header[
612 (ctx->path_match - 1) - LSSPPT_HTTP_AUTH_HEADER];
613 goto string2;
614
615 case LSSPPT_HTTP_AUTH_PREAMBLE:
616 pp = (char **)&a->curr[LTY_POLICY].p->u.http.auth_preamble;
617 goto string2;
618
619 case LSSPPT_HTTP_NO_CONTENT_LENGTH:
620 if (reason == LEJPCB_VAL_TRUE)
621 a->curr[LTY_POLICY].p->flags |=
622 LWSSSPOLF_HTTP_NO_CONTENT_LENGTH;
623 break;
624
625 case LSSPPT_NGHTTP2_QUIRK_END_STREAM:
626 if (reason == LEJPCB_VAL_TRUE)
627 a->curr[LTY_POLICY].p->flags |=
628 LWSSSPOLF_QUIRK_NGHTTP2_END_STREAM;
629 break;
630 case LSSPPT_H2_QUIRK_OVERFLOWS_TXCR:
631 if (reason == LEJPCB_VAL_TRUE)
632 a->curr[LTY_POLICY].p->flags |=
633 LWSSSPOLF_H2_QUIRK_OVERFLOWS_TXCR;
634 break;
635 case LSSPPT_HTTP_MULTIPART_NAME:
636 a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_HTTP_MULTIPART;
637 pp = (char **)&a->curr[LTY_POLICY].p->u.http.multipart_name;
638 goto string2;
639 case LSSPPT_HTTP_MULTIPART_FILENAME:
640 a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_HTTP_MULTIPART;
641 pp = (char **)&a->curr[LTY_POLICY].p->u.http.multipart_filename;
642 goto string2;
643 case LSSPPT_HTTP_MULTIPART_CONTENT_TYPE:
644 a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_HTTP_MULTIPART;
645 pp = (char **)&a->curr[LTY_POLICY].p->u.http.multipart_content_type;
646 goto string2;
647 case LSSPPT_WS_SUBPROTOCOL:
648 pp = (char **)&a->curr[LTY_POLICY].p->u.http.u.ws.subprotocol;
649 goto string2;
650
651 case LSSPPT_WS_BINARY:
652 a->curr[LTY_POLICY].p->u.http.u.ws.binary =
653 reason == LEJPCB_VAL_TRUE;
654 break;
655 case LSSPPT_LOCAL_SINK:
656 if (reason == LEJPCB_VAL_TRUE)
657 a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_LOCAL_SINK;
658 break;
659
660 case LSSPPT_MQTT_TOPIC:
661 pp = (char **)&a->curr[LTY_POLICY].p->u.mqtt.topic;
662 goto string2;
663
664 case LSSPPT_MQTT_SUBSCRIBE:
665 pp = (char **)&a->curr[LTY_POLICY].p->u.mqtt.subscribe;
666 goto string2;
667
668 case LSSPPT_MQTT_QOS:
669 a->curr[LTY_POLICY].p->u.mqtt.qos = atoi(ctx->buf);
670 break;
671
672 case LSSPPT_MQTT_KEEPALIVE:
673 a->curr[LTY_POLICY].p->u.mqtt.keep_alive = atoi(ctx->buf);
674 break;
675
676 case LSSPPT_MQTT_CLEAN_START:
677 a->curr[LTY_POLICY].p->u.mqtt.clean_start =
678 reason == LEJPCB_VAL_TRUE;
679 break;
680 case LSSPPT_MQTT_WILL_TOPIC:
681 pp = (char **)&a->curr[LTY_POLICY].p->u.mqtt.will_topic;
682 goto string2;
683
684 case LSSPPT_MQTT_WILL_MESSAGE:
685 pp = (char **)&a->curr[LTY_POLICY].p->u.mqtt.will_message;
686 goto string2;
687
688 case LSSPPT_MQTT_WILL_QOS:
689 a->curr[LTY_POLICY].p->u.mqtt.will_qos = atoi(ctx->buf);
690 break;
691 case LSSPPT_MQTT_WILL_RETAIN:
692 a->curr[LTY_POLICY].p->u.mqtt.will_retain =
693 reason == LEJPCB_VAL_TRUE;
694 break;
695
696 case LSSPPT_PROTOCOL:
697 a->curr[LTY_POLICY].p->protocol = 0xff;
698 for (n = 0; n < (int)LWS_ARRAY_SIZE(protonames); n++)
699 if (strlen(protonames[n]) == ctx->npos &&
700 !strncmp(ctx->buf, protonames[n], ctx->npos))
701 a->curr[LTY_POLICY].p->protocol = (uint8_t)n;
702
703 if (a->curr[LTY_POLICY].p->protocol != 0xff)
704 break;
705 lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
706 lwsl_err("%s: unknown protocol name %s\n", __func__, dotstar);
707 return -1;
708 }
709
710 return 0;
711
712 string2:
713 /*
714 * If we can do const string folding, reuse the existing string rather
715 * than make a new entry
716 */
717 extant = lwsac_scan_extant(a->ac, (uint8_t *)ctx->buf, ctx->npos, 1);
718 if (extant) {
719 *pp = (char *)extant;
720
721 return 0;
722 }
723 *pp = lwsac_use_backfill(&a->ac, ctx->npos + 1, POL_AC_GRAIN);
724 if (!*pp)
725 goto oom;
726 memcpy(*pp, ctx->buf, ctx->npos);
727 (*pp)[ctx->npos] = '\0';
728
729 return 0;
730
731 string1:
732 n = ctx->st[ctx->sp].p;
733 *pp = lwsac_use_backfill(&a->ac, ctx->path_match_len + 1 - n,
734 POL_AC_GRAIN);
735 if (!*pp)
736 goto oom;
737 memcpy(*pp, ctx->path + n, ctx->path_match_len - n);
738 (*pp)[ctx->path_match_len - n] = '\0';
739
740 return 0;
741
742 oom:
743 lwsl_err("%s: OOM\n", __func__);
744 lws_free_set_NULL(a->p);
745 lwsac_free(&a->ac);
746
747 return -1;
748 }
749
750 int
lws_ss_policy_parse_begin(struct lws_context * context)751 lws_ss_policy_parse_begin(struct lws_context *context)
752 {
753 struct policy_cb_args *args;
754 char *p;
755
756 args = lws_zalloc(sizeof(struct policy_cb_args), __func__);
757 if (!args) {
758 lwsl_err("%s: OOM\n", __func__);
759
760 return 1;
761 }
762
763 context->pol_args = args;
764 args->context = context;
765 p = lwsac_use(&args->ac, 1, POL_AC_INITIAL);
766 if (!p) {
767 lwsl_err("%s: OOM\n", __func__);
768 lws_free_set_NULL(context->pol_args);
769
770 return -1;
771 }
772 *p = 0;
773 lejp_construct(&args->jctx, lws_ss_policy_parser_cb, args,
774 lejp_tokens_policy, LWS_ARRAY_SIZE(lejp_tokens_policy));
775
776 return 0;
777 }
778
779 int
lws_ss_policy_parse_abandon(struct lws_context * context)780 lws_ss_policy_parse_abandon(struct lws_context *context)
781 {
782 struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args;
783
784 lejp_destruct(&args->jctx);
785 lws_free_set_NULL(context->pol_args);
786
787 return 0;
788 }
789
790 int
lws_ss_policy_parse(struct lws_context * context,const uint8_t * buf,size_t len)791 lws_ss_policy_parse(struct lws_context *context, const uint8_t *buf, size_t len)
792 {
793 struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args;
794 int m;
795
796 m = (int)(signed char)lejp_parse(&args->jctx, buf, len);
797 if (m == LEJP_CONTINUE || m >= 0)
798 return m;
799
800 lwsl_err("%s: parse failed: %d: %s\n", __func__, m,
801 lejp_error_to_string(m));
802 lws_ss_policy_parse_abandon(context);
803
804 return m;
805 }
806
807 int
lws_ss_policy_set(struct lws_context * context,const char * name)808 lws_ss_policy_set(struct lws_context *context, const char *name)
809 {
810 struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args;
811 lws_ss_trust_store_t *ts;
812 struct lws_vhost *v;
813 lws_ss_x509_t *x;
814 char buf[16];
815 int m, ret = 0;
816
817 /*
818 * Parsing seems to have succeeded, and we're going to use the new
819 * policy that's laid out in args->ac
820 */
821
822 lejp_destruct(&args->jctx);
823
824 if (context->ac_policy) {
825
826 /*
827 * So this is a bit fun-filled, we already had a policy in
828 * force, perhaps it was the default policy that's just good for
829 * fetching the real policy, and we're doing that now.
830 *
831 * We can destroy all the policy-related direct allocations
832 * easily because they're cleanly in a single lwsac...
833 */
834 lwsac_free(&context->ac_policy);
835
836 /*
837 * ...but when we did the trust stores, we created vhosts for
838 * each. We need to destroy those now too, and recreate new
839 * ones from the new policy, perhaps with different X.509s.
840 */
841
842 v = context->vhost_list;
843 while (v) {
844 if (v->from_ss_policy) {
845 struct lws_vhost *vh = v->vhost_next;
846 lwsl_debug("%s: destroying vh %p\n", __func__, v);
847 lws_vhost_destroy(v);
848 v = vh;
849 continue;
850 }
851 v = v->vhost_next;
852 }
853
854 lws_check_deferred_free(context, 0, 1);
855 }
856
857 context->pss_policies = args->heads[LTY_POLICY].p;
858 context->ac_policy = args->ac;
859
860 lws_humanize(buf, sizeof(buf), lwsac_total_alloc(args->ac),
861 humanize_schema_si_bytes);
862 if (lwsac_total_alloc(args->ac))
863 m = (int)((lwsac_total_overhead(args->ac) * 100) /
864 lwsac_total_alloc(args->ac));
865 else
866 m = 0;
867
868 lwsl_notice("%s: %s, pad %d%c: %s\n", __func__, buf, m, '%', name);
869
870 /* Create vhosts for each type of trust store */
871
872 ts = args->heads[LTY_TRUSTSTORE].t;
873 while (ts) {
874 struct lws_context_creation_info i;
875
876 memset(&i, 0, sizeof(i));
877
878 /*
879 * We get called from context creation... instantiates
880 * vhosts with client tls contexts set up for each unique CA.
881 *
882 * Create the vhost with the first (mandatory) entry in the
883 * trust store...
884 */
885
886 v = lws_get_vhost_by_name(context, ts->name);
887 if (!v) {
888 int n;
889
890 i.options = context->options;
891 i.vhost_name = ts->name;
892 lwsl_debug("%s: %s\n", __func__, i.vhost_name);
893 i.client_ssl_ca_mem = ts->ssx509[0]->ca_der;
894 i.client_ssl_ca_mem_len = ts->ssx509[0]->ca_der_len;
895 i.port = CONTEXT_PORT_NO_LISTEN;
896 lwsl_info("%s: %s trust store initial '%s'\n", __func__,
897 ts->name, ts->ssx509[0]->vhost_name);
898
899 v = lws_create_vhost(context, &i);
900 if (!v) {
901 lwsl_err("%s: failed to create vhost %s\n",
902 __func__, ts->name);
903 ret = 1;
904 } else
905 v->from_ss_policy = 1;
906
907 for (n = 1; v && n < ts->count; n++) {
908 lwsl_info("%s: add '%s' to trust store\n",
909 __func__, ts->ssx509[n]->vhost_name);
910 if (lws_tls_client_vhost_extra_cert_mem(v,
911 ts->ssx509[n]->ca_der,
912 ts->ssx509[n]->ca_der_len)) {
913 lwsl_err("%s: add extra cert failed\n",
914 __func__);
915 ret = 1;
916 }
917 }
918 }
919
920 ts = ts->next;
921 }
922
923 #if defined(LWS_WITH_SOCKS5)
924
925 /*
926 * ... we need to go through every vhost updating its understanding of
927 * which socks5 proxy to use...
928 */
929
930 v = context->vhost_list;
931 while (v) {
932 lws_set_socks(v, args->socks5_proxy);
933 v = v->vhost_next;
934 }
935 if (context->vhost_system)
936 lws_set_socks(context->vhost_system, args->socks5_proxy);
937
938 if (args->socks5_proxy)
939 lwsl_notice("%s: global socks5 proxy: %s\n", __func__,
940 args->socks5_proxy);
941 #endif
942
943 /* now we processed the x.509 CAs, we can free all of our originals */
944
945 x = args->heads[LTY_X509].x;
946 while (x) {
947 /*
948 * Free all the DER buffers now they have been parsed into
949 * tls library X.509 objects
950 */
951 lws_free((void *)x->ca_der);
952 x->ca_der = NULL;
953 x = x->next;
954 }
955
956 /* and we can discard the parsing args object now, invalidating args */
957
958 lws_free_set_NULL(context->pol_args);
959
960 return ret;
961 }
962
963 const lws_ss_policy_t *
lws_ss_policy_lookup(const struct lws_context * context,const char * streamtype)964 lws_ss_policy_lookup(const struct lws_context *context, const char *streamtype)
965 {
966 const lws_ss_policy_t *p = context->pss_policies;
967
968 if (!streamtype)
969 return NULL;
970
971 while (p) {
972 if (!strcmp(p->streamtype, streamtype))
973 return p;
974 p = p->next;
975 }
976
977 return NULL;
978 }
979