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 oHTTPDMaxConn,
00080 oHTTPDName,
00081 oClientTimeout,
00082 oCheckInterval,
00083 oWdctlSocket,
00084 oSyslogFacility,
00085 oFirewallRule,
00086 oFirewallRuleSet,
00087 oTrustedMACList
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 { "httpdmaxconn", oHTTPDMaxConn },
00106 { "httpdname", oHTTPDName },
00107 { "clienttimeout", oClientTimeout },
00108 { "checkinterval", oCheckInterval },
00109 { "syslogfacility", oSyslogFacility },
00110 { "wdctlsocket", oWdctlSocket },
00111 { "hostname", oAuthServHostname },
00112 { "sslavailable", oAuthServSSLAvailable },
00113 { "sslport", oAuthServSSLPort },
00114 { "httpport", oAuthServHTTPPort },
00115 { "path", oAuthServPath },
00116 { "firewallruleset", oFirewallRuleSet },
00117 { "firewallrule", oFirewallRule },
00118 { "trustedmaclist", oTrustedMACList },
00119 { NULL, oBadOption },
00120 };
00121
00122 static OpCodes config_parse_token(const char *cp, const char *filename, int linenum);
00123
00127 s_config *
00128 config_get_config(void)
00129 {
00130 return &config;
00131 }
00132
00134 void
00135 config_init(void)
00136 {
00137 debug(LOG_DEBUG, "Setting default config parameters");
00138 strncpy(config.configfile, DEFAULT_CONFIGFILE, sizeof(config.configfile));
00139 config.debuglevel = DEFAULT_DEBUGLEVEL;
00140 config.httpdmaxconn = DEFAULT_HTTPDMAXCONN;
00141 config.external_interface = NULL;
00142 config.gw_id = DEFAULT_GATEWAYID;
00143 config.gw_interface = NULL;
00144 config.gw_address = NULL;
00145 config.gw_port = DEFAULT_GATEWAYPORT;
00146 config.auth_servers = NULL;
00147 config.httpdname = NULL;
00148 config.clienttimeout = DEFAULT_CLIENTTIMEOUT;
00149 config.checkinterval = DEFAULT_CHECKINTERVAL;
00150 config.syslog_facility = DEFAULT_SYSLOG_FACILITY;
00151 config.daemon = -1;
00152 config.log_syslog = DEFAULT_LOG_SYSLOG;
00153 config.wdctl_sock = safe_strdup(DEFAULT_WDCTL_SOCK);
00154 config.internal_sock = safe_strdup(DEFAULT_INTERNAL_SOCK);
00155 config.rulesets = NULL;
00156 config.trustedmaclist = NULL;
00157 }
00158
00162 void
00163 config_init_override(void)
00164 {
00165 if (config.daemon == -1) config.daemon = DEFAULT_DAEMON;
00166 }
00167
00171 static OpCodes
00172 config_parse_token(const char *cp, const char *filename, int linenum)
00173 {
00174 int i;
00175
00176 for (i = 0; keywords[i].name; i++)
00177 if (strcasecmp(cp, keywords[i].name) == 0)
00178 return keywords[i].opcode;
00179
00180 debug(LOG_ERR, "%s: line %d: Bad configuration option: %s",
00181 filename, linenum, cp);
00182 return oBadOption;
00183 }
00184
00188 static void
00189 parse_auth_server(FILE *file, char *filename, int *linenum)
00190 {
00191 char *host = NULL,
00192 *path = NULL,
00193 line[MAX_BUF],
00194 *p1,
00195 *p2;
00196 int http_port,
00197 ssl_port,
00198 ssl_available,
00199 opcode;
00200 t_auth_serv *new,
00201 *tmp;
00202
00203
00204 path = safe_strdup(DEFAULT_AUTHSERVPATH);
00205 http_port = DEFAULT_AUTHSERVPORT;
00206 ssl_port = DEFAULT_AUTHSERVSSLPORT;
00207 ssl_available = DEFAULT_AUTHSERVSSLAVAILABLE;
00208
00209
00210 memset(line, 0, MAX_BUF);
00211 fgets(line, MAX_BUF - 1, file);
00212 (*linenum)++;
00213
00214
00215 while ((line[0] != '\0') && (strchr(line, '}') == NULL)) {
00216
00217 for (p1 = line; isblank(*p1); p1++);
00218
00219
00220 if ((p2 = strchr(p1, '#')) != NULL) {
00221 *p2 = '\0';
00222 } else if ((p2 = strchr(p1, '\r')) != NULL) {
00223 *p2 = '\0';
00224 } else if ((p2 = strchr(p1, '\n')) != NULL) {
00225 *p2 = '\0';
00226 }
00227
00228
00229 if (strlen(p1) > 0) {
00230 p2 = p1;
00231
00232 while ((*p2 != '\0') && (!isblank(*p2)))
00233 p2++;
00234
00235
00236 *p2 = '\0';
00237 p2++;
00238
00239
00240 while (isblank(*p2))
00241 p2++;
00242
00243
00244 opcode = config_parse_token(p1, filename, *linenum);
00245
00246 switch (opcode) {
00247 case oAuthServHostname:
00248 host = safe_strdup(p2);
00249 break;
00250 case oAuthServPath:
00251 free(path);
00252 path = safe_strdup(p2);
00253 break;
00254 case oAuthServSSLPort:
00255 ssl_port = atoi(p2);
00256 break;
00257 case oAuthServHTTPPort:
00258 http_port = atoi(p2);
00259 break;
00260 case oAuthServSSLAvailable:
00261 ssl_available = parse_boolean_value(p2);
00262 if (ssl_available < 0)
00263 ssl_available = 0;
00264 break;
00265 case oBadOption:
00266 default:
00267 debug(LOG_ERR, "Bad option on line %d "
00268 "in %s.", *linenum,
00269 filename);
00270 debug(LOG_ERR, "Exiting...");
00271 exit(-1);
00272 break;
00273 }
00274 }
00275
00276
00277 memset(line, 0, MAX_BUF);
00278 fgets(line, MAX_BUF - 1, file);
00279 (*linenum)++;
00280 }
00281
00282
00283 if (host == NULL)
00284 return;
00285
00286 debug(LOG_DEBUG, "Adding %s:%d (SSL: %d) %s to the auth server list",
00287 host, http_port, ssl_port, path);
00288
00289
00290 new = safe_malloc(sizeof(t_auth_serv));
00291
00292
00293 memset(new, 0, sizeof(t_auth_serv));
00294 new->authserv_hostname = host;
00295 new->authserv_use_ssl = ssl_available;
00296 new->authserv_path = path;
00297 new->authserv_http_port = http_port;
00298 new->authserv_ssl_port = ssl_port;
00299
00300
00301 if (config.auth_servers == NULL) {
00302 config.auth_servers = new;
00303 } else {
00304 for (tmp = config.auth_servers; tmp->next != NULL;
00305 tmp = tmp->next);
00306 tmp->next = new;
00307 }
00308
00309 debug(LOG_DEBUG, "Auth server added");
00310 }
00311
00321 #define TO_NEXT_WORD(s, e) do { \
00322 while (*s != '\0' && !isblank(*s)) { \
00323 s++; \
00324 } \
00325 if (*s != '\0') { \
00326 *s = '\0'; \
00327 s++; \
00328 while (isblank(*s)) \
00329 s++; \
00330 } else { \
00331 e = 1; \
00332 } \
00333 } while (0)
00334
00338 static void
00339 parse_firewall_ruleset(char *ruleset, FILE *file, char *filename, int *linenum)
00340 {
00341 char line[MAX_BUF],
00342 *p1,
00343 *p2;
00344 int opcode;
00345
00346 debug(LOG_DEBUG, "Adding Firewall Rule Set %s", ruleset);
00347
00348
00349 memset(line, 0, MAX_BUF);
00350 fgets(line, MAX_BUF - 1, file);
00351 (*linenum)++;
00352
00353
00354 while ((line[0] != '\0') && (strchr(line, '}') == NULL)) {
00355
00356 for (p1 = line; isblank(*p1); p1++);
00357
00358
00359 if ((p2 = strchr(p1, '#')) != NULL) {
00360 *p2 = '\0';
00361 } else if ((p2 = strchr(p1, '\r')) != NULL) {
00362 *p2 = '\0';
00363 } else if ((p2 = strchr(p1, '\n')) != NULL) {
00364 *p2 = '\0';
00365 }
00366
00367
00368 if (strlen(p1) > 0) {
00369 p2 = p1;
00370
00371 while ((*p2 != '\0') && (!isblank(*p2)))
00372 p2++;
00373
00374
00375 *p2 = '\0';
00376 p2++;
00377
00378
00379 while (isblank(*p2))
00380 p2++;
00381
00382
00383 opcode = config_parse_token(p1, filename, *linenum);
00384
00385 debug(LOG_DEBUG, "p1 = [%s]; p2 = [%s]", p1, p2);
00386
00387 switch (opcode) {
00388 case oFirewallRule:
00389 _parse_firewall_rule(ruleset, p2);
00390 break;
00391
00392 case oBadOption:
00393 default:
00394 debug(LOG_ERR, "Bad option on line %d "
00395 "in %s.", *linenum,
00396 filename);
00397 debug(LOG_ERR, "Exiting...");
00398 exit(-1);
00399 break;
00400 }
00401 }
00402
00403
00404 memset(line, 0, MAX_BUF);
00405 fgets(line, MAX_BUF - 1, file);
00406 (*linenum)++;
00407 }
00408
00409 debug(LOG_DEBUG, "Firewall Rule Set %s added.", ruleset);
00410 }
00411
00415 static int
00416 _parse_firewall_rule(char *ruleset, char *leftover)
00417 {
00418 int i;
00419 int block_allow = 0;
00420 int all_nums = 1;
00421 int finished = 0;
00422 char *token = NULL;
00423 char *port = NULL;
00424 char *protocol = NULL;
00425 char *mask = NULL;
00426 char *other_kw = NULL;
00427 t_firewall_ruleset *tmpr;
00428 t_firewall_ruleset *tmpr2;
00429 t_firewall_rule *tmp;
00430 t_firewall_rule *tmp2;
00431
00432 debug(LOG_DEBUG, "leftover: %s", leftover);
00433
00434
00435 for (i = 0; *(leftover + i) != '\0'
00436 && (*(leftover + i) = tolower(*(leftover + i))); i++);
00437
00438 token = leftover;
00439 TO_NEXT_WORD(leftover, finished);
00440
00441
00442 if (!strcasecmp(token, "block") || finished) {
00443 block_allow = 0;
00444 } else if (!strcasecmp(token, "allow")) {
00445 block_allow = 1;
00446 } else {
00447 debug(LOG_ERR, "Invalid rule type %s, expecting "
00448 "\"block\" or \"allow\"", token);
00449 return -1;
00450 }
00451
00452
00453
00454 if (strncmp(leftover, "tcp", 3) == 0
00455 || strncmp(leftover, "udp", 3) == 0
00456 || strncmp(leftover, "icmp", 4) == 0) {
00457 protocol = leftover;
00458 TO_NEXT_WORD(leftover, finished);
00459 }
00460
00461
00462 if (strncmp(leftover, "port", 4) == 0) {
00463 TO_NEXT_WORD(leftover, finished);
00464
00465 port = leftover;
00466 TO_NEXT_WORD(leftover, finished);
00467 for (i = 0; *(port + i) != '\0'; i++)
00468 if (!isdigit(*(port + i)))
00469 all_nums = 0;
00470 if (!all_nums) {
00471 debug(LOG_ERR, "Invalid port %s", port);
00472 return -3;
00473 }
00474 }
00475
00476
00477 if (!finished) {
00478
00479 other_kw = leftover;
00480 TO_NEXT_WORD(leftover, finished);
00481 if (strcmp(other_kw, "to") || finished) {
00482 debug(LOG_ERR, "Invalid or unexpected keyword %s, "
00483 "expecting \"to\"", other_kw);
00484 return -4;
00485 }
00486
00487
00488 mask = leftover;
00489 TO_NEXT_WORD(leftover, finished);
00490 all_nums = 1;
00491 for (i = 0; *(mask + i) != '\0'; i++)
00492 if (!isdigit(*(mask + i)) && (*(mask + i) != '.')
00493 && (*(mask + i) != '/'))
00494 all_nums = 0;
00495 if (!all_nums) {
00496 debug(LOG_ERR, "Invalid mask %s", mask);
00497 return -3;
00498 }
00499 }
00500
00501
00502 tmp = safe_malloc(sizeof(t_firewall_rule));
00503 memset((void *)tmp, 0, sizeof(t_firewall_rule));
00504 tmp->block_allow = block_allow;
00505 if (protocol != NULL)
00506 tmp->protocol = safe_strdup(protocol);
00507 if (port != NULL)
00508 tmp->port = safe_strdup(port);
00509 if (mask == NULL)
00510 tmp->mask = safe_strdup("0.0.0.0/0");
00511 else
00512 tmp->mask = safe_strdup(mask);
00513
00514 debug(LOG_DEBUG, "Adding Firewall Rule %s %s port %s to %s", token, tmp->protocol, tmp->port, tmp->mask);
00515
00516
00517 if (config.rulesets == NULL) {
00518 config.rulesets = safe_malloc(sizeof(t_firewall_ruleset));
00519 memset(config.rulesets, 0, sizeof(t_firewall_ruleset));
00520 config.rulesets->name = safe_strdup(ruleset);
00521 tmpr = config.rulesets;
00522 } else {
00523 tmpr2 = tmpr = config.rulesets;
00524 while (tmpr != NULL && (strcmp(tmpr->name, ruleset) != 0)) {
00525 tmpr2 = tmpr;
00526 tmpr = tmpr->next;
00527 }
00528 if (tmpr == NULL) {
00529
00530 tmpr = safe_malloc(sizeof(t_firewall_ruleset));
00531 memset(tmpr, 0, sizeof(t_firewall_ruleset));
00532 tmpr->name = safe_strdup(ruleset);
00533 tmpr2->next = tmpr;
00534 }
00535 }
00536
00537
00538 if (tmpr->rules == NULL) {
00539
00540 tmpr->rules = tmp;
00541 } else {
00542 tmp2 = tmpr->rules;
00543 while (tmp2->next != NULL)
00544 tmp2 = tmp2->next;
00545 tmp2->next = tmp;
00546 }
00547
00548 return 1;
00549 }
00550
00551 t_firewall_rule *
00552 get_ruleset(char *ruleset)
00553 {
00554 t_firewall_ruleset *tmp;
00555
00556 for (tmp = config.rulesets; tmp != NULL
00557 && strcmp(tmp->name, ruleset) != 0; tmp = tmp->next);
00558
00559 if (tmp == NULL)
00560 return NULL;
00561
00562 return(tmp->rules);
00563 }
00564
00568 void
00569 config_read(char *filename)
00570 {
00571 FILE *fd;
00572 char line[MAX_BUF], *s, *p1, *p2;
00573 int linenum = 0, opcode, value;
00574
00575 debug(LOG_INFO, "Reading configuration file '%s'", filename);
00576
00577 if (!(fd = fopen(filename, "r"))) {
00578 debug(LOG_ERR, "Could not open configuration file '%s', "
00579 "exiting...", filename);
00580 exit(1);
00581 }
00582
00583 while (!feof(fd) && fgets(line, MAX_BUF, fd)) {
00584 linenum++;
00585 s = line;
00586
00587 if (s[strlen(s) - 1] == '\n')
00588 s[strlen(s) - 1] = '\0';
00589
00590 if ((p1 = strchr(s, ' '))) {
00591 p1[0] = '\0';
00592 } else if ((p1 = strchr(s, '\t'))) {
00593 p1[0] = '\0';
00594 }
00595
00596 if (p1) {
00597 p1++;
00598
00599 if ((p2 = strchr(p1, ' '))) {
00600 p2[0] = '\0';
00601 } else if ((p2 = strstr(p1, "\r\n"))) {
00602 p2[0] = '\0';
00603 } else if ((p2 = strchr(p1, '\n'))) {
00604 p2[0] = '\0';
00605 }
00606 }
00607
00608 if (p1 && p1[0] != '\0') {
00609
00610
00611
00612 if ((strncmp(s, "#", 1)) != 0) {
00613 debug(LOG_DEBUG, "Parsing token: %s, "
00614 "value: %s", s, p1);
00615 opcode = config_parse_token(s, filename, linenum);
00616
00617 switch(opcode) {
00618 case oDaemon:
00619 if (config.daemon == -1 && ((value = parse_boolean_value(p1)) != -1)) {
00620 config.daemon = value;
00621 }
00622 break;
00623 case oExternalInterface:
00624 config.external_interface = safe_strdup(p1);
00625 break;
00626 case oGatewayID:
00627 config.gw_id = safe_strdup(p1);
00628 break;
00629 case oGatewayInterface:
00630 config.gw_interface = safe_strdup(p1);
00631 break;
00632 case oGatewayAddress:
00633 config.gw_address = safe_strdup(p1);
00634 break;
00635 case oGatewayPort:
00636 sscanf(p1, "%d", &config.gw_port);
00637 break;
00638 case oAuthServer:
00639 parse_auth_server(fd, filename,
00640 &linenum);
00641 break;
00642 case oFirewallRuleSet:
00643 parse_firewall_ruleset(p1, fd, filename, &linenum);
00644 break;
00645 case oTrustedMACList:
00646 parse_trusted_mac_list(p1);
00647 break;
00648 case oHTTPDName:
00649 config.httpdname = safe_strdup(p1);
00650 break;
00651 case oHTTPDMaxConn:
00652 sscanf(p1, "%d", &config.httpdmaxconn);
00653 break;
00654 case oBadOption:
00655 debug(LOG_ERR, "Bad option on line %d "
00656 "in %s.", linenum,
00657 filename);
00658 debug(LOG_ERR, "Exiting...");
00659 exit(-1);
00660 break;
00661 case oCheckInterval:
00662 sscanf(p1, "%d", &config.checkinterval);
00663 break;
00664 case oWdctlSocket:
00665 free(config.wdctl_sock);
00666 config.wdctl_sock = safe_strdup(p1);
00667 break;
00668 case oClientTimeout:
00669 sscanf(p1, "%d", &config.clienttimeout);
00670 break;
00671 case oSyslogFacility:
00672 sscanf(p1, "%d", &config.syslog_facility);
00673 break;
00674 }
00675 }
00676 }
00677 }
00678
00679 fclose(fd);
00680 }
00681
00685 static int
00686 parse_boolean_value(char *line)
00687 {
00688 if (strcasecmp(line, "yes") == 0) {
00689 return 1;
00690 }
00691 if (strcasecmp(line, "no") == 0) {
00692 return 0;
00693 }
00694 if (strcmp(line, "1") == 0) {
00695 return 1;
00696 }
00697 if (strcmp(line, "0") == 0) {
00698 return 0;
00699 }
00700
00701 return -1;
00702 }
00703
00704 void parse_trusted_mac_list(char *ptr) {
00705 char *ptrcopy = NULL;
00706 char *possiblemac = NULL;
00707 char *mac = NULL;
00708 t_trusted_mac *p = NULL;
00709
00710 debug(LOG_DEBUG, "Parsing string [%s] for trusted MAC addresses", ptr);
00711
00712 mac = safe_malloc(18);
00713
00714
00715 ptrcopy = safe_strdup(ptr);
00716
00717 while ((possiblemac = strsep(&ptrcopy, ", "))) {
00718 if (sscanf(possiblemac, " %17[A-Fa-f0-9:]", mac) == 1) {
00719
00720
00721 debug(LOG_DEBUG, "Adding MAC address [%s] to trusted list", mac);
00722
00723 if (config.trustedmaclist == NULL) {
00724 config.trustedmaclist = safe_malloc(sizeof(t_trusted_mac));
00725 config.trustedmaclist->mac = safe_strdup(mac);
00726 config.trustedmaclist->next = NULL;
00727 }
00728 else {
00729
00730 for (p = config.trustedmaclist; p->next != NULL; p = p->next);
00731 p->next = safe_malloc(sizeof(t_trusted_mac));
00732 p = p->next;
00733 p->mac = safe_strdup(mac);
00734 p->next = NULL;
00735 }
00736
00737 }
00738 }
00739
00740 free(ptrcopy);
00741
00742 free(mac);
00743
00744 }
00745
00747 void
00748 config_validate(void)
00749 {
00750 config_notnull(config.gw_interface, "GatewayInterface");
00751 config_notnull(config.auth_servers, "AuthServer");
00752
00753 if (missing_parms) {
00754 debug(LOG_ERR, "Configuration is not complete, exiting...");
00755 exit(-1);
00756 }
00757 }
00758
00762 static void
00763 config_notnull(void *parm, char *parmname)
00764 {
00765 if (parm == NULL) {
00766 debug(LOG_ERR, "%s is not set", parmname);
00767 missing_parms = 1;
00768 }
00769 }
00770
00774 t_auth_serv *
00775 get_auth_server(void)
00776 {
00777
00778
00779 return config.auth_servers;
00780 }
00781
00786 void
00787 mark_auth_server_bad(t_auth_serv *bad_server)
00788 {
00789 t_auth_serv *tmp;
00790
00791 if (config.auth_servers == bad_server && bad_server->next != NULL) {
00792
00793 for (tmp = config.auth_servers; tmp->next != NULL; tmp = tmp->next);
00794
00795 tmp->next = bad_server;
00796
00797 config.auth_servers = bad_server->next;
00798
00799 bad_server->next = NULL;
00800 }
00801
00802 }