#include #include #include #include #include #include #include "log.h" #include "confparser.h" #include "enum_functions.h" static int test_conf_perms(); static int test_conf_syntax(); struct conf_table conf = { 0, /* isvalid initial state */ { "", /* db.type */ "", /* db.hostname */ "", /* db.port */ "" /* db.pass */ }, { "127.0.0.1", /* rmps.agent_ip */ "7000", /* rmps.agent_port */ "127.0.0.1", /* rmps.client_ip */ "7001", /* rmps.client_port */ "/var/log/rmps/rmpsd.log", "/var/log/rmps/rmpsd.err", '2', /* rmps.loglevel */ "/run/rmps/rmpsd.pid", "/etc/rmps/agent.crt", "/etc/rmps/agent.key", "/etc/rmps/ca.crt", "", /* rmps.cipherlist */ 2, /* rmps.agent_poolsize */ "/etc/rmps/client.crt", "/etc/rmps/client.key", 2 /* rmps.client_poolsize */ }, { 0 /* nfs -> TODO */ } }; const char* conf_db_pass(void) { return conf.db.pass; } const char* conf_db_hostname(void) { return conf.db.hostname; } void confexport(void) { printf( "db.type=%s\n" "db.hostname=%s\n" "db.port=%s\n" "db.pass=%s\n" "rmps.agent_ip=%s\n" "rmps.agent_port=%s\n" "rmps.client_ip=%s\n" "rmps.client_port=%s\n" "rmps.logfile=%s\n" "rmps.errlog=%s\n" "rmps.loglevel=%d\n" "rmps.pidfile=%s\n" "rmps.agent_tls_crt=%s\n" "rmps.agent_tls_key=%s\n" "rmps.cafile=%s\n" "rmps.cipherlist=%s\n" "rmps.agent_poolsize=%d\n" "rmps.client_tls_crt=%s\n" "rmps.client_tls_key=%s\n" "rmps.client_poolsize=%d\n", conf.db.type, conf.db.hostname, conf.db.port, conf.db.pass, conf.rmps.agent_ip, conf.rmps.agent_port, conf.rmps.client_ip, conf.rmps.client_port, conf.rmps.logfile, conf.rmps.errlog, conf.rmps.loglevel, conf.rmps.pidfile, conf.rmps.agent_tls_crt, conf.rmps.agent_tls_key, conf.rmps.cafile, conf.rmps.cipherlist, conf.rmps.agent_poolsize, conf.rmps.client_tls_crt, conf.rmps.client_tls_key, conf.rmps.client_poolsize ); } static int fopen_and_mkdir(const char *dir) { char tmp[256]; char *p = NULL; size_t len; FILE *fp; snprintf(tmp, sizeof(tmp),"%s",dir); len = strlen(tmp); if(tmp[len - 1] == '/') tmp[len - 1] = 0; for (p = tmp + 1; *p; p++) if(*p == '/') { *p = 0; if (mkdir(tmp, S_IRWXU) == -1 && errno != EEXIST) { log( ERROR, "Permission denied to create directory: %s", tmp ); return 1; } *p = '/'; } fp = fopen(dir, "a"); if (!fp) { log(ERROR, "Permission denied to write into: %s", dir); return 1; } fclose(fp); return 0; } static int test_conf_perms(void) { struct stat s; char confresult[128]; int err = stat("/etc/rmps", &s); if (err == -1) { if (errno == ENOENT) { enumtostr(confresult, CONF_DIR_MISSING); log(ERROR, confresult); return 1; } } else { if (!S_ISDIR(s.st_mode)) { enumtostr(confresult, CONF_DIR_NOTDIR); log(ERROR, confresult); return 1; } if ( !(S_IRUSR & s.st_mode) || !(S_IXUSR & s.st_mode) ) { enumtostr(confresult, CONF_DIR_PERM); log(ERROR, confresult); return 1; } if (s.st_uid != 0) { enumtostr(confresult, CONF_DIR_UID_INSECURE); log(WARNING, confresult); } else if (s.st_gid != 0) { enumtostr(confresult, CONF_DIR_GID_INSECURE); log(WARNING, confresult); } else if ( (S_IROTH & s.st_mode) || (S_IWOTH & s.st_mode) ) { enumtostr(confresult, CONF_DIR_PERM_INSECURE); log(WARNING, confresult); } } err = stat("/etc/rmps/rmps.conf", &s); if (err == -1) { if (errno == ENOENT) { enumtostr(confresult, CONF_MISSING); log(ERROR, confresult); return 1; } } else { if (!S_ISREG(s.st_mode)) { enumtostr(confresult, CONF_NOTFILE); log(ERROR, confresult); return 1; } if (!(S_IRUSR & s.st_mode)) { enumtostr(confresult, CONF_PERM); log(ERROR, confresult); return 1; } if (s.st_uid != 0) { enumtostr(confresult, CONF_FILE_UID_INSECURE); log(WARNING, confresult); } else if (s.st_gid != 0) { enumtostr(confresult, CONF_FILE_GID_INSECURE); log(WARNING, confresult); } else if ( (S_IROTH & s.st_mode) || (S_IWOTH & s.st_mode) ) { enumtostr(confresult, CONF_FILE_PERM_INSECURE); log(WARNING, confresult); } } return 0; /* conf is readable */ } static int test_conf_syntax(void) { int i, j = 0, ok = 1, failed = 0; char buf[CFGLINESIZE], *tmp; FILE *fp = fopen("/etc/rmps/rmps.conf", "r"); if (fp == NULL) { log(ERROR, "Failed to read /etc/rmps/rmps.conf"); return 1; } while (fgets(buf, CFGLINESIZE, fp) != NULL) { j++; /* kill comments and ignore BLANK lines */ if ((tmp = strstr(buf, "#"))) *tmp = '\0'; if (buf[strspn(buf, " \t\v\r\n")] == '\0') continue; /* If we have "=", it's a possible var */ if ((tmp = strstr(buf, "="))) *tmp = '\0'; else { log( ERROR, "Bad entry in /etc/rmps/rmps.conf, line %d: %s", j, buf ); ok = 0; failed = 1; continue; } /* Check if there actually is a value after '=' */ i = strlen(tmp + 1); if (tmp[i] == '\n') tmp[i] = '\0'; if (tmp[strspn(tmp + 1, " \t\v\r\n") + 1] == '\0') { log( ERROR, "Specified entry without value, line %d: %s", j, buf ); failed = 1; continue; } /* Here we check every single conf entry manually */ if (!strcmp(buf, "db.type")) { if (!strcmp(tmp + 1, "mysql")) { /* || !strcmp(tmp[1], "postgresql") */ /* || !strcmp(tmp[1], "oracle") */ strcpy(conf.db.type, tmp + 1); if (conf.db.port[0] == '\0') strcpy(conf.db.port, "3306"); } else { ok = 0; failed = 1; } } else if (!strcmp(buf, "db.hostname")) /* Just save it, launch_rmps will check it */ strcpy(conf.db.hostname, tmp + 1); else if (!strcmp(buf, "db.port")) { if ((i = strlen(tmp + 1)) < 6) { if ((signed int)strspn(tmp + 1, "1234567890") == i) { i = atoi(tmp + 1); if (i > 0 && i < 65536) { strcpy(conf.db.port, tmp + 1); continue; } } } ok = 0; failed = 1; } else if (!strcmp(buf, "db.pass")) strcpy(conf.db.pass, tmp + 1); else if (!strcmp(buf, "rmps.agent_ip")) { /* TODO */ } else if (!strcmp(buf, "rmps.agent_port")) { if ((i = strlen(tmp + 1)) < 6) { if ((signed int)strspn(tmp + 1, "1234567890") == i) { i = atoi(tmp + 1); if (i > 0 && i < 65536) { strcpy(conf.rmps.agent_port, tmp + 1); continue; } } } ok = 0; failed = 1; } else if (!strcmp(buf, "rmps.client_ip")) { /* TODO */ } else if (!strcmp(buf, "rmps.client_port")) { if ((i = strlen(tmp + 1)) < 6) { if ((signed int)strspn(tmp + 1, "1234567890") == i) { i = atoi(tmp + 1); if (i > 0 && i < 65536) { strcpy(conf.rmps.client_port, tmp + 1); continue; } } } ok = 0; failed = 1; } else if (!strcmp(buf, "rmps.logfile")) { strcpy(conf.rmps.logfile, tmp + 1); if (fopen_and_mkdir(conf.rmps.logfile) != 0) failed = 1; } else if (!strcmp(buf, "rmps.errlog")) { strcpy(conf.rmps.errlog, tmp + 1); if (fopen_and_mkdir(conf.rmps.errlog) != 0) failed = 1; } else if (!strcmp(buf, "rmps.pidfile")) { strcpy(conf.rmps.pidfile, tmp + 1); /*if (fopen_and_mkdir(conf.rmps.pidfile) != 0) failed = 1;*/ } else if (!strcmp(buf, "rmps.loglevel")) { if (strlen(tmp + 1) == 1 && (tmp[1] > '0' && tmp[1] < '5')) conf.rmps.loglevel = tmp[1] - '0'; else failed = 1; } else if (!strcmp(buf, "rmps.agent_tls_crt")) { if (access(tmp + 1, F_OK) == -1) { log(ERROR, "%s is missing", tmp + 1); failed = 1; } else if (access(tmp + 1, R_OK) == -1) { log(ERROR, "%s is not readable", tmp + 1); failed = 1; } else strncpy(conf.rmps.agent_tls_crt, tmp + 1, sizeof(conf.rmps.agent_tls_crt)); } else if (!strcmp(buf, "rmps.agent_tls_key")) { if (access(tmp + 1, F_OK) == -1) { log(ERROR, "%s is missing", tmp + 1); failed = 1; } else if (access(tmp + 1, R_OK) == -1) { log(ERROR, "%s is not readable", tmp + 1); failed = 1; } else strncpy(conf.rmps.agent_tls_key, tmp + 1, sizeof(conf.rmps.agent_tls_key)); } else if (!strcmp(buf, "rmps.cipherlist")) { strncpy(conf.rmps.cipherlist, tmp + 1, sizeof(conf.rmps.cipherlist)); } else if (!strcmp(buf, "rmps.cafile")) { if (access(tmp + 1, F_OK) == -1) { log(ERROR, "%s is missing", tmp + 1); failed = 1; } else if (access(tmp + 1, R_OK) == -1) { log(ERROR, "%s is not readable\n", tmp + 1); failed = 1; } else strncpy(conf.rmps.cafile, tmp + 1, sizeof(conf.rmps.cafile)); } else if (!strcmp(buf, "rmps.client_tls_crt")) { if (access(tmp + 1, F_OK) == -1) { log(ERROR, "%s is missing", tmp + 1); failed = 1; } else if (access(tmp + 1, R_OK) == -1) { log(ERROR, "%s is not readable", tmp + 1); failed = 1; } else strncpy(conf.rmps.client_tls_crt, tmp + 1, sizeof(conf.rmps.client_tls_crt)); } else if (!strcmp(buf, "rmps.client_tls_key")) { if (access(tmp + 1, F_OK) == -1) { log(ERROR, "%s is missing", tmp + 1); failed = 1; } else if (access(tmp + 1, R_OK) == -1) { log(ERROR, "%s is not readable", tmp + 1); failed = 1; } else strncpy(conf.rmps.client_tls_key, tmp + 1, sizeof(conf.rmps.client_tls_key)); } else log(ERROR, "Unknown config entry on line %d: %s", j, buf); if (!ok) { log( ERROR, "Invalid value for \"%s\", line %d: \"%s\"", buf, j, tmp + 1 ); ok = !ok; } } fclose(fp); if (failed) return 1; conf.isvalid = 1; return 0; } int confparse(void) { int result; result = test_conf_perms(); if (result) return 1; /* Bad conf perms */ result = test_conf_syntax(); if (result != 0) return 1; /* Bad conf syntax */ return 0; /* seems legit */ }