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

Last change on this file since 408 was 402, checked in by Nishi, on Nov 3, 2024 at 7:39:59 PM

amiga

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