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
RevLine 
[4]1/* $Id: config.c 315 2024-10-14 10:01:02Z nishi $ */
2
[16]3#define SOURCE
4
[312]5#include "../config.h"
[4]6
7#include <stdio.h>
[7]8#include <stdint.h>
[4]9#include <stdlib.h>
10#include <string.h>
[257]11#include <sys/stat.h>
[315]12#include <errno.h>
[212]13
[215]14#if !defined(_MSC_VER) && !defined(__BORLANDC__)
[12]15#include <unistd.h>
[212]16#endif
[4]17
[312]18#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && !defined(__OS2__) && !defined(__WATCOMC__))
[240]19#ifdef USE_WINSOCK1
20#include <winsock.h>
21#else
[20]22#include <winsock2.h>
23#endif
[240]24#endif
[20]25
[4]26#include <cm_string.h>
27#include <cm_log.h>
28
[312]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
[6]38struct tw_config config;
39
[12]40struct tw_config_entry* tw_vhost_match(const char* name, int port) {
41 int i;
42 for(i = 0; i < config.vhost_count; i++) {
[13]43 if(strcmp(config.vhosts[i].name, name) == 0 && (config.vhosts[i].port == -1 ? 1 : config.vhosts[i].port == port)) {
[12]44 return &config.vhosts[i];
45 }
46 }
47 return &config.root;
48}
49
[22]50bool tw_permission_allowed(const char* path, SOCKADDR addr, struct tw_http_request req, struct tw_config_entry* vhost) {
[21]51 int i;
52 bool found = false;
53 bool pathstart = false;
54 bool perm = false;
55again:
[22]56 for(i = 0; i < vhost->dir_count; i++) {
[212]57 char* noslash;
[21]58 struct tw_dir_entry* e = &vhost->dirs[i];
59 pathstart = false;
[22]60 if(strlen(path) >= strlen(e->dir)) {
[212]61 int j;
[21]62 pathstart = true;
[22]63 for(j = 0; path[j] != 0 && e->dir[j] != 0; j++) {
64 if(path[j] != e->dir[j]) {
[21]65 pathstart = false;
66 break;
67 }
68 }
69 }
[212]70 noslash = cm_strdup(e->dir);
[21]71 noslash[strlen(noslash) - 1] = 0;
[22]72 if(strcmp(e->dir, path) == 0 || strcmp(noslash, path) == 0 || pathstart) {
[21]73 found = true;
[22]74 if(strcmp(e->name, "all") == 0) {
[21]75 perm = e->type == TW_DIR_ALLOW;
76 }
77 }
78 free(noslash);
79 }
[22]80 if(!found && vhost != &config.root) {
[21]81 vhost = &config.root;
82 goto again;
83 }
84 return perm;
85}
86
[7]87void tw_config_init(void) {
88 int i;
89 for(i = 0; i < MAX_PORTS + 1; i++) {
90 config.ports[i] = -1;
91 }
[12]92 for(i = 0; i < MAX_VHOSTS; i++) {
[156]93#ifndef NO_SSL
[12]94 config.vhosts[i].sslkey = NULL;
95 config.vhosts[i].sslcert = NULL;
[156]96#endif
[19]97 config.vhosts[i].root = NULL;
[156]98#ifdef HAS_CHROOT
99 config.vhosts[i].chroot_path = NULL;
100#endif
[12]101 }
[156]102#ifndef NO_SSL
[12]103 config.root.sslkey = NULL;
104 config.root.sslcert = NULL;
[156]105#endif
[19]106 config.root.root = NULL;
[21]107 config.root.mime_count = 0;
108 config.root.dir_count = 0;
[22]109 config.root.icon_count = 0;
[24]110 config.root.index_count = 0;
[33]111 config.root.readme_count = 0;
[123]112 config.root.hideport = 0;
[156]113#ifdef HAS_CHROOT
114 config.root.chroot_path = NULL;
115#endif
[12]116 config.vhost_count = 0;
[18]117 config.module_count = 0;
118 config.extension = NULL;
[17]119 config.server_root = cm_strdup(PREFIX);
[128]120 config.server_admin = cm_strdup(SERVER_ADMIN);
[156]121 config.defined[0] = NULL;
[187]122#if defined(_PSP)
[182]123 strcpy(config.hostname, "psp");
[187]124#elif defined(__PPU__)
125 strcpy(config.hostname, "ps3");
[189]126#elif defined(__ps2sdk__)
127 strcpy(config.hostname, "ps2");
[315]128#elif defined(__NETWARE__)
129 strcpy(config.hostname, "netware");
[182]130#else
[12]131 gethostname(config.hostname, 1024);
[182]132#endif
[161]133#ifdef HAS_CHROOT
134 tw_add_define("HAS_CHROOT");
135#endif
[174]136#ifndef NO_SSL
137 tw_add_define("HAS_SSL");
138#endif
[7]139}
[6]140
141int tw_config_read(const char* path) {
[4]142 char cbuf[2];
[6]143 int ln = 0;
[156]144 int ifbr = 0;
145 int ignore = -1;
[253]146 int portcount;
[212]147 FILE* f;
148 cm_log("Config", "Reading %s", path);
149 f = fopen(path, "r");
150 cbuf[1] = 0;
[6]151 if(f != NULL) {
[4]152 char* line = malloc(1);
[6]153 int stop = 0;
[12]154 struct tw_config_entry* current = &config.root;
[6]155 char* vhost = NULL;
[21]156 char* dir = NULL;
[212]157 line[0] = 0;
[6]158 while(stop == 0) {
[4]159 int c = fread(cbuf, 1, 1, f);
[6]160 if(cbuf[0] == '\n' || c <= 0) {
[212]161 char* l = cm_trim(line);
[6]162 ln++;
163 if(strlen(l) > 0 && l[0] != '#') {
[5]164 char** r = cm_split(l, " \t");
165 int i;
[156]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")) {
[6]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;
[5]176 }
177 }
[156]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 }
[21]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 }
[6]242 } else if(cm_strcaseequ(r[0], "BeginVirtualHost")) {
243 if(vhost != NULL) {
[12]244 cm_log("Config", "Already in virtual host section at line %d", ln);
[6]245 stop = 1;
246 } else {
247 if(r[1] == NULL) {
[12]248 cm_log("Config", "Missing virtual host at line %d", ln);
[6]249 stop = 1;
250 } else {
[212]251 int i;
[6]252 vhost = cm_strdup(r[1]);
[12]253 current = &config.vhosts[config.vhost_count++];
[21]254 current->dir_count = 0;
255 current->mime_count = 0;
[22]256 current->icon_count = 0;
[24]257 current->index_count = 0;
[33]258 current->readme_count = 0;
[123]259 current->hideport = -1;
[12]260 current->name = cm_strdup(vhost);
[13]261 current->port = -1;
[12]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 }
[6]269 }
270 }
271 } else if(cm_strcaseequ(r[0], "EndVirtualHost")) {
272 if(vhost == NULL) {
[12]273 cm_log("Config", "Not in virtual host section at line %d", ln);
[6]274 stop = 1;
275 } else {
276 free(vhost);
277 vhost = NULL;
[12]278 current = &config.root;
[6]279 }
[174]280 } else if(cm_strcaseequ(r[0], "Listen")
281#ifndef NO_SSL
282 || cm_strcaseequ(r[0], "ListenSSL")
283#endif
284 ) {
[7]285 for(i = 1; r[i] != NULL; i++) {
[215]286#if defined(_MSC_VER) || defined(__BORLANDC__)
[212]287 uint32_t port = atoi(r[i]);
288#else
[7]289 uint64_t port = atoi(r[i]);
[212]290#endif
291 int j;
[7]292 cm_log("Config", "Going to listen at port %d%s", (int)port, cm_strcaseequ(r[0], "ListenSSL") ? " with SSL" : "");
[215]293#if defined(_MSC_VER) || defined(__BORLANDC__)
[212]294 if(cm_strcaseequ(r[0], "ListenSSL")) port |= (1UL << 31);
295#else
296 if(cm_strcaseequ(r[0], "ListenSSL")) port |= (1ULL << 31);
297#endif
[7]298 for(j = 0; config.ports[j] != -1; j++)
299 ;
300 config.ports[j] = port;
301 }
[123]302 } else if(cm_strcaseequ(r[0], "HidePort")) {
303 current->hideport = 1;
304 } else if(cm_strcaseequ(r[0], "ShowPort")) {
305 current->hideport = 0;
[156]306#ifndef NO_SSL
[12]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 }
[156]323#endif
[161]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
[156]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 {
[212]351 bool ign = false;
[156]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 }
[61]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]);
[127]388 free(config.server_root);
389 config.server_root = cm_strdup(r[1]);
[61]390 }
[128]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 }
[19]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);
[21]405 current->root = cm_strdup(strcmp(r[1], "/") == 0 ? "" : r[1]);
[19]406 }
[21]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;
[22]411 } else if(r[2] == NULL) {
[21]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 }
[257]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 }
[22]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 }
[17]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) {
[18]513 config.modules[config.module_count++] = mod;
[17]514 if(tw_module_init(mod) != 0) {
515 stop = 1;
516 break;
517 }
518 } else {
[127]519 cm_log("Config", "Could not load the module at line %d", ln);
[17]520 stop = 1;
521 break;
522 }
523 }
[24]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 }
[178]528 } else if(cm_strcaseequ(r[0], "ReadmeFile") || cm_strcaseequ(r[0], "Readme")) {
[182]529 if(cm_strcaseequ(r[0], "Readme")) {
[178]530 cm_force_log("NOTE: Readme directive is deprecated.");
531 }
[33]532 for(i = 1; r[i] != NULL; i++) {
533 current->readmes[current->readme_count++] = cm_strdup(r[i]);
534 }
[6]535 } else {
[39]536 stop = 1;
[6]537 if(r[0] != NULL) {
[39]538 int argc;
[212]539 int i;
540 bool called = false;
541 struct tw_tool tools;
[39]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 }
[6]563 }
[5]564 }
565 for(i = 0; r[i] != NULL; i++) free(r[i]);
566 free(r);
[4]567 }
568 free(l);
569 free(line);
570 line = malloc(1);
571 line[0] = 0;
572 if(c <= 0) break;
[6]573 } else if(cbuf[0] != '\r') {
[4]574 char* tmp = line;
575 line = cm_strcat(tmp, cbuf);
576 free(tmp);
577 }
578 }
579 free(line);
580 fclose(f);
[255]581 for(portcount = 0; config.ports[portcount] != -1; portcount++)
582 ;
583 if(portcount == 0) {
[253]584 return 1;
[255]585 } else {
[253]586 return stop;
587 }
[6]588 } else {
[315]589 printf("%d\n", errno);
[5]590 cm_log("Config", "Could not open the file");
[4]591 return 1;
592 }
593}
Note: See TracBrowser for help on using the repository browser.