lwsws redirect and correct vhost selection before accept
[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)(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 #ifndef _WIN32
349 static int filter(const struct dirent *ent)
350 {
351         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
352                 return 0;
353
354         return 1;
355 }
356 #endif
357
358 static int
359 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
360                    int count_paths, lejp_callback cb)
361 {
362 #ifndef _WIN32
363         struct dirent **namelist;
364         char path[256];
365         int n, i, ret = 0;
366
367         n = scandir(d, &namelist, filter, alphasort);
368         if (n < 0) {
369                 lwsl_err("Scandir on %d failed\n", d);
370         }
371
372         for (i = 0; i < n; i++) {
373                 snprintf(path, sizeof(path) - 1, "%s/%s", d,
374                          namelist[i]->d_name);
375                 ret = lwsws_get_config(user, path, paths, count_paths, cb);
376                 if (ret) {
377                         while (i++ < n)
378                                 free(namelist[i]);
379                         goto bail;
380                 }
381                 free(namelist[i]);
382         }
383
384 bail:
385         free(namelist);
386
387         return ret;
388 #else
389         return 0;
390 #endif
391 }
392
393 int
394 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
395                          char **cs, int *len)
396 {
397         struct jpargs a;
398
399         a.info = info;
400         a.p = *cs;
401         a.end = a.p + *len;
402         a.valid = 0;
403
404         if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_global,
405                              ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
406                 return 1;
407         if (lwsws_get_config_d(&a, d, paths_global,
408                                ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
409                 return 1;
410
411         *cs = a.p;
412         *len = a.end - a.p;
413
414         return 0;
415 }
416
417 int
418 lwsws_get_config_vhosts(struct lws_context *context,
419                         struct lws_context_creation_info *info, const char *d,
420                         char **cs, int *len)
421 {
422         struct jpargs a;
423
424         a.info = info;
425         a.p = *cs;
426         a.end = a.p + *len;
427         a.valid = 0;
428         a.context = context;
429         a.protocols = info->protocols;
430         a.extensions = info->extensions;
431
432         if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_vhosts,
433                              ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
434                 return 1;
435         if (lwsws_get_config_d(&a, d, paths_vhosts,
436                                ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
437                 return 1;
438
439         *cs = a.p;
440         *len = a.end - a.p;
441
442         lws_finalize_startup(context);
443
444         return 0;
445 }