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

Last change on this file since 276 was 257, checked in by Nishi, on Oct 4, 2024 at 2:34:27 PM

[release 2.04] can read mime.types from apache

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