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

Last change on this file since 185 was 182, checked in by Nishi, on Sep 27, 2024 at 9:55:12 PM

psp

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