00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #define _GNU_SOURCE
00028
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <syslog.h>
00032
00033 #include <pthread.h>
00034
00035 #include <string.h>
00036 #include <ctype.h>
00037
00038 #include "common.h"
00039 #include "safe.h"
00040 #include "debug.h"
00041 #include "conf.h"
00042 #include "http.h"
00043 #include "auth.h"
00044 #include "firewall.h"
00045
00046 #include "util.h"
00047
00050 static s_config config;
00051
00055 pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
00056
00060 static int missing_parms;
00061
00064 typedef enum {
00065 oBadOption,
00066 oDaemon,
00067 oDebugLevel,
00068 oExternalInterface,
00069 oGatewayID,
00070 oGatewayInterface,
00071 oGatewayAddress,
00072 oGatewayPort,
00073 oAuthServer,
00074 oAuthServHostname,
00075 oAuthServSSLAvailable,
00076 oAuthServSSLPort,
00077 oAuthServHTTPPort,
00078 oAuthServPath,
00079 oAuthServMaxTries,
00080 oHTTPDMaxConn,
00081 oHTTPDName,
00082 oClientTimeout,
00083 oCheckInterval,
00084 oWdctlSocket,
00085 oSyslogFacility,
00086 oFirewallRule,
00087 oFirewallRuleSet
00088 } OpCodes;
00089
00092 static const struct {
00093 const char *name;
00094 OpCodes opcode;
00095 int required;
00096 } keywords[] = {
00097 { "daemon", oDaemon },
00098 { "debuglevel", oDebugLevel },
00099 { "externalinterface", oExternalInterface },
00100 { "gatewayid", oGatewayID },
00101 { "gatewayinterface", oGatewayInterface },
00102 { "gatewayaddress", oGatewayAddress },
00103 { "gatewayport", oGatewayPort },
00104 { "authserver", oAuthServer },
00105 { "authservmaxtries", oAuthServMaxTries },
00106 { "httpdmaxconn", oHTTPDMaxConn },
00107 { "httpdname", oHTTPDName },
00108 { "clienttimeout", oClientTimeout },
00109 { "checkinterval", oCheckInterval },
00110 { "syslogfacility", oSyslogFacility },
00111 { "wdctlsocket", oWdctlSocket },
00112 { "hostname", oAuthServHostname },
00113 { "sslavailable", oAuthServSSLAvailable },
00114 { "sslport", oAuthServSSLPort },
00115 { "httpport", oAuthServHTTPPort },
00116 { "path", oAuthServPath },
00117 { "firewallruleset", oFirewallRuleSet },
00118 { "firewallrule", oFirewallRule },
00119 { NULL, oBadOption },
00120 };
00121
00122 static OpCodes config_parse_token(const char *cp, const char *filename, int linenum);
00123 static void config_notnull(void *parm, char *parmname);
00124 static int parse_boolean_value(char *);
00125 static void parse_auth_server(FILE *, char *, int *);
00126 static int parse_firewall_rule(char *ruleset, char *leftover);
00127 static void parse_firewall_ruleset(char *, FILE *, char *, int *);
00128
00132 s_config *
00133 config_get_config(void)
00134 {
00135 return &config;
00136 }
00137
00139 void
00140 config_init(void)
00141 {
00142 debug(LOG_DEBUG, "Setting default config parameters");
00143 strncpy(config.configfile, DEFAULT_CONFIGFILE, sizeof(config.configfile));
00144 config.debuglevel = DEFAULT_DEBUGLEVEL;
00145 config.httpdmaxconn = DEFAULT_HTTPDMAXCONN;
00146 config.external_interface = NULL;
00147 config.gw_id = DEFAULT_GATEWAYID;
00148 config.gw_interface = NULL;
00149 config.gw_address = NULL;
00150 config.gw_port = DEFAULT_GATEWAYPORT;
00151 config.auth_servers = NULL;
00152 config.authserv_maxtries = DEFAULT_AUTHSERVMAXTRIES;
00153 config.httpdname = NULL;
00154 config.clienttimeout = DEFAULT_CLIENTTIMEOUT;
00155 config.checkinterval = DEFAULT_CHECKINTERVAL;
00156 config.syslog_facility = DEFAULT_SYSLOG_FACILITY;
00157 config.daemon = -1;
00158 config.log_syslog = DEFAULT_LOG_SYSLOG;
00159 config.wdctl_sock = safe_strdup(DEFAULT_WDCTL_SOCK);
00160 config.rulesets = NULL;
00161 }
00162
00166 void
00167 config_init_override(void)
00168 {
00169 if (config.daemon == -1) config.daemon = DEFAULT_DAEMON;
00170 }
00171
00175 static OpCodes
00176 config_parse_token(const char *cp, const char *filename, int linenum)
00177 {
00178 int i;
00179
00180 for (i = 0; keywords[i].name; i++)
00181 if (strcasecmp(cp, keywords[i].name) == 0)
00182 return keywords[i].opcode;
00183
00184 debug(LOG_ERR, "%s: line %d: Bad configuration option: %s",
00185 filename, linenum, cp);
00186 return oBadOption;
00187 }
00188
00192 static void
00193 parse_auth_server(FILE *file, char *filename, int *linenum)
00194 {
00195 char *host = NULL,
00196 *path = NULL,
00197 line[MAX_BUF],
00198 *p1,
00199 *p2;
00200 int http_port,
00201 ssl_port,
00202 ssl_available,
00203 opcode;
00204 t_auth_serv *new,
00205 *tmp;
00206
00207
00208 path = safe_strdup(DEFAULT_AUTHSERVPATH);
00209 http_port = DEFAULT_AUTHSERVPORT;
00210 ssl_port = DEFAULT_AUTHSERVSSLPORT;
00211 ssl_available = DEFAULT_AUTHSERVSSLAVAILABLE;
00212
00213
00214 memset(line, 0, MAX_BUF);
00215 fgets(line, MAX_BUF - 1, file);
00216 (*linenum)++;
00217
00218
00219 while ((line[0] != '\0') && (strchr(line, '}') == NULL)) {
00220
00221 for (p1 = line; isblank(*p1); p1++);
00222
00223
00224 if ((p2 = strchr(p1, '#')) != NULL) {
00225 *p2 = '\0';
00226 } else if ((p2 = strchr(p1, '\r')) != NULL) {
00227 *p2 = '\0';
00228 } else if ((p2 = strchr(p1, '\n')) != NULL) {
00229 *p2 = '\0';
00230 }
00231
00232
00233 if (strlen(p1) > 0) {
00234 p2 = p1;
00235
00236 while ((*p2 != '\0') && (!isblank(*p2)))
00237 p2++;
00238
00239
00240 *p2 = '\0';
00241 p2++;
00242
00243
00244 while (isblank(*p2))
00245 p2++;
00246
00247
00248 opcode = config_parse_token(p1, filename, *linenum);
00249
00250 switch (opcode) {
00251 case oAuthServHostname:
00252 host = safe_strdup(p2);
00253 break;
00254 case oAuthServPath:
00255 free(path);
00256 path = safe_strdup(p2);
00257 break;
00258 case oAuthServSSLPort:
00259 ssl_port = atoi(p2);
00260 break;
00261 case oAuthServHTTPPort:
00262 http_port = atoi(p2);
00263 break;
00264 case oAuthServSSLAvailable:
00265 ssl_available = parse_boolean_value(p2);
00266 if (ssl_available < 0)
00267 ssl_available = 0;
00268 break;
00269 case oBadOption:
00270 default:
00271 debug(LOG_ERR, "Bad option on line %d "
00272 "in %s.", *linenum,
00273 filename);
00274 debug(LOG_ERR, "Exiting...");
00275 exit(-1);
00276 break;
00277 }
00278 }
00279
00280
00281 memset(line, 0, MAX_BUF);
00282 fgets(line, MAX_BUF - 1, file);
00283 (*linenum)++;
00284 }
00285
00286
00287 if (host == NULL)
00288 return;
00289
00290 debug(LOG_DEBUG, "Adding %s:%d (SSL: %d) %s to the auth server list",
00291 host, http_port, ssl_port, path);
00292
00293
00294 new = safe_malloc(sizeof(t_auth_serv));
00295
00296
00297 memset(new, 0, sizeof(t_auth_serv));
00298 new->authserv_hostname = host;
00299 new->authserv_use_ssl = ssl_available;
00300 new->authserv_path = path;
00301 new->authserv_http_port = http_port;
00302 new->authserv_ssl_port = ssl_port;
00303
00304
00305 if (config.auth_servers == NULL) {
00306 config.auth_servers = new;
00307 } else {
00308 for (tmp = config.auth_servers; tmp->next != NULL;
00309 tmp = tmp->next);
00310 tmp->next = new;
00311 }
00312
00313 debug(LOG_DEBUG, "Auth server added");
00314 }
00315
00325 #define TO_NEXT_WORD(s, e) do { \
00326 while (*s != '\0' && !isblank(*s)) { \
00327 s++; \
00328 } \
00329 if (*s != '\0') { \
00330 *s = '\0'; \
00331 s++; \
00332 while (isblank(*s)) \
00333 s++; \
00334 } else { \
00335 e = 1; \
00336 } \
00337 } while (0)
00338
00342 static void
00343 parse_firewall_ruleset(char *ruleset, FILE *file, char *filename, int *linenum)
00344 {
00345 char line[MAX_BUF],
00346 *p1,
00347 *p2;
00348 int opcode;
00349
00350 debug(LOG_DEBUG, "Adding Firewall Rule Set %s", ruleset);
00351
00352
00353 memset(line, 0, MAX_BUF);
00354 fgets(line, MAX_BUF - 1, file);
00355 (*linenum)++;
00356
00357
00358 while ((line[0] != '\0') && (strchr(line, '}') == NULL)) {
00359
00360 for (p1 = line; isblank(*p1); p1++);
00361
00362
00363 if ((p2 = strchr(p1, '#')) != NULL) {
00364 *p2 = '\0';
00365 } else if ((p2 = strchr(p1, '\r')) != NULL) {
00366 *p2 = '\0';
00367 } else if ((p2 = strchr(p1, '\n')) != NULL) {
00368 *p2 = '\0';
00369 }
00370
00371
00372 if (strlen(p1) > 0) {
00373 p2 = p1;
00374
00375 while ((*p2 != '\0') && (!isblank(*p2)))
00376 p2++;
00377
00378
00379 *p2 = '\0';
00380 p2++;
00381
00382
00383 while (isblank(*p2))
00384 p2++;
00385
00386
00387 opcode = config_parse_token(p1, filename, *linenum);
00388
00389 debug(LOG_DEBUG, "p1 = [%s]; p2 = [%s]", p1, p2);
00390
00391 switch (opcode) {
00392 case oFirewallRule:
00393 parse_firewall_rule(ruleset, p2);
00394 break;
00395
00396 case oBadOption:
00397 default:
00398 debug(LOG_ERR, "Bad option on line %d "
00399 "in %s.", *linenum,
00400 filename);
00401 debug(LOG_ERR, "Exiting...");
00402 exit(-1);
00403 break;
00404 }
00405 }
00406
00407
00408 memset(line, 0, MAX_BUF);
00409 fgets(line, MAX_BUF - 1, file);
00410 (*linenum)++;
00411 }
00412
00413 debug(LOG_DEBUG, "Firewall Rule Set %s added.", ruleset);
00414 }
00415
00416 static int
00417 parse_firewall_rule(char *ruleset, char *leftover)
00418 {
00419 int i;
00420 int block_allow = 0;
00421 int all_nums = 1;
00422 int finished = 0;
00423 char *token = NULL;
00424 char *port = NULL;
00425 char *protocol = NULL;
00426 char *mask = NULL;
00427 char *other_kw = NULL;
00428 t_firewall_ruleset *tmpr;
00429 t_firewall_ruleset *tmpr2;
00430 t_firewall_rule *tmp;
00431 t_firewall_rule *tmp2;
00432
00433 debug(LOG_DEBUG, "leftover: %s", leftover);
00434
00435
00436 for (i = 0; *(leftover + i) != '\0'
00437 && (*(leftover + i) = tolower(*(leftover + i))); i++);
00438
00439 token = leftover;
00440 TO_NEXT_WORD(leftover, finished);
00441
00442
00443 if (!strcasecmp(token, "block") || finished) {
00444 block_allow = 0;
00445 } else if (!strcasecmp(token, "allow")) {
00446 block_allow = 1;
00447 } else {
00448 debug(LOG_ERR, "Invalid rule type %s, expecting "
00449 "\"block\" or \"allow\"", token);
00450 return -1;
00451 }
00452
00453
00454
00455 if (strncmp(leftover, "tcp", 3) == 0
00456 || strncmp(leftover, "udp", 3) == 0
00457 || strncmp(leftover, "icmp", 4) == 0) {
00458 protocol = leftover;
00459 TO_NEXT_WORD(leftover, finished);
00460 }
00461
00462
00463 if (strncmp(leftover, "port", 4) == 0) {
00464 TO_NEXT_WORD(leftover, finished);
00465
00466 port = leftover;
00467 TO_NEXT_WORD(leftover, finished);
00468 for (i = 0; *(port + i) != '\0'; i++)
00469 if (!isdigit(*(port + i)))
00470 all_nums = 0;
00471 if (!all_nums) {
00472 debug(LOG_ERR, "Invalid port %s", port);
00473 return -3;
00474 }
00475 }
00476
00477
00478 if (!finished) {
00479
00480 other_kw = leftover;
00481 TO_NEXT_WORD(leftover, finished);
00482 if (strcmp(other_kw, "to") || finished) {
00483 debug(LOG_ERR, "Invalid or unexpected keyword %s, "
00484 "expecting \"to\"", other_kw);
00485 return -4;
00486 }
00487
00488
00489 mask = leftover;
00490 TO_NEXT_WORD(leftover, finished);
00491 all_nums = 1;
00492 for (i = 0; *(mask + i) != '\0'; i++)
00493 if (!isdigit(*(mask + i)) && (*(mask + i) != '.')
00494 && (*(mask + i) != '/'))
00495 all_nums = 0;
00496 if (!all_nums) {
00497 debug(LOG_ERR, "Invalid mask %s", mask);
00498 return -3;
00499 }
00500 }
00501
00502
00503 tmp = safe_malloc(sizeof(t_firewall_rule));
00504 memset((void *)tmp, 0, sizeof(t_firewall_rule));
00505 tmp->block_allow = block_allow;
00506 if (protocol != NULL)
00507 tmp->protocol = safe_strdup(protocol);
00508 if (port != NULL)
00509 tmp->port = safe_strdup(port);
00510 if (mask == NULL)
00511 tmp->mask = safe_strdup("0.0.0.0/0");
00512 else
00513 tmp->mask = safe_strdup(mask);
00514
00515 debug(LOG_DEBUG, "Adding Firewall Rule %s %s port %s to %s", token, tmp->protocol, tmp->port, tmp->mask);
00516
00517
00518 if (config.rulesets == NULL) {
00519 config.rulesets = safe_malloc(sizeof(t_firewall_ruleset));
00520 memset(config.rulesets, 0, sizeof(t_firewall_ruleset));
00521 config.rulesets->name = safe_strdup(ruleset);
00522 tmpr = config.rulesets;
00523 } else {
00524 tmpr2 = tmpr = config.rulesets;
00525 while (tmpr != NULL && (strcmp(tmpr->name, ruleset) != 0)) {
00526 tmpr2 = tmpr;
00527 tmpr = tmpr->next;
00528 }
00529 if (tmpr == NULL) {
00530
00531 tmpr = safe_malloc(sizeof(t_firewall_ruleset));
00532 memset(tmpr, 0, sizeof(t_firewall_ruleset));
00533 tmpr->name = safe_strdup(ruleset);
00534 tmpr2->next = tmpr;
00535 }
00536 }
00537
00538
00539 if (tmpr->rules == NULL) {
00540
00541 tmpr->rules = tmp;
00542 } else {
00543 tmp2 = tmpr->rules;
00544 while (tmp2->next != NULL)
00545 tmp2 = tmp2->next;
00546 tmp2->next = tmp;
00547 }
00548
00549 return 1;
00550 }
00551
00552 t_firewall_rule *
00553 get_ruleset(char *ruleset)
00554 {
00555 t_firewall_ruleset *tmp;
00556
00557 for (tmp = config.rulesets; tmp != NULL
00558 && strcmp(tmp->name, ruleset) != 0; tmp = tmp->next);
00559
00560 if (tmp == NULL)
00561 return NULL;
00562
00563 return(tmp->rules);
00564 }
00565
00569 void
00570 config_read(char *filename)
00571 {
00572 FILE *fd;
00573 char line[MAX_BUF], *s, *p1, *p2;
00574 int linenum = 0, opcode, value;
00575
00576 debug(LOG_INFO, "Reading configuration file '%s'", filename);
00577
00578 if (!(fd = fopen(filename, "r"))) {
00579 debug(LOG_ERR, "Could not open configuration file '%s', "
00580 "exiting...", filename);
00581 exit(1);
00582 }
00583
00584 while (!feof(fd) && fgets(line, MAX_BUF, fd)) {
00585 linenum++;
00586 s = line;
00587
00588 if (s[strlen(s) - 1] == '\n')
00589 s[strlen(s) - 1] = '\0';
00590
00591 if ((p1 = strchr(s, ' '))) {
00592 p1[0] = '\0';
00593 } else if ((p1 = strchr(s, '\t'))) {
00594 p1[0] = '\0';
00595 }
00596
00597 if (p1) {
00598 p1++;
00599
00600 if ((p2 = strchr(p1, ' '))) {
00601 p2[0] = '\0';
00602 } else if ((p2 = strstr(p1, "\r\n"))) {
00603 p2[0] = '\0';
00604 } else if ((p2 = strchr(p1, '\n'))) {
00605 p2[0] = '\0';
00606 }
00607 }
00608
00609 if (p1 && p1[0] != '\0') {
00610
00611
00612
00613 if ((strncmp(s, "#", 1)) != 0) {
00614 debug(LOG_DEBUG, "Parsing token: %s, "
00615 "value: %s", s, p1);
00616 opcode = config_parse_token(s, filename, linenum);
00617
00618 switch(opcode) {
00619 case oDaemon:
00620 if (config.daemon == -1 && ((value = parse_boolean_value(p1)) != -1)) {
00621 config.daemon = value;
00622 }
00623 break;
00624 case oExternalInterface:
00625 config.external_interface = safe_strdup(p1);
00626 break;
00627 case oGatewayID:
00628 config.gw_id = safe_strdup(p1);
00629 break;
00630 case oGatewayInterface:
00631 config.gw_interface = safe_strdup(p1);
00632 break;
00633 case oGatewayAddress:
00634 config.gw_address = safe_strdup(p1);
00635 break;
00636 case oGatewayPort:
00637 sscanf(p1, "%d", &config.gw_port);
00638 break;
00639 case oAuthServer:
00640 parse_auth_server(fd, filename,
00641 &linenum);
00642 break;
00643 case oFirewallRuleSet:
00644 parse_firewall_ruleset(p1, fd,
00645 filename, &linenum);
00646 break;
00647 case oHTTPDName:
00648 config.httpdname = safe_strdup(p1);
00649 break;
00650 case oHTTPDMaxConn:
00651 sscanf(p1, "%d", &config.httpdmaxconn);
00652 break;
00653 case oAuthServMaxTries:
00654 sscanf(p1, "%d", &config.authserv_maxtries);
00655 break;
00656 case oBadOption:
00657 debug(LOG_ERR, "Bad option on line %d "
00658 "in %s.", linenum,
00659 filename);
00660 debug(LOG_ERR, "Exiting...");
00661 exit(-1);
00662 break;
00663 case oCheckInterval:
00664 sscanf(p1, "%d", &config.checkinterval);
00665 break;
00666 case oWdctlSocket:
00667 free(config.wdctl_sock);
00668 config.wdctl_sock = safe_strdup(p1);
00669 break;
00670 case oClientTimeout:
00671 sscanf(p1, "%d", &config.clienttimeout);
00672 break;
00673 case oSyslogFacility:
00674 sscanf(p1, "%d", &config.syslog_facility);
00675 break;
00676 }
00677 }
00678 }
00679 }
00680
00681 fclose(fd);
00682 }
00683
00687 static int
00688 parse_boolean_value(char *line)
00689 {
00690 if (strcasecmp(line, "yes") == 0) {
00691 return 1;
00692 }
00693 if (strcasecmp(line, "no") == 0) {
00694 return 0;
00695 }
00696 if (strcmp(line, "1") == 0) {
00697 return 1;
00698 }
00699 if (strcmp(line, "0") == 0) {
00700 return 0;
00701 }
00702
00703 return -1;
00704 }
00705
00707 void
00708 config_validate(void)
00709 {
00710 config_notnull(config.gw_id, "GatewayID");
00711 config_notnull(config.gw_interface, "GatewayInterface");
00712 config_notnull(config.auth_servers, "AuthServer");
00713
00714 if (missing_parms) {
00715 debug(LOG_ERR, "Configuration is not complete, exiting...");
00716 exit(-1);
00717 }
00718 }
00719
00723 static void
00724 config_notnull(void *parm, char *parmname)
00725 {
00726 if (parm == NULL) {
00727 debug(LOG_ERR, "%s is not set", parmname);
00728 missing_parms = 1;
00729 }
00730 }
00731
00735 t_auth_serv *
00736 get_auth_server(void)
00737 {
00738
00739
00740 return config.auth_servers;
00741 }
00742
00747 void
00748 mark_auth_server_bad(t_auth_serv *bad_server)
00749 {
00750 t_auth_serv *tmp;
00751
00752 if (config.auth_servers == bad_server && bad_server->next != NULL) {
00753
00754 for (tmp = config.auth_servers; tmp->next != NULL; tmp = tmp->next);
00755
00756 tmp->next = bad_server;
00757
00758 config.auth_servers = bad_server->next;
00759
00760 bad_server->next = NULL;
00761 }
00762
00763 }