source: Main/trunk/Server/config.c@ 330

Last change on this file since 330 was 318, checked in by Nishi, on Oct 14, 2024 at 9:25:36 PM

fix

  • Property svn:keywords set to Id
File size: 16.0 KB
Line 
1/* $Id: config.c 318 2024-10-14 12:25:36Z nishi $ */
2
3#define SOURCE
4
5#include "../config.h"
6
7#include <stdio.h>
8#include <stdint.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/stat.h>
12
13#if !defined(_MSC_VER) && !defined(__BORLANDC__)
14#include <unistd.h>
15#endif
16
17#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && !defined(__OS2__) && !defined(__WATCOMC__))
18#ifdef USE_WINSOCK1
19#include <winsock.h>
20#else
21#include <winsock2.h>
22#endif
23#endif
24
25#include <cm_string.h>
26#include <cm_log.h>
27
28#ifdef __OS2__
29#include <types.h>
30#include <netinet/in.h>
31#include <tcpustd.h>
32#endif
33
34#include "tw_config.h"
35#include "tw_module.h"
36
37struct tw_config config;
38
39struct tw_config_entry* tw_vhost_match(const char* name, int port) {
40 int i;
41 for(i = 0; i < config.vhost_count; i++) {
42 if(strcmp(config.vhosts[i].name, name) == 0 && (config.vhosts[i].port == -1 ? 1 : config.vhosts[i].port == port)) {
43 return &config.vhosts[i];
44 }
45 }
46 return &config.root;
47}
48
49bool tw_permission_allowed(const char* path, SOCKADDR addr, struct tw_http_request req, struct tw_config_entry* vhost) {
50 int i;
51 bool found = false;
52 bool pathstart = false;
53 bool perm = false;
54again:
55 for(i = 0; i < vhost->dir_count; i++) {
56 char* noslash;
57 struct tw_dir_entry* e = &vhost->dirs[i];
58 pathstart = false;
59 if(strlen(path) >= strlen(e->dir)) {
60 int j;
61 pathstart = true;
62 for(j = 0; path[j] != 0 && e->dir[j] != 0; j++) {
63 if(path[j] != e->dir[j]) {
64 pathstart = false;
65 break;
66 }
67 }
68 }
69 noslash = cm_strdup(e->dir);
70 noslash[strlen(noslash) - 1] = 0;
71 if(strcmp(e->dir, path) == 0 || strcmp(noslash, path) == 0 || pathstart) {
72 found = true;
73 if(strcmp(e->name, "all") == 0) {
74 perm = e->type == TW_DIR_ALLOW;
75 }
76 }
77 free(noslash);
78 }
79 if(!found && vhost != &config.root) {
80 vhost = &config.root;
81 goto again;
82 }
83 return perm;
84}
85
86void tw_config_init(void) {
87 int i;
88 for(i = 0; i < MAX_PORTS + 1; i++) {
89 config.ports[i] = -1;
90 }
91 for(i = 0; i < MAX_VHOSTS; i++) {
92#ifndef NO_SSL
93 config.vhosts[i].sslkey = NULL;
94 config.vhosts[i].sslcert = NULL;
95#endif
96 config.vhosts[i].root = NULL;
97#ifdef HAS_CHROOT
98 config.vhosts[i].chroot_path = NULL;
99#endif
100 }
101#ifndef NO_SSL
102 config.root.sslkey = NULL;
103 config.root.sslcert = NULL;
104#endif
105 config.root.root = NULL;
106 config.root.mime_count = 0;
107 config.root.dir_count = 0;
108 config.root.icon_count = 0;
109 config.root.index_count = 0;
110 config.root.readme_count = 0;
111 config.root.hideport = 0;
112#ifdef HAS_CHROOT
113 config.root.chroot_path = NULL;
114#endif
115 config.vhost_count = 0;
116 config.module_count = 0;
117 config.extension = NULL;
118 config.server_root = cm_strdup(PREFIX);
119 config.server_admin = cm_strdup(SERVER_ADMIN);
120 config.defined[0] = NULL;
121#if defined(_PSP)
122 strcpy(config.hostname, "psp");
123#elif defined(__PPU__)
124 strcpy(config.hostname, "ps3");
125#elif defined(__ps2sdk__)
126 strcpy(config.hostname, "ps2");
127#elif defined(__NETWARE__)
128 strcpy(config.hostname, "netware");
129#else
130 gethostname(config.hostname, 1024);
131#endif
132#ifdef HAS_CHROOT
133 tw_add_define("HAS_CHROOT");
134#endif
135#ifndef NO_SSL
136 tw_add_define("HAS_SSL");
137#endif
138}
139
140int tw_config_read(const char* path) {
141 char cbuf[2];
142 int ln = 0;
143 int ifbr = 0;
144 int ignore = -1;
145 int portcount;
146 FILE* f;
147 cm_log("Config", "Reading %s", path);
148 f = fopen(path, "r");
149 cbuf[1] = 0;
150 if(f != NULL) {
151 char* line = malloc(1);
152 int stop = 0;
153 struct tw_config_entry* current = &config.root;
154 char* vhost = NULL;
155 char* dir = NULL;
156 line[0] = 0;
157 while(stop == 0) {
158 int c = fread(cbuf, 1, 1, f);
159 if(cbuf[0] == '\n' || c <= 0) {
160 char* l = cm_trim(line);
161 ln++;
162 if(strlen(l) > 0 && l[0] != '#') {
163 char** r = cm_split(l, " \t");
164 int i;
165 if(ignore != -1 && ifbr >= ignore) {
166 if(cm_strcaseequ(r[0], "EndIf")) ifbr--;
167 if(ifbr == 0) {
168 ignore = -1;
169 }
170 } else if(cm_strcaseequ(r[0], "Include") || cm_strcaseequ(r[0], "IncludeOptional")) {
171 for(i = 1; r[i] != NULL; i++) {
172 if(tw_config_read(r[i]) != 0 && cm_strcaseequ(r[0], "Include")) {
173 stop = 1;
174 break;
175 }
176 }
177 } else if(cm_strcaseequ(r[0], "Define")) {
178 if(r[1] == NULL) {
179 cm_log("Config", "Missing name at line %d", ln);
180 stop = 1;
181 } else {
182 tw_add_define(r[1]);
183 }
184 } else if(cm_strcaseequ(r[0], "Undefine")) {
185 if(r[1] == NULL) {
186 cm_log("Config", "Missing name at line %d", ln);
187 stop = 1;
188 } else {
189 tw_delete_define(r[1]);
190 }
191 } else if(cm_strcaseequ(r[0], "BeginDirectory")) {
192 if(dir != NULL) {
193 cm_log("Config", "Already in directory section at line %d", ln);
194 stop = 1;
195 } else {
196 if(r[1] == NULL) {
197 cm_log("Config", "Missing directory at line %d", ln);
198 stop = 1;
199 } else {
200 dir = cm_strcat(r[1], r[1][strlen(r[1]) - 1] == '/' ? "" : "/");
201 }
202 }
203 } else if(cm_strcaseequ(r[0], "EndDirectory")) {
204 if(dir == NULL) {
205 cm_log("Config", "Not in directory section at line %d", ln);
206 stop = 1;
207 } else {
208 free(dir);
209 dir = NULL;
210 }
211 } else if(cm_strcaseequ(r[0], "Allow")) {
212 if(dir == NULL) {
213 cm_log("Config", "Not in directory section at line %d", ln);
214 stop = 1;
215 } else {
216 if(r[1] == NULL) {
217 cm_log("Config", "Missing argument at line %d", ln);
218 stop = 1;
219 } else {
220 struct tw_dir_entry* e = &current->dirs[current->dir_count++];
221 e->name = cm_strdup(r[1]);
222 e->dir = cm_strdup(dir);
223 e->type = TW_DIR_ALLOW;
224 }
225 }
226 } else if(cm_strcaseequ(r[0], "Deny")) {
227 if(dir == NULL) {
228 cm_log("Config", "Not in directory section at line %d", ln);
229 stop = 1;
230 } else {
231 if(r[1] == NULL) {
232 cm_log("Config", "Missing argument at line %d", ln);
233 stop = 1;
234 } else {
235 struct tw_dir_entry* e = &current->dirs[current->dir_count++];
236 e->name = cm_strdup(r[1]);
237 e->dir = cm_strdup(dir);
238 e->type = TW_DIR_DENY;
239 }
240 }
241 } else if(cm_strcaseequ(r[0], "BeginVirtualHost")) {
242 if(vhost != NULL) {
243 cm_log("Config", "Already in virtual host section at line %d", ln);
244 stop = 1;
245 } else {
246 if(r[1] == NULL) {
247 cm_log("Config", "Missing virtual host at line %d", ln);
248 stop = 1;
249 } else {
250 int i;
251 vhost = cm_strdup(r[1]);
252 current = &config.vhosts[config.vhost_count++];
253 current->dir_count = 0;
254 current->mime_count = 0;
255 current->icon_count = 0;
256 current->index_count = 0;
257 current->readme_count = 0;
258 current->hideport = -1;
259 current->name = cm_strdup(vhost);
260 current->port = -1;
261 for(i = 0; vhost[i] != 0; i++) {
262 if(vhost[i] == ':') {
263 current->name[i] = 0;
264 current->port = atoi(current->name + i + 1);
265 break;
266 }
267 }
268 }
269 }
270 } else if(cm_strcaseequ(r[0], "EndVirtualHost")) {
271 if(vhost == NULL) {
272 cm_log("Config", "Not in virtual host section at line %d", ln);
273 stop = 1;
274 } else {
275 free(vhost);
276 vhost = NULL;
277 current = &config.root;
278 }
279 } else if(cm_strcaseequ(r[0], "Listen")
280#ifndef NO_SSL
281 || cm_strcaseequ(r[0], "ListenSSL")
282#endif
283 ) {
284 for(i = 1; r[i] != NULL; i++) {
285#if defined(_MSC_VER) || defined(__BORLANDC__)
286 uint32_t port = atoi(r[i]);
287#else
288 uint64_t port = atoi(r[i]);
289#endif
290 int j;
291 cm_log("Config", "Going to listen at port %d%s", (int)port, cm_strcaseequ(r[0], "ListenSSL") ? " with SSL" : "");
292#if defined(_MSC_VER) || defined(__BORLANDC__)
293 if(cm_strcaseequ(r[0], "ListenSSL")) port |= (1UL << 31);
294#else
295 if(cm_strcaseequ(r[0], "ListenSSL")) port |= (1ULL << 31);
296#endif
297 for(j = 0; config.ports[j] != -1; j++)
298 ;
299 config.ports[j] = port;
300 }
301 } else if(cm_strcaseequ(r[0], "HidePort")) {
302 current->hideport = 1;
303 } else if(cm_strcaseequ(r[0], "ShowPort")) {
304 current->hideport = 0;
305#ifndef NO_SSL
306 } else if(cm_strcaseequ(r[0], "SSLKey")) {
307 if(r[1] == NULL) {
308 cm_log("Config", "Missing path at line %d", ln);
309 stop = 1;
310 } else {
311 if(current->sslkey != NULL) free(current->sslkey);
312 current->sslkey = cm_strdup(r[1]);
313 }
314 } else if(cm_strcaseequ(r[0], "SSLCertificate")) {
315 if(r[1] == NULL) {
316 cm_log("Config", "Missing path at line %d", ln);
317 stop = 1;
318 } else {
319 if(current->sslcert != NULL) free(current->sslcert);
320 current->sslcert = cm_strdup(r[1]);
321 }
322#endif
323#ifdef HAS_CHROOT
324 } else if(cm_strcaseequ(r[0], "ChrootDirectory")) {
325 if(r[1] == NULL) {
326 cm_log("Config", "Missing path at line %d", ln);
327 stop = 1;
328 } else {
329 if(current->chroot_path != NULL) free(current->chroot_path);
330 current->chroot_path = cm_strdup(r[1]);
331 }
332#endif
333 } else if(cm_strcaseequ(r[0], "ForceLog")) {
334 if(r[1] == NULL) {
335 cm_log("Config", "Missing log at line %d", ln);
336 stop = 1;
337 } else {
338 cm_force_log(r[1]);
339 }
340 } else if(cm_strcaseequ(r[0], "EndIf")) {
341 if(ifbr == 0) {
342 cm_log("Config", "Missing BeginIf at line %d", ln);
343 stop = 1;
344 }
345 ifbr--;
346 } else if(cm_strcaseequ(r[0], "BeginIf") || cm_strcaseequ(r[0], "BeginIfNot")) {
347 if(r[1] == NULL) {
348 cm_log("Config", "Missing condition type at line %d", ln);
349 } else {
350 bool ign = false;
351 ifbr++;
352 if(cm_strcaseequ(r[1], "False")) {
353 ign = true;
354 } else if(cm_strcaseequ(r[1], "True")) {
355 } else if(cm_strcaseequ(r[1], "Defined")) {
356 if(r[2] == NULL) {
357 cm_log("Config", "Missing name at line %d", ln);
358 stop = 1;
359 } else {
360 int i;
361 bool fndit = false;
362 for(i = 0; config.defined[i] != NULL; i++) {
363 if(strcmp(config.defined[i], r[2]) == 0) {
364 fndit = true;
365 break;
366 }
367 }
368 if(!fndit) {
369 ign = true;
370 }
371 }
372 } else {
373 cm_log("Config", "Unknown condition type at line %d", ln);
374 stop = 1;
375 }
376 if(cm_strcaseequ(r[0], "BeginIfNot")) ign = !ign;
377 if(ign) {
378 ignore = ifbr - 1;
379 }
380 }
381 } else if(cm_strcaseequ(r[0], "ServerRoot")) {
382 if(r[1] == NULL) {
383 cm_log("Config", "Missing path at line %d", ln);
384 stop = 1;
385 } else {
386 chdir(r[1]);
387 free(config.server_root);
388 config.server_root = cm_strdup(r[1]);
389 }
390 } else if(cm_strcaseequ(r[0], "ServerAdmin")) {
391 if(r[1] == NULL) {
392 cm_log("Config", "Missing email at line %d", ln);
393 stop = 1;
394 } else {
395 free(config.server_admin);
396 config.server_admin = cm_strdup(r[1]);
397 }
398 } else if(cm_strcaseequ(r[0], "DocumentRoot")) {
399 if(r[1] == NULL) {
400 cm_log("Config", "Missing path at line %d", ln);
401 stop = 1;
402 } else {
403 if(current->root != NULL) free(current->root);
404 current->root = cm_strdup(strcmp(r[1], "/") == 0 ? "" : r[1]);
405 }
406 } else if(cm_strcaseequ(r[0], "MIMEType")) {
407 if(r[1] == NULL) {
408 cm_log("Config", "Missing extension at line %d", ln);
409 stop = 1;
410 } else if(r[2] == NULL) {
411 cm_log("Config", "Missing MIME at line %d", ln);
412 stop = 1;
413 } else {
414 struct tw_mime_entry* e = &current->mimes[current->mime_count++];
415 e->ext = cm_strdup(r[1]);
416 e->mime = cm_strdup(r[2]);
417 }
418 } else if(cm_strcaseequ(r[0], "MIMEFile")) {
419 if(r[1] == NULL) {
420 cm_log("Config", "Missing path at line %d", ln);
421 stop = 1;
422 } else {
423 FILE* mimefile = fopen(r[1], "r");
424 if(mimefile == NULL) {
425 cm_log("Config", "Could not load the file at line %d", ln);
426 stop = 1;
427 } else {
428 char* line = malloc(1);
429 int i;
430 struct stat st;
431 char* buf;
432 int incr = 0;
433 stat(r[1], &st);
434
435 buf = malloc(st.st_size + 1);
436 fread(buf, st.st_size, 1, mimefile);
437
438 for(i = 0;; i++) {
439 if(buf[i] == '\n' || buf[i] == 0) {
440 char oldc = buf[i];
441 char* line;
442 buf[i] = 0;
443
444 line = buf + incr;
445
446 if(strlen(line) > 0 && line[0] != '#') {
447 int j;
448 for(j = 0; line[j] != 0; j++) {
449 if(line[j] == ' ' || line[j] == '\t') {
450 line[j] = 0;
451 j++;
452 for(; line[j] != 0; j++) {
453 if(line[j] != ' ' && line[j] != '\t') {
454 char* name = line;
455 char* mimes = line + j;
456 int k = 0;
457 int incr2 = 0;
458 for(k = 0;; k++) {
459 if(mimes[k] == ' ' || mimes[k] == 0) {
460 char oldc2 = mimes[k];
461 struct tw_mime_entry* e;
462 mimes[k] = 0;
463
464 e = &current->mimes[current->mime_count++];
465 e->ext = cm_strcat(".", mimes + incr2);
466 e->mime = cm_strdup(name);
467 if(current->mime_count == MAX_MIME) {
468 cm_log("Config", "Too many MIME types, cannot handle");
469 stop = 1;
470 break;
471 }
472
473 incr2 = k + 1;
474 if(oldc2 == 0) break;
475 }
476 }
477 break;
478 }
479 }
480 break;
481 }
482 if(stop) break;
483 }
484 }
485
486 incr = i + 1;
487 if(oldc == 0) break;
488 }
489 }
490
491 free(buf);
492
493 fclose(mimefile);
494 }
495 }
496 } else if(cm_strcaseequ(r[0], "Icon")) {
497 if(r[1] == NULL) {
498 cm_log("Config", "Missing MIME at line %d", ln);
499 stop = 1;
500 } else if(r[2] == NULL) {
501 cm_log("Config", "Missing path at line %d", ln);
502 stop = 1;
503 } else {
504 struct tw_icon_entry* e = &current->icons[current->icon_count++];
505 e->mime = cm_strdup(r[1]);
506 e->icon = cm_strdup(r[2]);
507 }
508 } else if(cm_strcaseequ(r[0], "LoadModule")) {
509 for(i = 1; r[i] != NULL; i++) {
510 void* mod = tw_module_load(r[i]);
511 if(mod != NULL) {
512 config.modules[config.module_count++] = mod;
513 if(tw_module_init(mod) != 0) {
514 stop = 1;
515 break;
516 }
517 } else {
518 cm_log("Config", "Could not load the module at line %d", ln);
519 stop = 1;
520 break;
521 }
522 }
523 } else if(cm_strcaseequ(r[0], "DirectoryIndex")) {
524 for(i = 1; r[i] != NULL; i++) {
525 current->indexes[current->index_count++] = cm_strdup(r[i]);
526 }
527 } else if(cm_strcaseequ(r[0], "ReadmeFile") || cm_strcaseequ(r[0], "Readme")) {
528 if(cm_strcaseequ(r[0], "Readme")) {
529 cm_force_log("NOTE: Readme directive is deprecated.");
530 }
531 for(i = 1; r[i] != NULL; i++) {
532 current->readmes[current->readme_count++] = cm_strdup(r[i]);
533 }
534 } else {
535 stop = 1;
536 if(r[0] != NULL) {
537 int argc;
538 int i;
539 bool called = false;
540 struct tw_tool tools;
541 for(argc = 0; r[argc] != NULL; argc++)
542 ;
543 stop = 0;
544 tw_init_tools(&tools);
545 for(i = 0; i < config.module_count; i++) {
546 tw_mod_config_t mod_config = (tw_mod_config_t)tw_module_symbol(config.modules[i], "mod_config");
547 int resp;
548 if(mod_config != NULL && (resp = mod_config(&tools, r, argc)) == TW_CONFIG_PARSED) {
549 called = true;
550 break;
551 }
552 if(resp == TW_CONFIG_ERROR) {
553 stop = 1;
554 called = true;
555 break;
556 }
557 }
558 if(!called) {
559 cm_log("Config", "Unknown directive `%s' at line %d", r[0], ln);
560 stop = 1;
561 }
562 }
563 }
564 for(i = 0; r[i] != NULL; i++) free(r[i]);
565 free(r);
566 }
567 free(l);
568 free(line);
569 line = malloc(1);
570 line[0] = 0;
571 if(c <= 0) break;
572 } else if(cbuf[0] != '\r') {
573 char* tmp = line;
574 line = cm_strcat(tmp, cbuf);
575 free(tmp);
576 }
577 }
578 free(line);
579 fclose(f);
580 for(portcount = 0; config.ports[portcount] != -1; portcount++)
581 ;
582 if(portcount == 0) {
583 return 1;
584 } else {
585 return stop;
586 }
587 } else {
588 cm_log("Config", "Could not open the file");
589 return 1;
590 }
591}
Note: See TracBrowser for help on using the repository browser.