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

Last change on this file since 315 was 315, checked in by Nishi, on Oct 14, 2024 at 7:01:02 PM

wip

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