ff4029d2af453dcca84165c057ca686bc545742d
[platform/upstream/libwebsockets.git] / lwsws / conf.c
1 /*
2  * libwebsockets web server application
3  *
4  * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation:
9  * version 2.1 of the License.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA  02110-1301  USA
20  */
21
22 #include "lwsws.h"
23
24 static const char * const paths_global[] = {
25         "global.uid",
26         "global.gid",
27         "global.interface",
28         "global.count-threads",
29         "global.init-ssl",
30 };
31
32 enum lejp_global_paths {
33         LEJPGP_UID,
34         LEJPGP_GID,
35         LEJPGP_INTERFACE,
36         LEJPGP_COUNT_THREADS,
37         LWJPGP_INIT_SSL,
38 };
39
40 static const char * const paths_vhosts[] = {
41         "vhosts[]",
42         "vhosts[].mounts[]",
43         "vhosts[].name",
44         "vhosts[].port",
45         "vhosts[].host-ssl-key",
46         "vhosts[].host-ssl-cert",
47         "vhosts[].host-ssl-ca",
48         "vhosts[].mounts[].mountpoint",
49         "vhosts[].mounts[].origin",
50         "vhosts[].mounts[].default",
51         "vhosts[].ws-protocols[].*.*",
52         "vhosts[].ws-protocols[].*",
53         "vhosts[].ws-protocols[]",
54 };
55
56 enum lejp_vhost_paths {
57         LEJPVP,
58         LEJPVP_MOUNTS,
59         LEJPVP_NAME,
60         LEJPVP_PORT,
61         LEJPVP_HOST_SSL_KEY,
62         LEJPVP_HOST_SSL_CERT,
63         LEJPVP_HOST_SSL_CA,
64         LEJPVP_MOUNTPOINT,
65         LEJPVP_ORIGIN,
66         LEJPVP_DEFAULT,
67         LEJPVP_PROTOCOL_NAME_OPT,
68         LEJPVP_PROTOCOL_NAME,
69         LEJPVP_PROTOCOL,
70 };
71
72 struct jpargs {
73         struct lws_context_creation_info *info;
74         struct lws_context *context;
75         const struct lws_protocols *protocols;
76         const struct lws_extension *extensions;
77         char *p, *end, valid;
78         struct lws_http_mount *head, *last;
79         char *mountpoint, *origin, *def;
80         struct lws_protocol_vhost_options *pvo;
81 };
82
83 static void *
84 lwsws_align(struct jpargs *a)
85 {
86         if ((unsigned long)(a->p) & 15)
87                 a->p += 16 - ((unsigned long)(a->p) & 15);
88
89         return a->p;
90 }
91
92 static int arg_to_bool(const char *s)
93 {
94         static const char * const on[] = { "on", "yes", "true" };
95         int n = atoi(s);
96
97         if (n)
98                 return 1;
99
100         for (n = 0; n < ARRAY_SIZE(on); n++)
101                 if (!strcasecmp(s, on[n]))
102                         return 1;
103
104         return 0;
105 }
106
107 static char
108 lejp_globals_cb(struct lejp_ctx *ctx, char reason)
109 {
110         struct jpargs *a = (struct jpargs *)ctx->user;
111
112         /* we only match on the prepared path strings */
113         if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
114                 return 0;
115
116         switch (ctx->path_match - 1) {
117         case LEJPGP_UID:
118                 a->info->uid = atoi(ctx->buf);
119                 return 0;
120         case LEJPGP_GID:
121                 a->info->gid = atoi(ctx->buf);
122                 return 0;
123         case LEJPGP_INTERFACE:
124                 a->info->iface = a->p;
125                 break;
126         case LEJPGP_COUNT_THREADS:
127                 a->info->count_threads = atoi(ctx->buf);
128                 return 0;
129         case LWJPGP_INIT_SSL:
130                 if (arg_to_bool(ctx->buf))
131                         a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
132                 return 0;
133
134         default:
135                 return 0;
136         }
137
138         a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
139
140         return 0;
141 }
142
143 static char
144 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
145 {
146         struct jpargs *a = (struct jpargs *)ctx->user;
147         struct lws_protocol_vhost_options *pvo;
148         struct lws_http_mount *m;
149         int n;
150
151 //      lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
152 //      for (n = 0; n < ctx->wildcount; n++)
153 //              lwsl_notice("    %d\n", ctx->wild[n]);
154
155         if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
156                 /* set the defaults for this vhost */
157                 a->valid = 1;
158                 a->head = NULL;
159                 a->last = NULL;
160                 a->info->port = 0;
161                 a->info->iface = NULL;
162                 a->info->protocols = a->protocols;
163                 a->info->extensions = a->extensions;
164                 a->info->ssl_cert_filepath = NULL;
165                 a->info->ssl_private_key_filepath = NULL;
166                 a->info->ssl_ca_filepath = NULL;
167                 a->info->timeout_secs = 5;
168                 a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
169                                        "ECDHE-RSA-AES256-GCM-SHA384:"
170                                        "DHE-RSA-AES256-GCM-SHA384:"
171                                        "ECDHE-RSA-AES256-SHA384:"
172                                        "HIGH:!aNULL:!eNULL:!EXPORT:"
173                                        "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
174                                        "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
175                                        "!DHE-RSA-AES128-SHA256:"
176                                        "!AES128-GCM-SHA256:"
177                                        "!AES128-SHA256:"
178                                        "!DHE-RSA-AES256-SHA256:"
179                                        "!AES256-GCM-SHA384:"
180                                        "!AES256-SHA256";
181                 a->info->pvo = NULL;
182         }
183
184         if (reason == LEJPCB_OBJECT_START &&
185             ctx->path_match == LEJPVP_MOUNTS + 1) {
186                 a->mountpoint = NULL;
187                 a->origin = NULL;
188                 a->def = NULL;
189         }
190
191         /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
192         if (reason == LEJPCB_OBJECT_START &&
193             ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
194                 a->pvo = lwsws_align(a);
195                 a->p += sizeof(*a->pvo);
196
197                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
198                 /* ie, enable this protocol, no options yet */
199                 a->pvo->next = a->info->pvo;
200                 a->info->pvo = a->pvo;
201                 a->pvo->name = a->p;
202                 lwsl_err("adding %s\n", a->p);
203                 a->p += n;
204                 a->pvo->value = a->p;
205                 a->pvo->options = NULL;
206                 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
207                 *(a->p)++ = '\0';
208         }
209
210         if (reason == LEJPCB_OBJECT_END &&
211             (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
212             a->valid) {
213
214                 //lwsl_notice("%s\n", ctx->path);
215                 if (!a->info->port) {
216                         lwsl_err("Port required (eg, 443)");
217                         return 1;
218                 }
219                 a->valid = 0;
220
221                 if (!lws_create_vhost(a->context, a->info, a->head)) {
222                         lwsl_err("Failed to create vhost %s\n",
223                                  a->info->vhost_name);
224                         return 1;
225                 }
226
227                 return 0;
228         }
229
230         if (reason == LEJPCB_OBJECT_END &&
231             ctx->path_match == LEJPVP_MOUNTS + 1) {
232                 if (!a->mountpoint || !a->origin) {
233                         lwsl_err("mountpoint and origin required\n");
234                         return 1;
235                 }
236
237                 n = lws_write_http_mount(a->last, &m, a->p, a->mountpoint,
238                                          a->origin, a->def);
239                 if (!n)
240                         return 1;
241                 a->p += n;
242                 if (!a->head)
243                         a->head = m;
244
245                 a->last = m;
246         }
247
248         /* we only match on the prepared path strings */
249         if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
250                 return 0;
251
252         switch (ctx->path_match - 1) {
253         case LEJPVP_NAME:
254                 a->info->vhost_name = a->p;
255                 break;
256         case LEJPVP_PORT:
257                 a->info->port = atoi(ctx->buf);
258                 return 0;
259         case LEJPVP_HOST_SSL_KEY:
260                 a->info->ssl_private_key_filepath = a->p;
261                 break;
262         case LEJPVP_HOST_SSL_CERT:
263                 a->info->ssl_cert_filepath = a->p;
264                 break;
265         case LEJPVP_HOST_SSL_CA:
266                 a->info->ssl_ca_filepath = a->p;
267                 break;
268         case LEJPVP_MOUNTPOINT:
269                 a->mountpoint = a->p;
270                 break;
271         case LEJPVP_ORIGIN:
272                 a->origin = a->p;
273                 break;
274         case LEJPVP_DEFAULT:
275                 a->def = a->p;
276                 break;
277
278         case LEJPVP_PROTOCOL_NAME_OPT:
279                 /* this catches, eg,
280                  * vhosts[].ws-protocols[].xxx-protocol.yyy-option
281                  * ie, these are options attached to a protocol with { }
282                  */
283                 pvo = lwsws_align(a);
284                 a->p += sizeof(*a->pvo);
285
286                 n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p);
287                 /* ie, enable this protocol, no options yet */
288                 pvo->next = a->pvo->options;
289                 a->pvo->options = pvo;
290                 pvo->name = a->p;
291                 a->p += n;
292                 pvo->value = a->p;
293                 pvo->options = NULL;
294                 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
295                 *(a->p)++ = '\0';
296                 break;
297
298         default:
299                 return 0;
300         }
301
302         a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
303         *(a->p)++ = '\0';
304
305         return 0;
306 }
307
308 /*
309  * returns 0 = OK, 1 = can't open, 2 = parsing error
310  */
311
312 static int
313 lwsws_get_config(void *user, const char *f, const char * const *paths,
314                  int count_paths, lejp_callback cb)
315 {
316         unsigned char buf[128];
317         struct lejp_ctx ctx;
318         int n, m, fd;
319
320         fd = open(f, O_RDONLY);
321         if (fd < 0) {
322                 lwsl_err("Cannot open %s\n", f);
323                 return 1;
324         }
325         lwsl_info("%s: %s\n", __func__, f);
326         lejp_construct(&ctx, cb, user, paths, count_paths);
327
328         do {
329                 n = read(fd, buf, sizeof(buf));
330                 if (!n)
331                         break;
332
333                 m = (int)(signed char)lejp_parse(&ctx, buf, n);
334         } while (m == LEJP_CONTINUE);
335
336         close(fd);
337         n = ctx.line;
338         lejp_destruct(&ctx);
339
340         if (m < 0) {
341                 lwsl_err("%s(%u): parsing error %d\n", f, n, m);
342                 return 2;
343         }
344
345         return 0;
346 }
347
348 #if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
349
350 static int
351 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
352                    int count_paths, lejp_callback cb)
353 {
354         uv_dirent_t dent;
355         uv_fs_t req;
356         char path[256];
357         int ret = 0;
358         uv_loop_t loop;
359
360         uv_loop_init(&loop);
361
362         if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
363                 lwsl_err("Scandir on %s failed\n", d);
364                 return 1;
365         }
366
367         while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
368                 snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
369                 ret = lwsws_get_config(user, path, paths, count_paths, cb);
370                 if (ret)
371                         goto bail;
372         }
373
374 bail:
375         uv_fs_req_cleanup(&req);
376         uv_loop_close(&loop);
377
378         return ret;
379 }
380
381 #else
382
383 #ifndef _WIN32
384 static int filter(const struct dirent *ent)
385 {
386         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
387                 return 0;
388
389         return 1;
390 }
391 #endif
392
393 static int
394 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
395                    int count_paths, lejp_callback cb)
396 {
397 #ifndef _WIN32
398         struct dirent **namelist;
399         char path[256];
400         int n, i, ret = 0;
401
402         n = scandir(d, &namelist, filter, alphasort);
403         if (n < 0) {
404                 lwsl_err("Scandir on %d failed\n", d);
405         }
406
407         for (i = 0; i < n; i++) {
408                 snprintf(path, sizeof(path) - 1, "%s/%s", d,
409                          namelist[i]->d_name);
410                 ret = lwsws_get_config(user, path, paths, count_paths, cb);
411                 if (ret) {
412                         while (i++ < n)
413                                 free(namelist[i]);
414                         goto bail;
415                 }
416                 free(namelist[i]);
417         }
418
419 bail:
420         free(namelist);
421
422         return ret;
423 #else
424         return 0;
425 #endif
426 }
427
428 #endif
429
430 int
431 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
432                          char **cs, int *len)
433 {
434         struct jpargs a;
435
436         a.info = info;
437         a.p = *cs;
438         a.end = a.p + *len;
439         a.valid = 0;
440
441         if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_global,
442                              ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
443                 return 1;
444         if (lwsws_get_config_d(&a, d, paths_global,
445                                ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
446                 return 1;
447
448         *cs = a.p;
449         *len = a.end - a.p;
450
451         return 0;
452 }
453
454 int
455 lwsws_get_config_vhosts(struct lws_context *context,
456                         struct lws_context_creation_info *info, const char *d,
457                         char **cs, int *len)
458 {
459         struct jpargs a;
460
461         a.info = info;
462         a.p = *cs;
463         a.end = a.p + *len;
464         a.valid = 0;
465         a.context = context;
466         a.protocols = info->protocols;
467         a.extensions = info->extensions;
468
469         if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_vhosts,
470                              ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
471                 return 1;
472         if (lwsws_get_config_d(&a, d, paths_vhosts,
473                                ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
474                 return 1;
475
476         *cs = a.p;
477         *len = a.end - a.p;
478
479         lws_finalize_startup(context);
480
481         return 0;
482 }