• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 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 #ifndef _WIN32
28 /* this is needed for Travis CI */
29 #include <dirent.h>
30 #endif
31 
32 #define ESC_INSTALL_DATADIR "_lws_ddir_"
33 
34 static const char * const paths_global[] = {
35 	"global.uid",
36 	"global.gid",
37 	"global.username",
38 	"global.groupname",
39 	"global.count-threads",
40 	"global.init-ssl",
41 	"global.server-string",
42 	"global.plugin-dir",
43 	"global.ws-pingpong-secs", /* deprecated */
44 	"global.timeout-secs",
45 	"global.reject-service-keywords[].*",
46 	"global.reject-service-keywords[]",
47 	"global.default-alpn",
48 	"global.ip-limit-ah",
49 	"global.ip-limit-wsi",
50 	"global.rlimit-nofile",
51 };
52 
53 enum lejp_global_paths {
54 	LEJPGP_UID,
55 	LEJPGP_GID,
56 	LEJPGP_USERNAME,
57 	LEJPGP_GROUPNAME,
58 	LEJPGP_COUNT_THREADS,
59 	LWJPGP_INIT_SSL,
60 	LEJPGP_SERVER_STRING,
61 	LEJPGP_PLUGIN_DIR,
62 	LWJPGP_PINGPONG_SECS,
63 	LWJPGP_TIMEOUT_SECS,
64 	LWJPGP_REJECT_SERVICE_KEYWORDS_NAME,
65 	LWJPGP_REJECT_SERVICE_KEYWORDS,
66 	LWJPGP_DEFAULT_ALPN,
67 	LWJPGP_IP_LIMIT_AH,
68 	LWJPGP_IP_LIMIT_WSI,
69 	LWJPGP_FD_LIMIT_PT,
70 };
71 
72 static const char * const paths_vhosts[] = {
73 	"vhosts[]",
74 	"vhosts[].mounts[]",
75 	"vhosts[].name",
76 	"vhosts[].port",
77 	"vhosts[].interface",
78 	"vhosts[].unix-socket",
79 	"vhosts[].unix-socket-perms",
80 	"vhosts[].sts",
81 	"vhosts[].host-ssl-key",
82 	"vhosts[].host-ssl-cert",
83 	"vhosts[].host-ssl-ca",
84 	"vhosts[].access-log",
85 	"vhosts[].mounts[].mountpoint",
86 	"vhosts[].mounts[].origin",
87 	"vhosts[].mounts[].protocol",
88 	"vhosts[].mounts[].default",
89 	"vhosts[].mounts[].auth-mask",
90 	"vhosts[].mounts[].cgi-timeout",
91 	"vhosts[].mounts[].cgi-env[].*",
92 	"vhosts[].mounts[].cache-max-age",
93 	"vhosts[].mounts[].cache-reuse",
94 	"vhosts[].mounts[].cache-revalidate",
95 	"vhosts[].mounts[].basic-auth",
96 	"vhosts[].mounts[].cache-intermediaries",
97 	"vhosts[].mounts[].extra-mimetypes.*",
98 	"vhosts[].mounts[].interpret.*",
99 	"vhosts[].ws-protocols[].*.*",
100 	"vhosts[].ws-protocols[].*",
101 	"vhosts[].ws-protocols[]",
102 	"vhosts[].keepalive_timeout",
103 	"vhosts[].enable-client-ssl",
104 	"vhosts[].ciphers",
105 	"vhosts[].ecdh-curve",
106 	"vhosts[].noipv6",
107 	"vhosts[].ipv6only",
108 	"vhosts[].ssl-option-set",
109 	"vhosts[].ssl-option-clear",
110 	"vhosts[].mounts[].pmo[].*",
111 	"vhosts[].headers[].*",
112 	"vhosts[].headers[]",
113 	"vhosts[].client-ssl-key",
114 	"vhosts[].client-ssl-cert",
115 	"vhosts[].client-ssl-ca",
116 	"vhosts[].client-ssl-ciphers",
117 	"vhosts[].onlyraw",
118 	"vhosts[].client-cert-required",
119 	"vhosts[].ignore-missing-cert",
120 	"vhosts[].error-document-404",
121 	"vhosts[].alpn",
122 	"vhosts[].fo-listen-queue",
123 	"vhosts[].ssl-client-option-set",
124 	"vhosts[].ssl-client-option-clear",
125 	"vhosts[].tls13-ciphers",
126 	"vhosts[].client-tls13-ciphers",
127 	"vhosts[].strict-host-check",
128 
129 	"vhosts[].listen-accept-role",
130 	"vhosts[].listen-accept-protocol",
131 	"vhosts[].apply-listen-accept", /* deprecates "onlyraw" */
132 	"vhosts[].fallback-listen-accept",
133 	"vhosts[].allow-non-tls",
134 	"vhosts[].redirect-http",
135 	"vhosts[].allow-http-on-https",
136 
137 	"vhosts[].disable-no-protocol-ws-upgrades",
138 	"vhosts[].h2-half-closed-long-poll",
139 };
140 
141 enum lejp_vhost_paths {
142 	LEJPVP,
143 	LEJPVP_MOUNTS,
144 	LEJPVP_NAME,
145 	LEJPVP_PORT,
146 	LEJPVP_INTERFACE,
147 	LEJPVP_UNIXSKT,
148 	LEJPVP_UNIXSKT_PERMS,
149 	LEJPVP_STS,
150 	LEJPVP_HOST_SSL_KEY,
151 	LEJPVP_HOST_SSL_CERT,
152 	LEJPVP_HOST_SSL_CA,
153 	LEJPVP_ACCESS_LOG,
154 	LEJPVP_MOUNTPOINT,
155 	LEJPVP_ORIGIN,
156 	LEJPVP_MOUNT_PROTOCOL,
157 	LEJPVP_DEFAULT,
158 	LEJPVP_DEFAULT_AUTH_MASK,
159 	LEJPVP_CGI_TIMEOUT,
160 	LEJPVP_CGI_ENV,
161 	LEJPVP_MOUNT_CACHE_MAX_AGE,
162 	LEJPVP_MOUNT_CACHE_REUSE,
163 	LEJPVP_MOUNT_CACHE_REVALIDATE,
164 	LEJPVP_MOUNT_BASIC_AUTH,
165 	LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
166 	LEJPVP_MOUNT_EXTRA_MIMETYPES,
167 	LEJPVP_MOUNT_INTERPRET,
168 	LEJPVP_PROTOCOL_NAME_OPT,
169 	LEJPVP_PROTOCOL_NAME,
170 	LEJPVP_PROTOCOL,
171 	LEJPVP_KEEPALIVE_TIMEOUT,
172 	LEJPVP_ENABLE_CLIENT_SSL,
173 	LEJPVP_CIPHERS,
174 	LEJPVP_ECDH_CURVE,
175 	LEJPVP_NOIPV6,
176 	LEJPVP_IPV6ONLY,
177 	LEJPVP_SSL_OPTION_SET,
178 	LEJPVP_SSL_OPTION_CLEAR,
179 	LEJPVP_PMO,
180 	LEJPVP_HEADERS_NAME,
181 	LEJPVP_HEADERS,
182 	LEJPVP_CLIENT_SSL_KEY,
183 	LEJPVP_CLIENT_SSL_CERT,
184 	LEJPVP_CLIENT_SSL_CA,
185 	LEJPVP_CLIENT_CIPHERS,
186 	LEJPVP_FLAG_ONLYRAW,
187 	LEJPVP_FLAG_CLIENT_CERT_REQUIRED,
188 	LEJPVP_IGNORE_MISSING_CERT,
189 	LEJPVP_ERROR_DOCUMENT_404,
190 	LEJPVP_ALPN,
191 	LWJPVP_FO_LISTEN_QUEUE,
192 	LEJPVP_SSL_CLIENT_OPTION_SET,
193 	LEJPVP_SSL_CLIENT_OPTION_CLEAR,
194 	LEJPVP_TLS13_CIPHERS,
195 	LEJPVP_CLIENT_TLS13_CIPHERS,
196 	LEJPVP_FLAG_STRICT_HOST_CHECK,
197 
198 	LEJPVP_LISTEN_ACCEPT_ROLE,
199 	LEJPVP_LISTEN_ACCEPT_PROTOCOL,
200 	LEJPVP_FLAG_APPLY_LISTEN_ACCEPT,
201 	LEJPVP_FLAG_FALLBACK_LISTEN_ACCEPT,
202 	LEJPVP_FLAG_ALLOW_NON_TLS,
203 	LEJPVP_FLAG_REDIRECT_HTTP,
204 	LEJPVP_FLAG_ALLOW_HTTP_ON_HTTPS,
205 
206 	LEJPVP_FLAG_DISABLE_NO_PROTOCOL_WS_UPGRADES,
207 	LEJPVP_FLAG_H2_HALF_CLOSED_LONG_POLL,
208 };
209 
210 #define MAX_PLUGIN_DIRS 10
211 
212 struct jpargs {
213 	struct lws_context_creation_info *info;
214 	struct lws_context *context;
215 	const struct lws_protocols *protocols;
216 	const struct lws_protocols **pprotocols;
217 	const struct lws_extension *extensions;
218 	char *p, *end, valid;
219 	struct lws_http_mount *head, *last;
220 
221 	struct lws_protocol_vhost_options *pvo;
222 	struct lws_protocol_vhost_options *pvo_em;
223 	struct lws_protocol_vhost_options *pvo_int;
224 	struct lws_http_mount m;
225 	const char **plugin_dirs;
226 	int count_plugin_dirs;
227 
228 	unsigned int reject_ws_with_no_protocol:1;
229 	unsigned int enable_client_ssl:1;
230 	unsigned int fresh_mount:1;
231 	unsigned int any_vhosts:1;
232 	unsigned int chunk:1;
233 };
234 
235 static void *
lwsws_align(struct jpargs * a)236 lwsws_align(struct jpargs *a)
237 {
238 	if ((lws_intptr_t)(a->p) & 15)
239 		a->p += 16 - ((lws_intptr_t)(a->p) & 15);
240 
241 	a->chunk = 0;
242 
243 	return a->p;
244 }
245 
246 static int
arg_to_bool(const char * s)247 arg_to_bool(const char *s)
248 {
249 	static const char * const on[] = { "on", "yes", "true" };
250 	int n = atoi(s);
251 
252 	if (n)
253 		return 1;
254 
255 	for (n = 0; n < (int)LWS_ARRAY_SIZE(on); n++)
256 		if (!strcasecmp(s, on[n]))
257 			return 1;
258 
259 	return 0;
260 }
261 
262 static void
set_reset_flag(uint64_t * p,const char * state,uint64_t flag)263 set_reset_flag(uint64_t *p, const char *state, uint64_t flag)
264 {
265 	if (arg_to_bool(state))
266 		*p |= flag;
267 	else
268 		*p &= ~(flag);
269 }
270 
271 static signed char
lejp_globals_cb(struct lejp_ctx * ctx,char reason)272 lejp_globals_cb(struct lejp_ctx *ctx, char reason)
273 {
274 	struct jpargs *a = (struct jpargs *)ctx->user;
275 	struct lws_protocol_vhost_options *rej;
276 	int n;
277 
278 	/* we only match on the prepared path strings */
279 	if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
280 		return 0;
281 
282 	/* this catches, eg, vhosts[].headers[].xxx */
283 	if (reason == LEJPCB_VAL_STR_END &&
284 	    ctx->path_match == LWJPGP_REJECT_SERVICE_KEYWORDS_NAME + 1) {
285 		rej = lwsws_align(a);
286 		a->p += sizeof(*rej);
287 
288 		n = lejp_get_wildcard(ctx, 0, a->p, lws_ptr_diff(a->end, a->p));
289 		rej->next = a->info->reject_service_keywords;
290 		a->info->reject_service_keywords = rej;
291 		rej->name = a->p;
292 		 lwsl_notice("  adding rej %s=%s\n", a->p, ctx->buf);
293 		a->p += n - 1;
294 		*(a->p++) = '\0';
295 		rej->value = a->p;
296 		rej->options = NULL;
297 		goto dostring;
298 	}
299 
300 	switch (ctx->path_match - 1) {
301 	case LEJPGP_UID:
302 		a->info->uid = (unsigned int)atoi(ctx->buf);
303 		return 0;
304 	case LEJPGP_GID:
305 		a->info->gid = (unsigned int)atoi(ctx->buf);
306 		return 0;
307 	case LEJPGP_USERNAME:
308 		a->info->username = a->p;
309 		break;
310 	case LEJPGP_GROUPNAME:
311 		a->info->groupname = a->p;
312 		break;
313 	case LEJPGP_COUNT_THREADS:
314 		a->info->count_threads = (unsigned int)atoi(ctx->buf);
315 		return 0;
316 	case LWJPGP_INIT_SSL:
317 		if (arg_to_bool(ctx->buf))
318 			a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
319 		return 0;
320 	case LEJPGP_SERVER_STRING:
321 #if defined(LWS_WITH_SERVER)
322 		a->info->server_string = a->p;
323 #endif
324 		break;
325 	case LEJPGP_PLUGIN_DIR:
326 		if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
327 			lwsl_err("Too many plugin dirs\n");
328 			return -1;
329 		}
330 		a->plugin_dirs[a->count_plugin_dirs++] = a->p;
331 		break;
332 
333 	case LWJPGP_PINGPONG_SECS: /* deprecated */
334 		return 0;
335 
336 	case LWJPGP_TIMEOUT_SECS:
337 		a->info->timeout_secs = (unsigned int)atoi(ctx->buf);
338 		return 0;
339 
340 #if defined(LWS_WITH_TLS)
341 	case LWJPGP_DEFAULT_ALPN:
342 		a->info->alpn = a->p;
343 		break;
344 #endif
345 
346 #if defined(LWS_WITH_PEER_LIMITS)
347 	case LWJPGP_IP_LIMIT_AH:
348 		a->info->ip_limit_ah = (uint16_t)atoi(ctx->buf);
349 		return 0;
350 
351 	case LWJPGP_IP_LIMIT_WSI:
352 		a->info->ip_limit_wsi = (uint16_t)atoi(ctx->buf);
353 		return 0;
354 #endif
355 
356 	case LWJPGP_FD_LIMIT_PT:
357 		a->info->rlimit_nofile = atoi(ctx->buf);
358 		return 0;
359 
360 	default:
361 		return 0;
362 	}
363 
364 dostring:
365 	a->p += lws_snprintf(a->p, lws_ptr_diff_size_t(a->end, a->p), "%s", ctx->buf);
366 	*(a->p)++ = '\0';
367 
368 	return 0;
369 }
370 
371 static signed char
lejp_vhosts_cb(struct lejp_ctx * ctx,char reason)372 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
373 {
374 	struct jpargs *a = (struct jpargs *)ctx->user;
375 	struct lws_protocol_vhost_options *pvo, *mp_cgienv, *headers;
376 	struct lws_http_mount *m;
377 	char *p, *p1;
378 	int n;
379 
380 #if 0
381 	lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
382 	for (n = 0; n < ctx->wildcount; n++)
383 		lwsl_notice("    %d\n", ctx->wild[n]);
384 #endif
385 
386 	if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
387 		uint32_t i[4];
388 #if defined(LWS_WITH_SERVER)
389 		const char *ss;
390 #endif
391 
392 		/* set the defaults for this vhost */
393 		a->reject_ws_with_no_protocol = 0;
394 		a->valid = 1;
395 		a->head = NULL;
396 		a->last = NULL;
397 
398 		i[0] = a->info->count_threads;
399 		i[1] = a->info->options & (
400 			LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME |
401 			LWS_SERVER_OPTION_LIBUV |
402 			LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
403 			LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
404 			LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN |
405 			LWS_SERVER_OPTION_LIBEVENT |
406 			LWS_SERVER_OPTION_LIBEV
407 				);
408 #if defined(LWS_WITH_SERVER)
409 		ss = a->info->server_string;
410 #endif
411 		i[3] = a->info->timeout_secs;
412 
413 		memset(a->info, 0, sizeof(*a->info));
414 
415 		a->info->count_threads = i[0];
416 		a->info->options = i[1];
417 #if defined(LWS_WITH_SERVER)
418 		a->info->server_string = ss;
419 #endif
420 		a->info->timeout_secs = i[3];
421 
422 		a->info->protocols = a->protocols;
423 		a->info->pprotocols = a->pprotocols;
424 #if defined(LWS_ROLE_WS)
425 		a->info->extensions = a->extensions;
426 #endif
427 #if defined(LWS_WITH_TLS)
428 #if defined(LWS_WITH_CLIENT)
429 		a->info->client_ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
430 			"ECDHE-RSA-AES256-GCM-SHA384:"
431 			"DHE-RSA-AES256-GCM-SHA384:"
432 			"ECDHE-RSA-AES256-SHA384:"
433 			"HIGH:!aNULL:!eNULL:!EXPORT:"
434 			"!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
435 			"!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
436 			"!DHE-RSA-AES128-SHA256:"
437 			"!AES128-GCM-SHA256:"
438 			"!AES128-SHA256:"
439 			"!DHE-RSA-AES256-SHA256:"
440 			"!AES256-GCM-SHA384:"
441 			"!AES256-SHA256";
442 #endif
443 #if defined(LWS_WITH_SERVER)
444 		a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
445 				       "ECDHE-RSA-AES256-GCM-SHA384:"
446 				       "DHE-RSA-AES256-GCM-SHA384:"
447 				       "ECDHE-RSA-AES256-SHA384:"
448 				       "HIGH:!aNULL:!eNULL:!EXPORT:"
449 				       "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
450 				       "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
451 				       "!DHE-RSA-AES128-SHA256:"
452 				       "!AES128-GCM-SHA256:"
453 				       "!AES128-SHA256:"
454 				       "!DHE-RSA-AES256-SHA256:"
455 				       "!AES256-GCM-SHA384:"
456 				       "!AES256-SHA256";
457 #endif
458 #endif
459 		a->info->keepalive_timeout = 5;
460 	}
461 
462 	if (reason == LEJPCB_OBJECT_START &&
463 	    ctx->path_match == LEJPVP_MOUNTS + 1) {
464 		a->fresh_mount = 1;
465 		memset(&a->m, 0, sizeof(a->m));
466 	}
467 
468 	/* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
469 	if (reason == LEJPCB_OBJECT_START &&
470 	    ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
471 		a->pvo = lwsws_align(a);
472 		a->p += sizeof(*a->pvo);
473 
474 		n = lejp_get_wildcard(ctx, 0, a->p, lws_ptr_diff(a->end, a->p));
475 		/* ie, enable this protocol, no options yet */
476 		a->pvo->next = a->info->pvo;
477 		a->info->pvo = a->pvo;
478 		a->pvo->name = a->p;
479 		lwsl_info("  adding protocol %s\n", a->p);
480 		a->p += n;
481 		a->pvo->value = a->p;
482 		a->pvo->options = NULL;
483 		goto dostring;
484 	}
485 
486 	/* this catches, eg, vhosts[].headers[].xxx */
487 	if ((reason == LEJPCB_VAL_STR_END || reason == LEJPCB_VAL_STR_CHUNK) &&
488 	    ctx->path_match == LEJPVP_HEADERS_NAME + 1) {
489 
490 		if (!a->chunk) {
491 			headers = lwsws_align(a);
492 			a->p += sizeof(*headers);
493 
494 			n = lejp_get_wildcard(ctx, 0, a->p,
495 					lws_ptr_diff(a->end, a->p));
496 			/* ie, add this header */
497 			headers->next = a->info->headers;
498 			a->info->headers = headers;
499 			headers->name = a->p;
500 
501 			lwsl_notice("  adding header %s=%s\n", a->p, ctx->buf);
502 			a->p += n - 1;
503 			*(a->p++) = ':';
504 			if (a->p < a->end)
505 				*(a->p++) = '\0';
506 			else
507 				*(a->p - 1) = '\0';
508 			headers->value = a->p;
509 			headers->options = NULL;
510 		}
511 		a->chunk = reason == LEJPCB_VAL_STR_CHUNK;
512 		goto dostring;
513 	}
514 
515 	if (reason == LEJPCB_OBJECT_END &&
516 	    (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
517 	    a->valid) {
518 
519 		struct lws_vhost *vhost;
520 
521 		//lwsl_notice("%s\n", ctx->path);
522 		if (!a->info->port &&
523 		    !(a->info->options & LWS_SERVER_OPTION_UNIX_SOCK)) {
524 			lwsl_err("Port required (eg, 443)\n");
525 			return 1;
526 		}
527 		a->valid = 0;
528 		a->info->mounts = a->head;
529 
530 		vhost = lws_create_vhost(a->context, a->info);
531 		if (!vhost) {
532 			lwsl_err("Failed to create vhost %s\n",
533 				 a->info->vhost_name);
534 			return 1;
535 		}
536 		a->any_vhosts = 1;
537 
538 		if (a->reject_ws_with_no_protocol) {
539 			a->reject_ws_with_no_protocol = 0;
540 
541 			vhost->default_protocol_index = 255;
542 		}
543 
544 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
545 		if (a->enable_client_ssl) {
546 			const char *cert_filepath =
547 					a->info->client_ssl_cert_filepath;
548 			const char *private_key_filepath =
549 				       a->info->client_ssl_private_key_filepath;
550 			const char *ca_filepath =
551 					a->info->client_ssl_ca_filepath;
552 			const char *cipher_list =
553 					a->info->client_ssl_cipher_list;
554 
555 			memset(a->info, 0, sizeof(*a->info));
556 			a->info->client_ssl_cert_filepath = cert_filepath;
557 			a->info->client_ssl_private_key_filepath =
558 							private_key_filepath;
559 			a->info->client_ssl_ca_filepath = ca_filepath;
560 			a->info->client_ssl_cipher_list = cipher_list;
561 			a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
562 			lws_init_vhost_client_ssl(a->info, vhost);
563 		}
564 #endif
565 
566 		return 0;
567 	}
568 
569 	if (reason == LEJPCB_OBJECT_END &&
570 	    ctx->path_match == LEJPVP_MOUNTS + 1) {
571 		static const char * const mount_protocols[] = {
572 			"http://",
573 			"https://",
574 			"file://",
575 			"cgi://",
576 			">http://",
577 			">https://",
578 			"callback://",
579 			"gzip://",
580 		};
581 
582 		if (!a->fresh_mount)
583 			return 0;
584 
585 		if (!a->m.mountpoint || !a->m.origin) {
586 			lwsl_err("mountpoint and origin required\n");
587 			return 1;
588 		}
589 		lwsl_debug("adding mount %s\n", a->m.mountpoint);
590 		m = lwsws_align(a);
591 		memcpy(m, &a->m, sizeof(*m));
592 		if (a->last)
593 			a->last->mount_next = m;
594 
595 		for (n = 0; n < (int)LWS_ARRAY_SIZE(mount_protocols); n++)
596 			if (!strncmp(a->m.origin, mount_protocols[n],
597 			     strlen(mount_protocols[n]))) {
598 				lwsl_info("----%s\n", a->m.origin);
599 				m->origin_protocol = (uint8_t)(unsigned int)n;
600 				m->origin = a->m.origin +
601 					    strlen(mount_protocols[n]);
602 				break;
603 			}
604 
605 		if (n == (int)LWS_ARRAY_SIZE(mount_protocols)) {
606 			lwsl_err("unsupported protocol:// %s\n", a->m.origin);
607 			return 1;
608 		}
609 
610 		a->p += sizeof(*m);
611 		if (!a->head)
612 			a->head = m;
613 
614 		a->last = m;
615 		a->fresh_mount = 0;
616 	}
617 
618 	/* we only match on the prepared path strings */
619 	if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
620 		return 0;
621 
622 	switch (ctx->path_match - 1) {
623 	case LEJPVP_NAME:
624 		a->info->vhost_name = a->p;
625 		break;
626 	case LEJPVP_PORT:
627 		a->info->port = atoi(ctx->buf);
628 		return 0;
629 	case LEJPVP_INTERFACE:
630 		a->info->iface = a->p;
631 		break;
632 	case LEJPVP_UNIXSKT:
633 		if (arg_to_bool(ctx->buf))
634 			a->info->options |= (uint64_t)LWS_SERVER_OPTION_UNIX_SOCK;
635 		else
636 			a->info->options &= (uint64_t)~(LWS_SERVER_OPTION_UNIX_SOCK);
637 		return 0;
638 	case LEJPVP_UNIXSKT_PERMS:
639 		a->info->unix_socket_perms = a->p;
640 		break;
641 	case LEJPVP_STS:
642 		if (arg_to_bool(ctx->buf))
643 			a->info->options |= (uint64_t)LWS_SERVER_OPTION_STS;
644 		else
645 			a->info->options &= (uint64_t)~(LWS_SERVER_OPTION_STS);
646 		return 0;
647 #if defined(LWS_WITH_TLS)
648 	case LEJPVP_HOST_SSL_KEY:
649 		a->info->ssl_private_key_filepath = a->p;
650 		break;
651 	case LEJPVP_HOST_SSL_CERT:
652 		a->info->ssl_cert_filepath = a->p;
653 		break;
654 	case LEJPVP_HOST_SSL_CA:
655 		a->info->ssl_ca_filepath = a->p;
656 		break;
657 #endif
658 	case LEJPVP_ACCESS_LOG:
659 		a->info->log_filepath = a->p;
660 		break;
661 	case LEJPVP_MOUNTPOINT:
662 		a->m.mountpoint = a->p;
663 		a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
664 		break;
665 	case LEJPVP_ORIGIN:
666 		if (!strncmp(ctx->buf, "callback://", 11))
667 			a->m.protocol = a->p + 11;
668 
669 		if (!a->m.origin)
670 			a->m.origin = a->p;
671 		break;
672 	case LEJPVP_DEFAULT:
673 		a->m.def = a->p;
674 		break;
675 	case LEJPVP_DEFAULT_AUTH_MASK:
676 		a->m.auth_mask = (unsigned int)atoi(ctx->buf);
677 		return 0;
678 	case LEJPVP_MOUNT_CACHE_MAX_AGE:
679 		a->m.cache_max_age = atoi(ctx->buf);
680 		return 0;
681 	case LEJPVP_MOUNT_CACHE_REUSE:
682 		a->m.cache_reusable = !!arg_to_bool(ctx->buf);
683 		return 0;
684 	case LEJPVP_MOUNT_CACHE_REVALIDATE:
685 		a->m.cache_revalidate = !!arg_to_bool(ctx->buf);
686 		return 0;
687 	case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
688 		a->m.cache_intermediaries = !!arg_to_bool(ctx->buf);;
689 		return 0;
690 	case LEJPVP_MOUNT_BASIC_AUTH:
691 #if defined(LWS_WITH_HTTP_BASIC_AUTH)
692 		a->m.basic_auth_login_file = a->p;
693 #endif
694 		break;
695 	case LEJPVP_CGI_TIMEOUT:
696 		a->m.cgi_timeout = atoi(ctx->buf);
697 		return 0;
698 	case LWJPVP_FO_LISTEN_QUEUE:
699 		a->info->fo_listen_queue = atoi(ctx->buf);
700 		return 0;
701 	case LEJPVP_KEEPALIVE_TIMEOUT:
702 		a->info->keepalive_timeout = atoi(ctx->buf);
703 		return 0;
704 #if defined(LWS_WITH_TLS)
705 #if defined(LWS_WITH_CLIENT)
706 	case LEJPVP_CLIENT_CIPHERS:
707 		a->info->client_ssl_cipher_list = a->p;
708 		break;
709 	case LEJPVP_CLIENT_TLS13_CIPHERS:
710 		a->info->client_tls_1_3_plus_cipher_list = a->p;
711 		break;
712 #endif
713 
714 	case LEJPVP_CIPHERS:
715 		a->info->ssl_cipher_list = a->p;
716 		break;
717 	case LEJPVP_TLS13_CIPHERS:
718 		a->info->tls1_3_plus_cipher_list = a->p;
719 		break;
720 	case LEJPVP_ECDH_CURVE:
721 		a->info->ecdh_curve = a->p;
722 		break;
723 #endif
724 	case LEJPVP_PMO:
725 	case LEJPVP_CGI_ENV:
726 		mp_cgienv = lwsws_align(a);
727 		a->p += sizeof(*a->m.cgienv);
728 
729 		mp_cgienv->next = a->m.cgienv;
730 		a->m.cgienv = mp_cgienv;
731 
732 		n = lejp_get_wildcard(ctx, 0, a->p, lws_ptr_diff(a->end, a->p));
733 		mp_cgienv->name = a->p;
734 		a->p += n;
735 		mp_cgienv->value = a->p;
736 		mp_cgienv->options = NULL;
737 		//lwsl_notice("    adding pmo / cgi-env '%s' = '%s'\n",
738 		//		mp_cgienv->name, mp_cgienv->value);
739 		goto dostring;
740 
741 	case LEJPVP_PROTOCOL_NAME_OPT:
742 		/* this catches, eg,
743 		 * vhosts[].ws-protocols[].xxx-protocol.yyy-option
744 		 * ie, these are options attached to a protocol with { }
745 		 */
746 		pvo = lwsws_align(a);
747 		a->p += sizeof(*a->pvo);
748 
749 		n = lejp_get_wildcard(ctx, 1, a->p, lws_ptr_diff(a->end, a->p));
750 		/* ie, enable this protocol, no options yet */
751 		pvo->next = a->pvo->options;
752 		a->pvo->options = pvo;
753 		pvo->name = a->p;
754 		a->p += n;
755 		pvo->value = a->p;
756 		pvo->options = NULL;
757 		break;
758 
759 	case LEJPVP_MOUNT_EXTRA_MIMETYPES:
760 		a->pvo_em = lwsws_align(a);
761 		a->p += sizeof(*a->pvo_em);
762 
763 		n = lejp_get_wildcard(ctx, 0, a->p, lws_ptr_diff(a->end, a->p));
764 		/* ie, enable this protocol, no options yet */
765 		a->pvo_em->next = a->m.extra_mimetypes;
766 		a->m.extra_mimetypes = a->pvo_em;
767 		a->pvo_em->name = a->p;
768 		lwsl_notice("  + extra-mimetypes %s -> %s\n", a->p, ctx->buf);
769 		a->p += n;
770 		a->pvo_em->value = a->p;
771 		a->pvo_em->options = NULL;
772 		break;
773 
774 	case LEJPVP_MOUNT_INTERPRET:
775 		a->pvo_int = lwsws_align(a);
776 		a->p += sizeof(*a->pvo_int);
777 
778 		n = lejp_get_wildcard(ctx, 0, a->p, lws_ptr_diff(a->end, a->p));
779 		/* ie, enable this protocol, no options yet */
780 		a->pvo_int->next = a->m.interpret;
781 		a->m.interpret = a->pvo_int;
782 		a->pvo_int->name = a->p;
783 		lwsl_notice("  adding interpret %s -> %s\n", a->p,
784 			    ctx->buf);
785 		a->p += n;
786 		a->pvo_int->value = a->p;
787 		a->pvo_int->options = NULL;
788 		break;
789 
790 	case LEJPVP_ENABLE_CLIENT_SSL:
791 		a->enable_client_ssl = !!arg_to_bool(ctx->buf);
792 		return 0;
793 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
794 	case LEJPVP_CLIENT_SSL_KEY:
795 		a->info->client_ssl_private_key_filepath = a->p;
796 		break;
797 	case LEJPVP_CLIENT_SSL_CERT:
798 		a->info->client_ssl_cert_filepath = a->p;
799 		break;
800 	case LEJPVP_CLIENT_SSL_CA:
801 		a->info->client_ssl_ca_filepath = a->p;
802 		break;
803 #endif
804 
805 	case LEJPVP_NOIPV6:
806 		set_reset_flag(&a->info->options, ctx->buf,
807 			       LWS_SERVER_OPTION_DISABLE_IPV6);
808 		return 0;
809 
810 	case LEJPVP_FLAG_ONLYRAW:
811 		set_reset_flag(&a->info->options, ctx->buf,
812 			    LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG);
813 		return 0;
814 
815 	case LEJPVP_IPV6ONLY:
816 		a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY;
817 		set_reset_flag(&a->info->options, ctx->buf,
818 			       LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
819 		return 0;
820 
821 	case LEJPVP_FLAG_CLIENT_CERT_REQUIRED:
822 		if (arg_to_bool(ctx->buf))
823 			a->info->options |=
824 			    LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
825 		return 0;
826 
827 	case LEJPVP_IGNORE_MISSING_CERT:
828 		set_reset_flag(&a->info->options, ctx->buf,
829 				LWS_SERVER_OPTION_IGNORE_MISSING_CERT);
830 		return 0;
831 
832 	case LEJPVP_FLAG_STRICT_HOST_CHECK:
833 		set_reset_flag(&a->info->options, ctx->buf,
834 			LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK);
835 		return 0;
836 
837 	case LEJPVP_ERROR_DOCUMENT_404:
838 		a->info->error_document_404 = a->p;
839 		break;
840 
841 #if defined(LWS_WITH_TLS)
842 	case LEJPVP_SSL_OPTION_SET:
843 		a->info->ssl_options_set |= atol(ctx->buf);
844 		return 0;
845 	case LEJPVP_SSL_OPTION_CLEAR:
846 		a->info->ssl_options_clear |= atol(ctx->buf);
847 		return 0;
848 
849 #if defined(LWS_WITH_CLIENT)
850 	case LEJPVP_SSL_CLIENT_OPTION_SET:
851 		a->info->ssl_client_options_set |= atol(ctx->buf);
852 		return 0;
853 	case LEJPVP_SSL_CLIENT_OPTION_CLEAR:
854 		a->info->ssl_client_options_clear |= atol(ctx->buf);
855 		return 0;
856 #endif
857 
858 	case LEJPVP_ALPN:
859 		a->info->alpn = a->p;
860 		break;
861 #endif
862 
863 	case LEJPVP_LISTEN_ACCEPT_ROLE:
864 		a->info->listen_accept_role = a->p;
865 		break;
866 	case LEJPVP_LISTEN_ACCEPT_PROTOCOL:
867 		a->info->listen_accept_protocol = a->p;
868 		break;
869 
870 	case LEJPVP_FLAG_APPLY_LISTEN_ACCEPT:
871 		set_reset_flag(&a->info->options, ctx->buf,
872 			LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG);
873 		return 0;
874 	case LEJPVP_FLAG_FALLBACK_LISTEN_ACCEPT:
875 		lwsl_notice("vh %s: LEJPVP_FLAG_FALLBACK_LISTEN_ACCEPT: %s\n",
876 			    a->info->vhost_name, ctx->buf);
877 		set_reset_flag(&a->info->options, ctx->buf,
878 		      LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG);
879 		return 0;
880 	case LEJPVP_FLAG_ALLOW_NON_TLS:
881 		set_reset_flag(&a->info->options, ctx->buf,
882 			       LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT);
883 		return 0;
884 	case LEJPVP_FLAG_REDIRECT_HTTP:
885 		set_reset_flag(&a->info->options, ctx->buf,
886 			       LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS);
887 		return 0;
888 	case LEJPVP_FLAG_ALLOW_HTTP_ON_HTTPS:
889 		set_reset_flag(&a->info->options, ctx->buf,
890 			       LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER);
891 		return 0;
892 
893 	case LEJPVP_FLAG_DISABLE_NO_PROTOCOL_WS_UPGRADES:
894 		a->reject_ws_with_no_protocol = 1;
895 		return 0;
896 
897 	case LEJPVP_FLAG_H2_HALF_CLOSED_LONG_POLL:
898 		set_reset_flag(&a->info->options, ctx->buf,
899 				LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL);
900 		return 0;
901 
902 	default:
903 		return 0;
904 	}
905 
906 dostring:
907 	p = ctx->buf;
908 	p[LEJP_STRING_CHUNK] = '\0';
909 	p1 = strstr(p, ESC_INSTALL_DATADIR);
910 	if (p1) {
911 		n = lws_ptr_diff(p1, p);
912 		if (n > a->end - a->p)
913 			n = lws_ptr_diff(a->end, a->p);
914 		lws_strncpy(a->p, p, (unsigned int)n + 1u);
915 		a->p += n;
916 		a->p += lws_snprintf(a->p, lws_ptr_diff_size_t(a->end, a->p), "%s",
917 				     LWS_INSTALL_DATADIR);
918 		p += n + (int)strlen(ESC_INSTALL_DATADIR);
919 	}
920 
921 	a->p += lws_snprintf(a->p, lws_ptr_diff_size_t(a->end, a->p), "%s", p);
922 	if (reason == LEJPCB_VAL_STR_END)
923 		*(a->p)++ = '\0';
924 
925 	return 0;
926 }
927 
928 /*
929  * returns 0 = OK, 1 = can't open, 2 = parsing error
930  */
931 
932 static int
lwsws_get_config(void * user,const char * f,const char * const * paths,int count_paths,lejp_callback cb)933 lwsws_get_config(void *user, const char *f, const char * const *paths,
934 		 int count_paths, lejp_callback cb)
935 {
936 	unsigned char buf[128];
937 	struct lejp_ctx ctx;
938 	int n, m = 0, fd;
939 
940 	fd = lws_open(f, O_RDONLY);
941 	if (fd < 0) {
942 		lwsl_err("Cannot open %s\n", f);
943 		return 2;
944 	}
945 	lwsl_info("%s: %s\n", __func__, f);
946 	lejp_construct(&ctx, cb, user, paths, (uint8_t)(unsigned int)count_paths);
947 
948 	do {
949 		n = (int)read(fd, buf, sizeof(buf));
950 		if (!n)
951 			break;
952 
953 		m = lejp_parse(&ctx, buf, n);
954 	} while (m == LEJP_CONTINUE);
955 
956 	close(fd);
957 	n = (int32_t)ctx.line;
958 	lejp_destruct(&ctx);
959 
960 	if (m < 0) {
961 		lwsl_err("%s(%u): parsing error %d: %s\n", f, n, m,
962 			 lejp_error_to_string(m));
963 		return 2;
964 	}
965 
966 	return 0;
967 }
968 
969 struct lws_dir_args {
970 	void *user;
971 	const char * const *paths;
972 	int count_paths;
973 	lejp_callback cb;
974 };
975 
976 static int
lwsws_get_config_d_cb(const char * dirpath,void * user,struct lws_dir_entry * lde)977 lwsws_get_config_d_cb(const char *dirpath, void *user,
978 		      struct lws_dir_entry *lde)
979 {
980 	struct lws_dir_args *da = (struct lws_dir_args *)user;
981 	char path[256];
982 
983 	if (lde->type != LDOT_FILE && lde->type != LDOT_UNKNOWN /* ZFS */)
984 		return 0;
985 
986 	lws_snprintf(path, sizeof(path) - 1, "%s/%s", dirpath, lde->name);
987 
988 	return lwsws_get_config(da->user, path, da->paths,
989 				da->count_paths, da->cb);
990 }
991 
992 int
lwsws_get_config_globals(struct lws_context_creation_info * info,const char * d,char ** cs,int * len)993 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
994 			 char **cs, int *len)
995 {
996 	struct lws_dir_args da;
997 	struct jpargs a;
998 #if defined(LWS_WITH_PLUGINS)
999 	const char * const *old = info->plugin_dirs;
1000 #endif
1001 	char dd[128];
1002 
1003 	memset(&a, 0, sizeof(a));
1004 
1005 	a.info = info;
1006 	a.p = *cs;
1007 	a.end = (a.p + *len) - 1;
1008 	a.valid = 0;
1009 
1010 	lwsws_align(&a);
1011 #if defined(LWS_WITH_PLUGINS)
1012 	info->plugin_dirs = (void *)a.p;
1013 #endif
1014 	a.plugin_dirs = (void *)a.p; /* writeable version */
1015 	a.p += MAX_PLUGIN_DIRS * sizeof(void *);
1016 
1017 #if defined(LWS_WITH_PLUGINS)
1018 	/* copy any default paths */
1019 
1020 	while (old && *old) {
1021 		a.plugin_dirs[a.count_plugin_dirs++] = *old;
1022 		old++;
1023 	}
1024 #endif
1025 
1026 	lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
1027 	if (lwsws_get_config(&a, dd, paths_global,
1028 			     LWS_ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
1029 		return 1;
1030 	lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
1031 
1032 	da.user = &a;
1033 	da.paths = paths_global;
1034 	da.count_paths = LWS_ARRAY_SIZE(paths_global),
1035 	da.cb = lejp_globals_cb;
1036 
1037 	if (lws_dir(dd, &da, lwsws_get_config_d_cb) > 1)
1038 		return 1;
1039 
1040 	a.plugin_dirs[a.count_plugin_dirs] = NULL;
1041 
1042 	*cs = a.p;
1043 	*len = lws_ptr_diff(a.end, a.p);
1044 
1045 	return 0;
1046 }
1047 
1048 int
lwsws_get_config_vhosts(struct lws_context * context,struct lws_context_creation_info * info,const char * d,char ** cs,int * len)1049 lwsws_get_config_vhosts(struct lws_context *context,
1050 			struct lws_context_creation_info *info, const char *d,
1051 			char **cs, int *len)
1052 {
1053 	struct lws_dir_args da;
1054 	struct jpargs a;
1055 	char dd[128];
1056 
1057 	memset(&a, 0, sizeof(a));
1058 
1059 	a.info = info;
1060 	a.p = *cs;
1061 	a.end = a.p + *len;
1062 	a.valid = 0;
1063 	a.context = context;
1064 	a.protocols = info->protocols;
1065 	a.pprotocols = info->pprotocols;
1066 #if defined(LWS_ROLE_WS)
1067 	a.extensions = info->extensions;
1068 #endif
1069 
1070 	lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
1071 	if (lwsws_get_config(&a, dd, paths_vhosts,
1072 			     LWS_ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
1073 		return 1;
1074 	lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
1075 
1076 	da.user = &a;
1077 	da.paths = paths_vhosts;
1078 	da.count_paths = LWS_ARRAY_SIZE(paths_vhosts),
1079 	da.cb = lejp_vhosts_cb;
1080 
1081 	if (lws_dir(dd, &da, lwsws_get_config_d_cb) > 1)
1082 		return 1;
1083 
1084 	*cs = a.p;
1085 	*len = lws_ptr_diff(a.end, a.p);
1086 
1087 	if (!a.any_vhosts) {
1088 		lwsl_err("Need at least one vhost\n");
1089 		return 1;
1090 	}
1091 
1092 //	lws_finalize_startup(context);
1093 
1094 	return 0;
1095 }
1096