Deprecate deny.c
[MonkeyD.git] / src / config.c
blobbde7e1744aee4b476df4c6a533741d8fe2b2d448
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
3 /* Monkey HTTP Daemon
4 * ------------------
5 * Copyright (C) 2001-2003, Eduardo Silva P.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <dirent.h>
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <fcntl.h>
33 #include "monkey.h"
34 #include "config.h"
35 #include "str.h"
36 #include "utils.h"
37 #include "mimetype.h"
38 #include "info.h"
39 #include "logfile.h"
40 #include "memory.h"
41 #include "cgi.h"
42 #include "plugin.h"
44 struct mk_config *mk_config_create(char *path)
46 FILE *f;
47 int len;
48 char buf[255];
49 char *key=0, *val=0, *last=0;
50 struct mk_config *cnf=0, *new, *p;
52 if((f=fopen(path, "r")) == NULL) {
53 fprintf(stderr, "\nConfig Error: I can't open %s file\n\n", path);
54 exit(1);
57 /* looking for configuration directives */
58 while(fgets(buf, 255, f)){
59 len = strlen(buf);
60 if(buf[len-1] == '\n') {
61 buf[--len] = 0;
62 if(len && buf[len-1] == '\r')
63 buf[--len] = 0;
66 if(!buf[0] || buf[0] == '#')
67 continue;
69 key = strtok_r(buf, "\"\t ", &last);
70 val = strtok_r(NULL, "\"\t ", &last);
72 if(!key || !val){
73 continue;
76 /* Allow new entry found */
77 new = mk_mem_malloc(sizeof(struct mk_config));
78 new->key = mk_string_dup(key);
79 new->val = mk_string_dup(val);
80 new->next = NULL;
82 /* Link to main list */
83 if(!cnf){
84 cnf = new;
86 else{
87 p = cnf;
88 while(p->next){
89 p = p->next;
91 p->next = new;
95 fclose(f);
96 return cnf;
99 void mk_config_free(struct mk_config *cnf)
101 struct mk_config *prev=0, *target;
103 target = cnf;
104 while(target){
105 while(target->next){
106 prev = target;
107 target = target->next;
110 mk_mem_free(target);
112 if(target == cnf){
113 return;
115 prev->next = NULL;
116 target = cnf;
120 void *mk_config_getval(struct mk_config *cnf, char *key, int mode)
122 int on, off;
123 struct mk_config *p;
125 p = cnf;
126 while(p){
127 if(strcasecmp(p->key, key) == 0){
128 switch(mode){
129 case MK_CONFIG_VAL_STR:
130 return (void *) p->val;
131 case MK_CONFIG_VAL_NUM:
132 return (void *) atoi(p->val);
133 case MK_CONFIG_VAL_BOOL:
134 on = strcasecmp(p->val, VALUE_ON);
135 off = strcasecmp(p->val,VALUE_OFF);
137 if(on!=0 && off!=0){
138 return (void *) -1;
140 else if(on>=0){
141 return (void *) VAR_ON;
143 else{
144 return (void *) VAR_OFF;
148 else{
149 p = p->next;
152 return NULL;
155 /* Read configuration files */
156 void mk_config_read_files(char *path_conf, char *file_conf)
158 unsigned long len;
159 char *path=0;
160 char *last=0;
161 struct stat checkdir;
162 struct mk_config *cnf;
164 config->serverconf = mk_string_dup(path_conf);
165 config->workers = MK_WORKERS_DEFAULT;
167 if(stat(config->serverconf, &checkdir)==-1){
168 fprintf(stderr, "ERROR: Invalid path to configuration files.");
169 exit(1);
172 m_build_buffer(&path, &len, "%s/%s", path_conf, file_conf);
174 cnf = mk_config_create(path);
176 /* Connection port */
177 config->serverport = (int) mk_config_getval(cnf,
178 "Port",
179 MK_CONFIG_VAL_NUM);
180 if(!config->serverport>=1 && !config->serverport<=65535){
181 mk_config_print_error_msg("Port", path);
184 /* Number of thread workers */
185 config->workers = (int) mk_config_getval(cnf,
186 "Workers",
187 MK_CONFIG_VAL_NUM);
188 if(config->maxclients < 1){
189 mk_config_print_error_msg("Workers", path);
192 /* Timeout */
193 config->timeout = (int) mk_config_getval(cnf,
194 "Timeout",
195 MK_CONFIG_VAL_NUM);
196 if(config->timeout < 1){
197 mk_config_print_error_msg("Timeout", path);
200 /* KeepAlive */
201 config->keep_alive = (int) mk_config_getval(cnf,
202 "KeepAlive",
203 MK_CONFIG_VAL_BOOL);
204 if(config->keep_alive == VAR_ERR){
205 mk_config_print_error_msg("KeepAlive", path);
208 /* MaxKeepAliveRequest */
209 config->max_keep_alive_request = (int) mk_config_getval(cnf,
210 "MaxKeepAliveRequest",
211 MK_CONFIG_VAL_NUM);
212 if(config->max_keep_alive_request == 0){
213 mk_config_print_error_msg("MaxKeepAliveRequest", path);
216 /* KeepAliveTimeout */
217 config->keep_alive_timeout = (int) mk_config_getval(cnf,
218 "KeepAliveTimeout",
219 MK_CONFIG_VAL_NUM);
220 if(config->keep_alive_timeout == 0){
221 mk_config_print_error_msg("KeepAliveTimeout", path);
224 /* Pid File */
225 config->pid_file_path = mk_config_getval(cnf,
226 "PidFile",
227 MK_CONFIG_VAL_STR);
229 /* Home user's directory /~ */
230 config->user_dir = mk_config_getval(cnf, "UserDir", MK_CONFIG_VAL_STR);
232 /* Index files */
233 char *index, *aux;
234 aux = index = mk_config_getval(cnf, "Indexfile", MK_CONFIG_VAL_STR);
235 while(aux!=NULL) {
236 mk_config_add_index(aux);
237 aux=strtok_r(NULL,"\"\t ", &last);
240 /* HideVersion Variable */
241 config->hideversion = (int) mk_config_getval(cnf,
242 "HideVersion",
243 MK_CONFIG_VAL_BOOL);
244 if(config->hideversion == VAR_ERR){
245 mk_config_print_error_msg("HideVersion", path);
248 /* User Variable */
249 config->user = mk_config_getval(cnf, "User", MK_CONFIG_VAL_STR);
251 /* Resume */
252 config->resume = (int) mk_config_getval(cnf,
253 "Resume",
254 MK_CONFIG_VAL_BOOL);
255 if(config->resume == VAR_ERR){
256 mk_config_print_error_msg("Resume", path);
259 /* Symbolic Links */
260 config->symlink = (int) mk_config_getval(cnf,
261 "SymLink",
262 MK_CONFIG_VAL_BOOL);
263 if(config->symlink == VAR_ERR){
264 mk_config_print_error_msg("SymLink", path);
268 /* Monkey Palm Servers */
269 char *palm;
270 palm = mk_config_getval(cnf, "Palm", MK_CONFIG_VAL_STR);
271 if(palm){
272 struct palm *new, *p;
273 last = palm;
274 new = mk_mem_malloc(sizeof(struct palm));
275 new->ext = strdup(strtok_r(NULL, "\"\t ", &last));
276 new->mimetype = strdup(strtok_r(NULL,"\"\t ", &last));
277 new->host = strdup(strtok_r(NULL,"\"\t ", &last));
278 new->port = atoi(strtok_r(NULL, "\"\t ", &last));
279 new->next = NULL;
281 if(!palms){
282 palms = new;
284 else{
285 p = palms;
286 while(p->next){
287 p = p->next;
289 p->next = palms;
293 mk_mem_free(path);
294 mk_config_free(cnf);
295 mk_config_read_hosts(path_conf);
298 void mk_config_read_hosts(char *path)
300 DIR *dir;
301 unsigned long len;
302 char *buf=0;
303 char *file;
304 struct host *p_host, *new_host; /* debug */
305 struct dirent *ent;
307 m_build_buffer(&buf, &len, "%s/sites/default", path);
308 config->hosts = mk_config_get_host(buf);
309 config->nhosts++;
310 mk_mem_free(buf);
312 if(!config->hosts)
314 printf("\nError parsing main configuration file 'default'\n");
315 exit(1);
318 m_build_buffer(&buf, &len, "%s/sites/", path);
319 if (!(dir = opendir(buf)))
320 exit(1);
323 p_host = config->hosts;
325 /* Reading content */
326 while ((ent = readdir(dir)) != NULL)
328 if (strcmp((char *) ent->d_name, "." ) == 0) continue;
329 if (strcmp((char *) ent->d_name, ".." ) == 0) continue;
330 if (strcasecmp((char *) ent->d_name, "default" ) == 0) continue;
332 m_build_buffer(&file, &len, "%s/sites/%s", path, ent->d_name);
334 new_host = (struct host *) mk_config_get_host(file);
335 mk_mem_free(file);
336 if(!new_host)
338 continue;
340 else{
341 p_host->next = new_host;
342 p_host = new_host;
343 config->nhosts++;
346 closedir(dir);
348 h = config->hosts;
349 while(h)
351 printf("*** HOST ***\n");
352 printf(" [servername]\t\t%s\n", h->servername);
353 printf(" [documentroot]\t\t%s\n", h->documentroot);
354 printf(" [conf file]\t\t%s\n", h->file);
355 printf(" [access log]\t\t%s\n", h->access_log_path);
356 printf(" [error log]\t\t%s\n", h->error_log_path);
357 printf(" [script alias]\t\t%s %s\n", h->scriptalias[0], h->scriptalias[1]);
358 printf(" [get dir]\t\t%i\n", h->getdir);
359 printf(" [header file]\t\t%s\n", h->header_file);
360 printf(" [footer file]\t\t%s\n\n", h->footer_file);
362 h = h->next;
364 fflush(stdout);
368 struct host *mk_config_get_host(char *path)
370 unsigned long len=0;
371 struct stat checkdir;
372 struct host *host;
373 struct mk_config *cnf;
375 cnf = mk_config_create(path);
377 host = mk_mem_malloc_z(sizeof(struct host));
378 host->servername = 0;
379 host->file = mk_string_dup(path);
381 host->servername = mk_config_getval(cnf, "Servername", MK_CONFIG_VAL_STR);
382 host->documentroot.data = mk_config_getval(cnf,
383 "DocumentRoot",
384 MK_CONFIG_VAL_STR);
385 host->documentroot.len = strlen(host->documentroot.data);
386 if(stat(host->documentroot.data, &checkdir)==-1) {
387 fprintf(stderr,
388 "ERROR: Invalid path to Server_root in %s\n\n",
389 path);
390 exit(1);
392 else if(!(checkdir.st_mode & S_IFDIR)) {
393 fprintf(stderr,
394 "ERROR: DocumentRoot variable in %s has an invalid directory path\n\n",
395 path);
396 exit(1);
399 /* Access log */
400 host->access_log_path = mk_config_getval(cnf,
401 "AccessLog",
402 MK_CONFIG_VAL_STR);
403 /* Error log */
404 host->error_log_path = mk_config_getval(cnf,
405 "ErrorLog",
406 MK_CONFIG_VAL_STR);
408 /* Get directory */
409 host->getdir = (int) mk_config_getval(cnf, "GetDir", MK_CONFIG_VAL_BOOL);
410 if(host->getdir == VAR_ERR){
411 mk_config_print_error_msg("GetDir", path);
414 if(!host->servername){
415 mk_config_free(cnf);
416 return NULL;
419 /* Server Signature */
420 if(config->hideversion==VAR_OFF){
421 m_build_buffer(&host->host_signature, &len,
422 "Monkey/%s Server (Host: %s, Port: %i)",
423 VERSION, host->servername, config->serverport);
425 else{
426 m_build_buffer(&host->host_signature, &len,
427 "Monkey Server (Host: %s, Port: %i)",
428 host->servername, config->serverport);
430 m_build_buffer(&host->header_host_signature.data,
431 &host->header_host_signature.len,
432 "Server: %s", host->host_signature);
434 if(pipe(host->log_access)<0){
435 perror("pipe");
438 if(pipe(host->log_error)<0){
439 perror("pipe");
442 fcntl(host->log_access[1], F_SETFL, O_NONBLOCK);
443 fcntl(host->log_error[1], F_SETFL, O_NONBLOCK);
445 host->next = NULL;
446 mk_config_free(cnf);
447 return host;
450 /* Imprime error de configuracion y cierra */
451 void mk_config_print_error_msg(char *variable, char *path)
453 fprintf(stderr, "\nError: %s variable in %s has an invalid value.\n", variable, path);
454 fflush(stderr);
455 exit(1);
458 /* Agrega distintos index.xxx */
459 void mk_config_add_index(char *indexname)
461 struct indexfile *new_index=0, *aux_index;
463 new_index = (struct indexfile *) malloc(sizeof(struct indexfile));
464 strncpy(new_index->indexname,indexname,MAX_INDEX_NOMBRE - 1);
465 new_index->indexname[MAX_INDEX_NOMBRE - 1]='\0';
466 new_index->next=NULL;
468 if(first_index==NULL) {
469 first_index=new_index;
471 else {
472 aux_index=first_index;
473 while(aux_index->next!=NULL)
474 aux_index=aux_index->next;
475 aux_index->next=new_index;
479 void mk_config_set_init_values(void)
481 /* Valores iniciales */
482 config->timeout=15;
483 config->hideversion=VAR_OFF;
484 config->keep_alive=VAR_ON;
485 config->keep_alive_timeout=15;
486 config->max_keep_alive_request=50;
487 config->maxclients=150;
488 config->max_ip = 15;
489 config->resume=VAR_ON;
490 config->standard_port=80;
491 config->serverport=2001;
492 config->symlink=VAR_OFF;
493 config->nhosts = 0;
494 config->user = NULL;
495 config->open_flags = O_RDONLY | O_NONBLOCK;
497 /* Plugins */
498 config->plugins = mk_mem_malloc_z(sizeof(struct plugin_stages));
501 /* read main configuration from monkey.conf */
502 void mk_config_start_configure(void)
504 unsigned long len;
506 mk_config_set_init_values();
507 mk_config_read_files(config->file_config, M_DEFAULT_CONFIG_FILE);
509 /* if not index names defined, set default */
510 if(first_index==NULL){
511 mk_config_add_index("index.html");
514 /* Load mimes */
515 mk_mimetype_read_config();
517 /* Basic server information */
518 if(config->hideversion==VAR_OFF)
520 m_build_buffer(&config->server_software.data,
521 &len, "Monkey/%s (%s)",VERSION,OS);
522 config->server_software.len = len;
524 else
526 m_build_buffer(&config->server_software.data, &len,
527 "Monkey Server");
528 config->server_software.len = len;
532 struct host *mk_config_host_find(mk_pointer host)
534 struct host *aux_host;
536 aux_host = config->hosts;
538 while(aux_host){
539 if(strncasecmp(aux_host->servername, host.data, host.len)==0)
540 break;
541 else
542 aux_host=aux_host->next;
545 return aux_host;
548 void mk_config_sanity_check()
550 /* Check O_NOATIME for current user, flag will just be used
551 * if running user is allowed to.
553 int fd, flags=config->open_flags;
555 flags |= O_NOATIME;
556 fd = open(config->file_config, flags);
558 if(fd > -1){
559 config->open_flags = flags;
560 close(fd);