Initial commit. It's far from finished.
This commit is contained in:
356
confparser.c
Normal file
356
confparser.c
Normal file
@@ -0,0 +1,356 @@
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "log_trace.h"
|
||||
#include "confparser.h"
|
||||
#include "enum_functions.h"
|
||||
|
||||
static int test_conf_perms();
|
||||
static int test_conf_syntax();
|
||||
|
||||
struct conf_table conf = {
|
||||
{
|
||||
"", /* db.type */
|
||||
"", /* db.hostname */
|
||||
"" /* db.port */
|
||||
},
|
||||
{
|
||||
"127.0.0.1", /* rmps.bind_on_ip */
|
||||
"7000", /* rmps.bind_on_port */
|
||||
"/var/log/rmps/rmpsd.log",
|
||||
"/var/log/rmps/rmpsd.err",
|
||||
'1', /* rmps.loglevel */
|
||||
"/run/rmps/rmpsd.pid",
|
||||
"/etc/rmps/cert.pem",
|
||||
"/etc/rmps/key.pem",
|
||||
"/etc/rmps/ca.crt",
|
||||
"", /* rmps.cipherlist */
|
||||
2 /* rmps.threadpoolsize */
|
||||
},
|
||||
{
|
||||
0 /* nfs -> TODO */
|
||||
}
|
||||
};
|
||||
|
||||
void confexport()
|
||||
{
|
||||
printf( "db.type=%s\n"
|
||||
"db.hostname=%s\n"
|
||||
"db.port=%s\n"
|
||||
"rmps.bind_on_ip=%s\n"
|
||||
"rmps.bind_on_port=%s\n"
|
||||
"rmps.logfile=%s\n"
|
||||
"rmps.errlog=%s\n"
|
||||
"rmps.loglevel=%c\n"
|
||||
"rmps.pidfile=%s\n"
|
||||
"rmps.certfile=%s\n"
|
||||
"rmps.keyfile=%s\n"
|
||||
"rmps.cafile=%s\n"
|
||||
"rmps.cipherlist=%s\n"
|
||||
"rmps.threadpoolsize=%d\n",
|
||||
conf.db.type,
|
||||
conf.db.hostname,
|
||||
conf.db.port,
|
||||
conf.rmps.bind_on_ip,
|
||||
conf.rmps.bind_on_port,
|
||||
conf.rmps.logfile,
|
||||
conf.rmps.errlog,
|
||||
conf.rmps.loglevel,
|
||||
conf.rmps.pidfile,
|
||||
conf.rmps.certfile,
|
||||
conf.rmps.keyfile,
|
||||
conf.rmps.cafile,
|
||||
conf.rmps.cipherlist,
|
||||
conf.rmps.threadpoolsize
|
||||
);
|
||||
}
|
||||
|
||||
static int fopen_and_mkdir(const char *dir) {
|
||||
char tmp[256];
|
||||
char *p = NULL;
|
||||
size_t len;
|
||||
FILE *fd;
|
||||
|
||||
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) {
|
||||
fprintf( stderr,
|
||||
"Permission denied to create directory: %s\n",
|
||||
tmp );
|
||||
return 1;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
fd = fopen(dir, "a");
|
||||
if (!fd) {
|
||||
fprintf(stderr, "Permission denied to write into: %s\n", dir);
|
||||
return 1;
|
||||
}
|
||||
fclose(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int test_conf_perms()
|
||||
{
|
||||
struct stat s;
|
||||
char confresult[128];
|
||||
int err = stat("/etc/rmps", &s);
|
||||
|
||||
if (err == -1) {
|
||||
if (errno == ENOENT) {
|
||||
enumtostr(confresult, CONF_DIR_MISSING);
|
||||
log_trace(ERROR, confresult);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (!S_ISDIR(s.st_mode)) {
|
||||
enumtostr(confresult, CONF_DIR_NOTDIR);
|
||||
log_trace(ERROR, confresult);
|
||||
return 1;
|
||||
}
|
||||
if ( !(S_IRUSR & s.st_mode) ||
|
||||
!(S_IXUSR & s.st_mode) ) {
|
||||
enumtostr(confresult, CONF_DIR_PERM);
|
||||
log_trace(ERROR, confresult);
|
||||
return 1;
|
||||
}
|
||||
if (s.st_uid != 0) {
|
||||
enumtostr(confresult, CONF_DIR_UID_INSECURE);
|
||||
log_trace(WARNING, confresult);
|
||||
}
|
||||
else if (s.st_gid != 0) {
|
||||
enumtostr(confresult, CONF_DIR_GID_INSECURE);
|
||||
log_trace(WARNING, confresult);
|
||||
}
|
||||
else if ( (S_IROTH & s.st_mode) ||
|
||||
(S_IWOTH & s.st_mode) ) {
|
||||
enumtostr(confresult, CONF_DIR_PERM_INSECURE);
|
||||
log_trace(WARNING, confresult);
|
||||
}
|
||||
}
|
||||
|
||||
err = stat("/etc/rmps/rmps.conf", &s);
|
||||
|
||||
if (err == -1) {
|
||||
if (errno == ENOENT) {
|
||||
enumtostr(confresult, CONF_MISSING);
|
||||
log_trace(ERROR, confresult);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (!S_ISREG(s.st_mode)) {
|
||||
enumtostr(confresult, CONF_NOTFILE);
|
||||
log_trace(ERROR, confresult);
|
||||
return 1;
|
||||
}
|
||||
if (!(S_IRUSR & s.st_mode)) {
|
||||
enumtostr(confresult, CONF_PERM);
|
||||
log_trace(ERROR, confresult);
|
||||
return 1;
|
||||
}
|
||||
if (s.st_uid != 0) {
|
||||
enumtostr(confresult, CONF_FILE_UID_INSECURE);
|
||||
log_trace(WARNING, confresult);
|
||||
}
|
||||
else if (s.st_gid != 0) {
|
||||
enumtostr(confresult, CONF_FILE_GID_INSECURE);
|
||||
log_trace(WARNING, confresult);
|
||||
}
|
||||
else if ( (S_IROTH & s.st_mode) ||
|
||||
(S_IWOTH & s.st_mode) ) {
|
||||
enumtostr(confresult, CONF_FILE_PERM_INSECURE);
|
||||
log_trace(WARNING, confresult);
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* conf is readable */
|
||||
}
|
||||
|
||||
static int test_conf_syntax()
|
||||
{
|
||||
int i, j = 0, ok = 1, failed = 0;
|
||||
char buf[CFGLINESIZE], *tmp;
|
||||
FILE *fd = fopen("/etc/rmps/rmps.conf", "r");
|
||||
|
||||
if (fd == NULL) {
|
||||
log_trace(ERROR, "Failed to read /etc/rmps/rmps.conf");
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (fgets(buf, CFGLINESIZE, fd) != 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 {
|
||||
fprintf( stderr,
|
||||
"Bad entry in /etc/rmps/rmps.conf, line %d: %s\n",
|
||||
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') {
|
||||
fprintf( stderr,
|
||||
"Specified entry without value, line %d: %s\n",
|
||||
j, buf );
|
||||
failed = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Here we check every single 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, "rmps.bind_on_ip")) {
|
||||
/* TODO */
|
||||
|
||||
} else if (!strcmp(buf, "rmps.bind_on_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.bind_on_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];
|
||||
else
|
||||
failed = 1;
|
||||
} else if (!strcmp(buf, "rmps.certfile")) {
|
||||
if (access(tmp + 1, F_OK) == -1) {
|
||||
fprintf( stderr,
|
||||
"%s is missing\n", tmp + 1);
|
||||
failed = 1;
|
||||
}
|
||||
else if (access(tmp + 1, R_OK) == -1) {
|
||||
fprintf( stderr,
|
||||
"%s is not readable\n",
|
||||
tmp + 1
|
||||
);
|
||||
failed = 1;
|
||||
} else
|
||||
strncpy(conf.rmps.certfile, tmp + 1, sizeof(conf.rmps.certfile));
|
||||
}
|
||||
|
||||
else if (!strcmp(buf, "rmps.keyfile")) {
|
||||
if (access(tmp + 1, F_OK) == -1) {
|
||||
fprintf( stderr,
|
||||
"%s is missing\n", conf.rmps.keyfile);
|
||||
failed = 1;
|
||||
}
|
||||
else if (access(tmp + 1, R_OK) == -1) {
|
||||
fprintf( stderr,
|
||||
"%s is not readable\n",
|
||||
tmp + 1
|
||||
);
|
||||
failed = 1;
|
||||
} else
|
||||
strncpy(conf.rmps.keyfile, tmp + 1, sizeof(conf.rmps.keyfile));
|
||||
} 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) {
|
||||
fprintf( stderr,
|
||||
"%s is missing\n", tmp + 1);
|
||||
failed = 1;
|
||||
}
|
||||
else if (access(tmp + 1, R_OK) == -1) {
|
||||
fprintf( stderr,
|
||||
"%s is not readable\n",
|
||||
tmp + 1
|
||||
);
|
||||
failed = 1;
|
||||
} else
|
||||
strncpy(conf.rmps.cafile, tmp + 1, sizeof(conf.rmps.cafile));
|
||||
} else
|
||||
fprintf( stderr,
|
||||
"Unknown config entry on line %d: %s\n",
|
||||
j, buf );
|
||||
if (!ok) {
|
||||
fprintf( stderr,
|
||||
"Invalid value for \"%s\", line %d: \"%s\"\n",
|
||||
buf, j, tmp + 1 );
|
||||
ok = !ok;
|
||||
}
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
if (failed)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int confparse()
|
||||
{
|
||||
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 */
|
||||
}
|
||||
Reference in New Issue
Block a user