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

Last change on this file since 400 was 400, checked in by Nishi, on Nov 3, 2024 at 2:19:42 PM

a

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