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 if ((strncmp(s, "#", 1)) != 0) {
00612 debug(LOG_DEBUG, "Parsing token: %s, "
00613 "value: %s", s, p1);
00614 opcode = config_parse_token(s, filename, linenum);
00615
00616 switch(opcode) {
00617 case oDaemon:
00618 if (config.daemon == -1 && ((value = parse_boolean_value(p1)) != -1)) {
00619 config.daemon = value;
00620 }
00621 break;
00622 case oExternalInterface:
00623 config.external_interface = safe_strdup(p1);
00624 break;
00625 case oGatewayID:
00626 config.gw_id = safe_strdup(p1);
00627 break;
00628 case oGatewayInterface:
00629 config.gw_interface = safe_strdup(p1);
00630 break;
00631 case oGatewayAddress:
00632 config.gw_address = safe_strdup(p1);
00633 break;
00634 case oGatewayPort:
00635 sscanf(p1, "%d", &config.gw_port);
00636 break;
00637 case oAuthServer:
00638 parse_auth_server(fd, filename,
00639 &linenum);
00640 break;
00641 case oFirewallRuleSet:
00642 parse_firewall_ruleset(p1, fd, filename, &linenum);
00643 break;
00644 case oTrustedMACList:
00645 parse_trusted_mac_list(p1);
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 oBadOption:
00654 debug(LOG_ERR, "Bad option on line %d "
00655 "in %s.", linenum,
00656 filename);
00657 debug(LOG_ERR, "Exiting...");
00658 exit(-1);
00659 break;
00660 case oCheckInterval:
00661 sscanf(p1, "%d", &config.checkinterval);
00662 break;
00663 case oWdctlSocket:
00664 free(config.wdctl_sock);
00665 config.wdctl_sock = safe_strdup(p1);
00666 break;
00667 case oClientTimeout:
00668 sscanf(p1, "%d", &config.clienttimeout);
00669 break;
00670 case oSyslogFacility:
00671 sscanf(p1, "%d", &config.syslog_facility);
00672 break;
00673 }
00674 }
00675 }
00676 }
00677
00678 fclose(fd);
00679 }
00680
00684 static int
00685 parse_boolean_value(char *line)
00686 {
00687 if (strcasecmp(line, "yes") == 0) {
00688 return 1;
00689 }
00690 if (strcasecmp(line, "no") == 0) {
00691 return 0;
00692 }
00693 if (strcmp(line, "1") == 0) {
00694 return 1;
00695 }
00696 if (strcmp(line, "0") == 0) {
00697 return 0;
00698 }
00699
00700 return -1;
00701 }
00702
00703 void parse_trusted_mac_list(char *ptr) {
00704 char *ptrcopy = NULL;
00705 char *possiblemac = NULL;
00706 char *mac = NULL;
00707 t_trusted_mac *p = NULL;
00708
00709 debug(LOG_DEBUG, "Parsing string [%s] for trusted MAC addresses", ptr);
00710
00711 mac = safe_malloc(18);
00712
00713
00714 ptrcopy = safe_strdup(ptr);
00715
00716 while ((possiblemac = strsep(&ptrcopy, ", "))) {
00717 if (sscanf(possiblemac, " %17[A-Fa-f0-9:]", mac) == 1) {
00718
00719
00720 debug(LOG_DEBUG, "Adding MAC address [%s] to trusted list", mac);
00721
00722 if (config.trustedmaclist == NULL) {
00723 config.trustedmaclist = safe_malloc(sizeof(t_trusted_mac));
00724 config.trustedmaclist->mac = safe_strdup(mac);
00725 config.trustedmaclist->next = NULL;
00726 }
00727 else {
00728
00729 for (p = config.trustedmaclist; p->next != NULL; p = p->next);
00730 p->next = safe_malloc(sizeof(t_trusted_mac));
00731 p = p->next;
00732 p->mac = safe_strdup(mac);
00733 p->next = NULL;
00734 }
00735
00736 }
00737 }
00738
00739 free(ptrcopy);
00740
00741 free(mac);
00742
00743 }
00744
00746 void
00747 config_validate(void)
00748 {
00749 config_notnull(config.gw_interface, "GatewayInterface");
00750 config_notnull(config.auth_servers, "AuthServer");
00751
00752 if (missing_parms) {
00753 debug(LOG_ERR, "Configuration is not complete, exiting...");
00754 exit(-1);
00755 }
00756 }
00757
00761 static void
00762 config_notnull(void *parm, char *parmname)
00763 {
00764 if (parm == NULL) {
00765 debug(LOG_ERR, "%s is not set", parmname);
00766 missing_parms = 1;
00767 }
00768 }
00769
00773 t_auth_serv *
00774 get_auth_server(void)
00775 {
00776
00777
00778 return config.auth_servers;
00779 }
00780
00785 void
00786 mark_auth_server_bad(t_auth_serv *bad_server)
00787 {
00788 t_auth_serv *tmp;
00789
00790 if (config.auth_servers == bad_server && bad_server->next != NULL) {
00791
00792 for (tmp = config.auth_servers; tmp->next != NULL; tmp = tmp->next);
00793
00794 tmp->next = bad_server;
00795
00796 config.auth_servers = bad_server->next;
00797
00798 bad_server->next = NULL;
00799 }
00800
00801 }