Introduce src, obj, build, docs & modify Makefile
This commit is contained in:
177
src/agent_pool.c
Normal file
177
src/agent_pool.c
Normal file
@@ -0,0 +1,177 @@
|
||||
#include "agent_pool.h"
|
||||
#include "log.h"
|
||||
#include "protocol.h"
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAXJOBS 10
|
||||
|
||||
struct agent_args {
|
||||
int busy;
|
||||
SSL *ssl;
|
||||
int sd;
|
||||
char ip[16]; /* IPv4 */
|
||||
};
|
||||
|
||||
static void show_certs(SSL *ssl);
|
||||
static void *servlet(void *args);
|
||||
static void send_reject_msg(SSL *ssl);
|
||||
|
||||
static void show_certs(SSL *ssl)
|
||||
{
|
||||
X509 *cert;
|
||||
char *line;
|
||||
|
||||
/* Get certificates (if available) */
|
||||
cert = SSL_get_peer_certificate(ssl);
|
||||
if (SSL_get_verify_result(ssl) == X509_V_OK)
|
||||
log(VERBOSE, "get_verify_result == ok");
|
||||
if (cert != NULL) {
|
||||
log(VERBOSE, "Server certificates:");
|
||||
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
|
||||
log(VERBOSE, "Subject: %s", line);
|
||||
free(line);
|
||||
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
|
||||
log(VERBOSE, "Issuer: %s", line);
|
||||
free(line);
|
||||
X509_free(cert);
|
||||
} else
|
||||
log(VERBOSE, "No certificates from peer");
|
||||
}
|
||||
|
||||
static void *servlet(void *args) /* Serve the connection -- threadable */
|
||||
{
|
||||
struct msg_t buf;
|
||||
int bytes, ret;
|
||||
//unsigned short job[MAXJOBS] = { 0 };
|
||||
struct agent_args *agent = (struct agent_args *)args;
|
||||
|
||||
SSL_load_error_strings();
|
||||
ret = SSL_accept(agent->ssl);
|
||||
/* We check for unclean (ret < 0) and clean (ret == 0) failures */
|
||||
if (ret <= 0) {
|
||||
log(WARNING, "SSL_accept() failed. Reason below:");
|
||||
log_ssl();
|
||||
} else {
|
||||
show_certs(agent->ssl);
|
||||
do {
|
||||
buf.meta.type = GET_MEMORY;
|
||||
sleep(1);
|
||||
SSL_write(agent->ssl, &buf, sizeof(buf));
|
||||
bytes = SSL_read(agent->ssl, &buf, sizeof(buf));
|
||||
if (bytes > 0) {
|
||||
if (bytes != sizeof(struct msg_t)) {
|
||||
log(WARNING,
|
||||
"Agent [%s] sent non-standard data!",
|
||||
agent->ip);
|
||||
continue;
|
||||
}
|
||||
|
||||
log(VERBOSE, "Client msg: \"%s\"",
|
||||
buf.chunk.data);
|
||||
/* TODO: Insert msg handler here */
|
||||
continue;
|
||||
}
|
||||
if (SSL_get_shutdown(agent->ssl)
|
||||
== SSL_RECEIVED_SHUTDOWN)
|
||||
log(VERBOSE,
|
||||
"SSL_RECEIVED_SHUTDOWN from agent [%s]",
|
||||
agent->ip);
|
||||
else {
|
||||
log(VERBOSE,
|
||||
"Client didn't send data! SSL error below:");
|
||||
/* I think logging is NOT needed here */
|
||||
//log_ssl();
|
||||
sprintf((char *)buf.chunk.data, "%s",
|
||||
"Where's the data, m8?");
|
||||
SSL_write(agent->ssl, &buf,
|
||||
sizeof(struct msg_t));
|
||||
}
|
||||
log(INFO, "Agent [%s] disconnected.", agent->ip);
|
||||
} while (bytes);
|
||||
}
|
||||
SSL_free(agent->ssl); /* release SSL state */
|
||||
close(agent->sd); /* close connection */
|
||||
agent->busy = 0;
|
||||
pthread_detach(pthread_self());
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static void send_reject_msg(SSL *ssl)
|
||||
{
|
||||
char *reply = "FAILURE - The connection queue is full!\n";
|
||||
|
||||
SSL_write(ssl, reply, strlen(reply));
|
||||
}
|
||||
|
||||
void *agent_pool(void *args)
|
||||
{
|
||||
struct pool_data *pool = args;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_attr_t attr;
|
||||
pthread_t *agent_thread = malloc(pool->size * sizeof(*agent_thread));
|
||||
struct agent_args *agent_struct =
|
||||
malloc(pool->size * sizeof(*agent_struct));
|
||||
int i;
|
||||
|
||||
memset(agent_thread, 0, sizeof(pthread_t) * pool->size);
|
||||
memset(agent_struct, 0, sizeof(struct agent_args) * pool->size);
|
||||
|
||||
pthread_mutex_init(&mutex, NULL);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
while (1) {
|
||||
struct sockaddr_in addr;
|
||||
char address[INET6_ADDRSTRLEN];
|
||||
socklen_t len = sizeof(addr);
|
||||
SSL *ssl;
|
||||
int agent = accept(pool->srv, (struct sockaddr *)&addr, &len);
|
||||
|
||||
log(INFO,
|
||||
"Connection: %s:%d",
|
||||
inet_ntop(AF_INET, &addr.sin_addr,
|
||||
address, sizeof(address)),
|
||||
ntohs(addr.sin_port));
|
||||
|
||||
for (i = 0; i < pool->size; i++) {
|
||||
if (!agent_struct[i].busy) {
|
||||
agent_struct[i].busy = 1;
|
||||
agent_struct[i].ssl = SSL_new(pool->ctx);
|
||||
agent_struct[i].sd = agent;
|
||||
memcpy(agent_struct[i].ip,
|
||||
inet_ntop(AF_INET, &addr.sin_addr,
|
||||
address, sizeof(address)),
|
||||
sizeof(agent_struct[i].ip));
|
||||
SSL_set_fd(agent_struct[i].ssl,
|
||||
agent_struct[i].sd);
|
||||
pthread_create(&agent_thread[i],
|
||||
&attr,
|
||||
servlet,
|
||||
&agent_struct[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == pool->size) {
|
||||
log(WARNING,
|
||||
"Agent [%s] dropped. Poolsize limit reached.",
|
||||
inet_ntop(AF_INET, &addr.sin_addr,
|
||||
address, sizeof(address)));
|
||||
ssl = SSL_new(pool->ctx);
|
||||
SSL_set_fd(ssl, agent);
|
||||
if (SSL_accept(ssl) == FAIL) {
|
||||
SSL_free(ssl);
|
||||
close(agent);
|
||||
continue;
|
||||
}
|
||||
send_reject_msg(ssl);
|
||||
SSL_free(ssl);
|
||||
close(agent);
|
||||
}
|
||||
}
|
||||
pthread_attr_destroy(&attr);
|
||||
pthread_mutex_destroy(&mutex);
|
||||
pthread_detach(pthread_self());
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
17
src/agent_pool.h
Normal file
17
src/agent_pool.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef AGENT_POOL_H
|
||||
#define AGENT_POOL_H
|
||||
|
||||
/* included for openssl and sockets */
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <resolv.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include "rmps.h"
|
||||
|
||||
#define FAIL -1
|
||||
|
||||
//void agent_pool(int srv, SSL_CTX *ctx, int poolsize);
|
||||
void *agent_pool(void *args);
|
||||
|
||||
#endif /* AGENT_POOL_H */
|
||||
149
src/client_pool.c
Normal file
149
src/client_pool.c
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "client_pool.h"
|
||||
#include "log.h"
|
||||
#include "job_queue.h"
|
||||
#include "protocol.h"
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAXJOBS 10
|
||||
|
||||
struct client_args {
|
||||
int busy;
|
||||
SSL *ssl;
|
||||
int sd;
|
||||
char ip[16]; /* IPv4 */
|
||||
};
|
||||
|
||||
static void *servlet(void *args);
|
||||
static void send_reject_msg(SSL *ssl);
|
||||
|
||||
static void *servlet(void *args) /* Serve the connection -- threadable */
|
||||
{
|
||||
struct msg_t buf;
|
||||
int bytes, ret;
|
||||
//unsigned short job[MAXJOBS] = { 0 };
|
||||
struct client_args *client = (struct client_args *)args;
|
||||
|
||||
SSL_load_error_strings();
|
||||
ret = SSL_accept(client->ssl);
|
||||
/* We check for unclean (ret < 0) and clean (ret == 0) failures */
|
||||
if (ret <= 0) {
|
||||
log(WARNING, "SSL_accept() failed. Reason below:");
|
||||
log_ssl();
|
||||
} else {
|
||||
int queue_id = start_msg_queue();
|
||||
|
||||
if (queue_id == FAIL)
|
||||
goto exit;
|
||||
do {
|
||||
//buf.meta.type = GET_MEMORY;
|
||||
//sleep(1);
|
||||
//SSL_write(client->ssl, &buf, sizeof(buf));
|
||||
bytes = SSL_read(client->ssl, &buf, sizeof(buf));
|
||||
if (bytes > 0) {
|
||||
if (bytes != sizeof(struct msg_t)) {
|
||||
log(WARNING,
|
||||
"Client [%s] sent non-standard data!",
|
||||
client->ip);
|
||||
continue;
|
||||
}
|
||||
|
||||
log(VERBOSE, "Client msg: \"%s\"", buf.chunk.data);
|
||||
/* TODO: Insert msg handler here */
|
||||
add_msg_to_queue(queue_id, buf);
|
||||
|
||||
continue;
|
||||
}
|
||||
if (SSL_get_shutdown(client->ssl) == SSL_RECEIVED_SHUTDOWN)
|
||||
log(VERBOSE, "SSL_RECEIVED_SHUTDOWN from client [%s]", client->ip);
|
||||
else {
|
||||
log(VERBOSE, "Client didn't send data! SSL error below:");
|
||||
//log_ssl(); /* We actually don't have anything to log from SSL */
|
||||
sprintf((char *)buf.chunk.data, "%s", "Where's the data, m8?");
|
||||
SSL_write(client->ssl, &buf, sizeof(struct msg_t));
|
||||
}
|
||||
log(INFO, "Client [%s] disconnected.", client->ip);
|
||||
} while (bytes);
|
||||
}
|
||||
exit:
|
||||
SSL_free(client->ssl); /* release SSL state */
|
||||
close(client->sd); /* close connection */
|
||||
client->busy = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_reject_msg(SSL *ssl)
|
||||
{
|
||||
char *reply = "FAILURE - The connection queue is full!\n";
|
||||
|
||||
SSL_write(ssl, reply, strlen(reply));
|
||||
}
|
||||
|
||||
void *client_pool(void *args)
|
||||
{
|
||||
struct pool_data *pool = args;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_attr_t attr;
|
||||
pthread_t *client_thread = malloc(pool->size * sizeof(*client_thread));
|
||||
struct client_args *client_struct =
|
||||
malloc(pool->size * sizeof(*client_struct));
|
||||
int i;
|
||||
|
||||
memset(client_thread, 0, sizeof(pthread_t) * pool->size);
|
||||
memset(client_struct, 0, sizeof(struct client_args) * pool->size);
|
||||
|
||||
pthread_mutex_init(&mutex, NULL);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
while (1) {
|
||||
struct sockaddr_in addr;
|
||||
char address[INET6_ADDRSTRLEN];
|
||||
socklen_t len = sizeof(addr);
|
||||
SSL *ssl;
|
||||
int agent = accept(pool->srv, (struct sockaddr *)&addr, &len);
|
||||
|
||||
log(INFO,
|
||||
"Connection: %s:%d",
|
||||
inet_ntop(AF_INET, &addr.sin_addr, address, sizeof(address)),
|
||||
ntohs(addr.sin_port));
|
||||
|
||||
for (i = 0; i < pool->size; i++) {
|
||||
if (!client_struct[i].busy) {
|
||||
client_struct[i].busy = 1;
|
||||
client_struct[i].ssl = SSL_new(pool->ctx);
|
||||
client_struct[i].sd = agent;
|
||||
memcpy(client_struct[i].ip,
|
||||
inet_ntop(AF_INET, &addr.sin_addr, address, sizeof(address)),
|
||||
sizeof(client_struct[i].ip));
|
||||
SSL_set_fd(client_struct[i].ssl, client_struct[i].sd);
|
||||
pthread_create(&client_thread[i],
|
||||
&attr,
|
||||
servlet,
|
||||
&client_struct[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == pool->size) {
|
||||
log(WARNING,
|
||||
"Agent [%s] dropped. Poolsize limit reached.",
|
||||
inet_ntop(AF_INET, &addr.sin_addr, address, sizeof(address))
|
||||
);
|
||||
ssl = SSL_new(pool->ctx);
|
||||
SSL_set_fd(ssl, agent);
|
||||
if (SSL_accept(ssl) == FAIL) {
|
||||
SSL_free(ssl);
|
||||
close(agent);
|
||||
continue;
|
||||
}
|
||||
send_reject_msg(ssl);
|
||||
SSL_free(ssl);
|
||||
close(agent);
|
||||
}
|
||||
}
|
||||
pthread_attr_destroy(&attr);
|
||||
pthread_mutex_destroy(&mutex);
|
||||
pthread_detach(pthread_self());
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
17
src/client_pool.h
Normal file
17
src/client_pool.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef CLIENT_POOL_H
|
||||
#define CLIENT_POOL_H
|
||||
|
||||
/* included for openssl and sockets */
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <resolv.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include "rmps.h"
|
||||
|
||||
#define FAIL -1
|
||||
|
||||
//void client_pool(int srv, SSL_CTX *ctx, int poolsize);
|
||||
void *client_pool(void *args);
|
||||
|
||||
#endif /* CLIENT_POOL_H */
|
||||
418
src/confparser.c
Normal file
418
src/confparser.c
Normal file
@@ -0,0 +1,418 @@
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "log.h"
|
||||
#include "confparser.h"
|
||||
#include "enum_functions.h"
|
||||
|
||||
static int test_conf_perms(void);
|
||||
static int test_conf_syntax(void);
|
||||
|
||||
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, 0700) == -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 (!(0400 & s.st_mode) ||
|
||||
!(0100 & 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 ((0004 & s.st_mode) ||
|
||||
(0002 & 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 (!(0400 & 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 ((0004 & s.st_mode) ||
|
||||
(0002 & 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 */
|
||||
tmp = strstr(buf, "#");
|
||||
if (tmp)
|
||||
*tmp = '\0';
|
||||
if (buf[strspn(buf, " \t\v\r\n")] == '\0')
|
||||
continue;
|
||||
|
||||
/* If we have "=", it's a possible var */
|
||||
tmp = strstr(buf, "=");
|
||||
if (tmp)
|
||||
*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")) {
|
||||
i = strlen(tmp + 1);
|
||||
if (i < 6) { /* max 5 digits for network port */
|
||||
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")) {
|
||||
i = strlen(tmp + 1);
|
||||
if (i < 6) { /* max 5 digits for network port */
|
||||
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")) {
|
||||
i = strlen(tmp + 1);
|
||||
if (i < 6) { /* max 5 digits for network port */
|
||||
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 */
|
||||
}
|
||||
54
src/confparser.h
Normal file
54
src/confparser.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef CONFPARSER_H
|
||||
#define CONFPARSER_H
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#define MAXPATHSIZE 256
|
||||
#define HOSTNAMESIZE 128
|
||||
#define CFGLINESIZE 300
|
||||
|
||||
struct conf_db {
|
||||
char type[15];
|
||||
char hostname[HOSTNAMESIZE];
|
||||
char port[6];
|
||||
char pass[60]; /* random decision */
|
||||
};
|
||||
|
||||
struct conf_rmps {
|
||||
char agent_ip[13];
|
||||
char agent_port[6];
|
||||
char client_ip[13];
|
||||
char client_port[6];
|
||||
char logfile[MAXPATHSIZE];
|
||||
char errlog[MAXPATHSIZE];
|
||||
enum LOG_LEVEL loglevel;
|
||||
char pidfile[MAXPATHSIZE];
|
||||
char agent_tls_crt[MAXPATHSIZE];
|
||||
char agent_tls_key[MAXPATHSIZE];
|
||||
char cafile[MAXPATHSIZE];
|
||||
char cipherlist[1024];
|
||||
int agent_poolsize;
|
||||
char client_tls_crt[MAXPATHSIZE];
|
||||
char client_tls_key[MAXPATHSIZE];
|
||||
int client_poolsize;
|
||||
};
|
||||
|
||||
struct conf_nfs {
|
||||
int TODO;
|
||||
};
|
||||
|
||||
struct conf_table {
|
||||
int isvalid;
|
||||
struct conf_db db;
|
||||
struct conf_rmps rmps;
|
||||
struct conf_nfs nfs;
|
||||
};
|
||||
|
||||
extern struct conf_table conf;
|
||||
extern int confparse(void);
|
||||
extern void confexport(void);
|
||||
extern const char *conf_db_pass(void);
|
||||
extern const char *conf_db_hostname(void);
|
||||
|
||||
#endif /* CONFPARSER_H */
|
||||
|
||||
32
src/enum_functions.c
Normal file
32
src/enum_functions.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "enum_functions.h"
|
||||
#include "log.h"
|
||||
|
||||
void enumtostr(char *scode, int code)
|
||||
{
|
||||
char line[128];
|
||||
FILE *fp;
|
||||
int bytes = 0;
|
||||
|
||||
snprintf(scode, 10, "%d", code);
|
||||
|
||||
fp = fopen("/usr/lib/rmps/resources/enum_codes", "r");
|
||||
if (fp == NULL) {
|
||||
log(ERROR, "Failed to fetch error enum code!");
|
||||
return;
|
||||
}
|
||||
while (fgets(line, sizeof(line), fp) != NULL)
|
||||
if (strstr(line, scode) != NULL) {
|
||||
char *byte;
|
||||
|
||||
bytes = sprintf(scode, "%s", line);
|
||||
byte = memchr(scode, '\n', bytes);
|
||||
byte[-1] = '\0';
|
||||
break;
|
||||
}
|
||||
strncpy(scode, (char *)memchr(scode, '\"', bytes) + 1, bytes);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
24
src/enum_functions.h
Normal file
24
src/enum_functions.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef ENUM_FUNCTIONS_H
|
||||
#define ENUM_FUNCTIONS_H
|
||||
|
||||
enum ERROR_CODES {
|
||||
CONF_DIR_MISSING = 100,
|
||||
CONF_DIR_PERM, /* 101 */
|
||||
CONF_DIR_NOTDIR, /* 102 */
|
||||
CONF_MISSING, /* 103 */
|
||||
CONF_PERM, /* 104 */
|
||||
CONF_NOTFILE, /* 105 */
|
||||
};
|
||||
|
||||
enum WARN_CODES {
|
||||
CONF_DIR_GID_INSECURE = 200,
|
||||
CONF_DIR_UID_INSECURE,
|
||||
CONF_DIR_PERM_INSECURE,
|
||||
CONF_FILE_GID_INSECURE,
|
||||
CONF_FILE_UID_INSECURE,
|
||||
CONF_FILE_PERM_INSECURE,
|
||||
};
|
||||
|
||||
extern void enumtostr(char *scode, int code);
|
||||
|
||||
#endif /* ENUM_FUNCTIONS_H */
|
||||
55
src/job_queue.c
Normal file
55
src/job_queue.c
Normal file
@@ -0,0 +1,55 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sql.h"
|
||||
#include "job_queue.h"
|
||||
|
||||
struct msg_t **slot;
|
||||
int total_queues;
|
||||
|
||||
int start_msg_queue(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < total_queues; i++) {
|
||||
if (slot[i] == NULL) {
|
||||
slot[i] = calloc(100, sizeof(**slot));
|
||||
if (slot[i] == NULL)
|
||||
return -1;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void free_queue(int id)
|
||||
{
|
||||
free(slot[id]);
|
||||
}
|
||||
|
||||
int start_job_queue(int poolsize)
|
||||
{
|
||||
slot = calloc(poolsize, sizeof(*slot));
|
||||
if (slot == NULL)
|
||||
return -1;
|
||||
total_queues = poolsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_msg_to_queue(int id, struct msg_t buf)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
if (slot[id][i].meta.is_recv) {
|
||||
memcpy(&slot[id][i], &buf, sizeof(struct msg_t));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void create_job(struct msg_t buf)
|
||||
{
|
||||
// add_job_in_db();
|
||||
|
||||
}
|
||||
13
src/job_queue.h
Normal file
13
src/job_queue.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef JOB_QUEUE_H
|
||||
#define JOB_QUEUE_H
|
||||
|
||||
#include "protocol.h"
|
||||
|
||||
//void* create_job(void *arg);
|
||||
int start_msg_queue(void);
|
||||
void free_queue(int id);
|
||||
int start_job_queue(int poolsize);
|
||||
int add_msg_to_queue(int id, struct msg_t buf);
|
||||
|
||||
#endif /* JOB_QUEUE_H */
|
||||
|
||||
77
src/log.c
Normal file
77
src/log.c
Normal file
@@ -0,0 +1,77 @@
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <pthread.h>
|
||||
#include <openssl/err.h>
|
||||
#include "log.h"
|
||||
#include "confparser.h"
|
||||
|
||||
static FILE *fderr;
|
||||
static FILE *fdout;
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void open_logs(void)
|
||||
{
|
||||
if ((fderr = fopen(conf.rmps.errlog, "a")) == NULL)
|
||||
fderr = stderr;
|
||||
else
|
||||
setvbuf(fderr, NULL, _IOLBF, 0);
|
||||
if ((fdout = fopen(conf.rmps.logfile, "a")) == NULL)
|
||||
fdout = stdout;
|
||||
else
|
||||
setvbuf(fdout, NULL, _IOLBF, 0);
|
||||
}
|
||||
|
||||
void log_ssl(void)
|
||||
{
|
||||
ERR_print_errors_fp(fderr);
|
||||
fflush(fderr);
|
||||
}
|
||||
|
||||
static void set_fpts(void)
|
||||
{
|
||||
fderr = stderr;
|
||||
fdout = stdout;
|
||||
}
|
||||
|
||||
void log(enum LOG_LEVEL lvl, char *fmt, ...)
|
||||
{
|
||||
char fmt_with_pfx[1024];
|
||||
|
||||
pthread_once(&init_once, set_fpts);
|
||||
if (conf.isvalid)
|
||||
pthread_once(&once, open_logs);
|
||||
if (lvl <= conf.rmps.loglevel) {
|
||||
va_list list;
|
||||
FILE *fp;
|
||||
|
||||
static const char * const prefixes[] = {
|
||||
"ERROR", "WARNING", "INFO", "VERBOSE"
|
||||
};
|
||||
time_t t = time(NULL);
|
||||
struct tm tm;
|
||||
|
||||
localtime_r(&t, &tm);
|
||||
if (lvl == ERROR || lvl == WARNING)
|
||||
fp = fderr;
|
||||
else
|
||||
fp = fdout;
|
||||
snprintf(fmt_with_pfx,
|
||||
sizeof(fmt_with_pfx),
|
||||
"[%d-%02d-%02d %02d:%02d:%02d] %s: %s\n",
|
||||
tm.tm_year + 1900,
|
||||
tm.tm_mon + 1,
|
||||
tm.tm_mday,
|
||||
tm.tm_hour,
|
||||
tm.tm_min,
|
||||
tm.tm_sec,
|
||||
prefixes[lvl-1],
|
||||
fmt);
|
||||
|
||||
va_start(list, fmt);
|
||||
vfprintf(fp, fmt_with_pfx, list);
|
||||
va_end(list);
|
||||
}
|
||||
}
|
||||
|
||||
18
src/log.h
Normal file
18
src/log.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef LOG_TRACE_H
|
||||
#define LOG_TRACE_H
|
||||
|
||||
#undef log
|
||||
#define log log_trace
|
||||
|
||||
enum LOG_LEVEL {
|
||||
ERROR = 1, /* Errors only */
|
||||
WARNING, /* Errors & warnings */
|
||||
INFO, /* Errors, warnings & events */
|
||||
VERBOSE, /* Errors, warnings, events & more? */
|
||||
};
|
||||
|
||||
void log_ssl(void);
|
||||
void log(enum LOG_LEVEL lvl, char *fmt, ...);
|
||||
|
||||
#endif /* LOG_TRACE_H */
|
||||
|
||||
95
src/main.c
Normal file
95
src/main.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include "confparser.h"
|
||||
#include "log.h"
|
||||
#include "rmps.h"
|
||||
|
||||
static void usage(char *argv)
|
||||
{
|
||||
log(ERROR,
|
||||
"Usage:\n%s start|stop|restart [--daemonize=yes|no]", argv);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fork_flag = 1, task;
|
||||
|
||||
if (argc < 2 || argc > 3) {
|
||||
usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "start"))
|
||||
task = 1;
|
||||
else if (!strcmp(argv[1], "stop"))
|
||||
task = 2;
|
||||
else if (!strcmp(argv[1], "restart"))
|
||||
task = 3;
|
||||
else {
|
||||
usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
if (!strcmp("--daemonize=yes", argv[2]))
|
||||
fork_flag = 1;
|
||||
else if (!strcmp("--daemonize=no", argv[2]))
|
||||
fork_flag = 0;
|
||||
else {
|
||||
usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (confparse() != 0) {
|
||||
log(ERROR, "Failed to parse the conf!");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
log(VERBOSE, "Conf parser finished successfully");
|
||||
//confexport();
|
||||
|
||||
if (task == 2 || task == 3) {
|
||||
char buf[10];
|
||||
int pid;
|
||||
FILE *fp;
|
||||
|
||||
if (task == 2)
|
||||
log(VERBOSE, "We got a stop signal!");
|
||||
else if (task == 3)
|
||||
log(VERBOSE, "We got a restart signal!");
|
||||
|
||||
fp = fopen(conf.rmps.pidfile, "r");
|
||||
|
||||
switch (errno) {
|
||||
case EEXIST:
|
||||
if (!fgets(buf, 10, fp)) {
|
||||
log(ERROR, "Failed to read %s!",
|
||||
conf.rmps.pidfile);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pid = strtol(buf, NULL, 10);
|
||||
kill(pid, SIGTERM);
|
||||
//waitpid(TODO);
|
||||
break;
|
||||
case EACCES:
|
||||
log(ERROR, "Permission denied to read PID. Exiting!");
|
||||
exit(EXIT_FAILURE);
|
||||
case ENOENT:
|
||||
if (task == 2)
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
default:
|
||||
log(ERROR,
|
||||
"Failed to open PID file (errno: %d. Exiting!",
|
||||
errno);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (task == 1 || task == 3)
|
||||
launch_rmps(&conf, fork_flag);
|
||||
|
||||
return 0;
|
||||
}
|
||||
3
src/protocol.c
Normal file
3
src/protocol.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "protocol.h"
|
||||
|
||||
|
||||
41
src/protocol.h
Normal file
41
src/protocol.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef PROTOCOL_H
|
||||
#define PROTOCOL_H
|
||||
|
||||
#define CHUNKSIZE 2048
|
||||
|
||||
enum msg_types {
|
||||
UNIX,
|
||||
POWERSHELL,
|
||||
INSTALL_PKG,
|
||||
QUERY_PKG,
|
||||
DELETE_PKG,
|
||||
LIST_PKGS,
|
||||
UPDATE_PKG,
|
||||
UPDATE_PKGS,
|
||||
GET_OS,
|
||||
GET_KERNEL,
|
||||
GET_UPTIME,
|
||||
GET_MEMORY
|
||||
};
|
||||
|
||||
struct msg_meta_t {
|
||||
unsigned short id; /* Agent job ID */
|
||||
unsigned short type; /* Data type */
|
||||
unsigned int len; /* Data size to expect in buffer */
|
||||
unsigned int chunks;
|
||||
short is_recv;
|
||||
short locking;
|
||||
short isjob;
|
||||
};
|
||||
|
||||
struct msg_chunk_t {
|
||||
int id;
|
||||
unsigned char data[CHUNKSIZE];
|
||||
};
|
||||
|
||||
struct msg_t {
|
||||
struct msg_meta_t meta;
|
||||
struct msg_chunk_t chunk;
|
||||
};
|
||||
|
||||
#endif /* PROTOCOL_H */
|
||||
313
src/rmps.c
Normal file
313
src/rmps.c
Normal file
@@ -0,0 +1,313 @@
|
||||
#include "log.h"
|
||||
#include "confparser.h"
|
||||
#include "agent_pool.h"
|
||||
#include "client_pool.h"
|
||||
#include "job_queue.h"
|
||||
#include "rmps.h"
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* included for openssl */
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
static void rmps_shutdown(void);
|
||||
static void signal_handler(int sig);
|
||||
static void set_env(void);
|
||||
static void daemonize(const char *rundir);
|
||||
static void spawn_pidfile(const char *pidfile);
|
||||
static inline int set_reuse_addr(int sockfd);
|
||||
static int open_listener(int port);
|
||||
static void cleanup(void);
|
||||
static void signal_handler(int sig);
|
||||
static void load_certificates(SSL_CTX *ctx, const char *certfile,
|
||||
const char *keyfile, const char *cafile);
|
||||
static SSL_CTX *init_server_ctx(const char *cipherlist, int mode);
|
||||
|
||||
static int pid_file_handle;
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
log(VERBOSE, "Deleting pidfile %s", conf.rmps.pidfile);
|
||||
if (unlink(conf.rmps.pidfile) != 0)
|
||||
log(WARNING,
|
||||
"Failed to delete pidfile %s. Reason code: %d",
|
||||
conf.rmps.pidfile, errno);
|
||||
}
|
||||
|
||||
static void signal_handler(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
log(WARNING, "Received SIGHUP signal. Ignoring...");
|
||||
break;
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
log(INFO, "Received SIGTERM signal.");
|
||||
log(INFO, "RMPS is shutting down...");
|
||||
rmps_shutdown();
|
||||
log(INFO, "RMPS has been stopped properly.");
|
||||
_exit(EXIT_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
log(WARNING, "Unhandled signal %s", strsignal(sig));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rmps_shutdown(void)
|
||||
{
|
||||
close(pid_file_handle);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
static void set_env(void)
|
||||
{
|
||||
struct sigaction new_sigaction;
|
||||
sigset_t new_sigset;
|
||||
|
||||
/* Set signal mask - signals we want to block */
|
||||
sigemptyset(&new_sigset);
|
||||
sigaddset(&new_sigset, SIGCHLD); /* ignore child */
|
||||
sigaddset(&new_sigset, SIGTSTP); /* ignore Tty stop signals */
|
||||
sigaddset(&new_sigset, SIGTTOU); /* ignore Tty background writes */
|
||||
sigaddset(&new_sigset, SIGTTIN); /* ignore Tty background reads */
|
||||
sigprocmask(SIG_BLOCK, &new_sigset, NULL); /* Block above signals */
|
||||
|
||||
/* Set up a signal handler */
|
||||
new_sigaction.sa_handler = signal_handler;
|
||||
sigemptyset(&new_sigaction.sa_mask);
|
||||
new_sigaction.sa_flags = 0;
|
||||
|
||||
/* Signals to handle */
|
||||
sigaction(SIGHUP, &new_sigaction, NULL); /* catch hangup signal */
|
||||
sigaction(SIGTERM, &new_sigaction, NULL); /* catch term signal */
|
||||
sigaction(SIGINT, &new_sigaction, NULL); /* catch interrupt signal */
|
||||
signal(SIGPIPE, SIG_IGN); /* prevent crashing from bad writes */
|
||||
}
|
||||
|
||||
static void daemonize(const char *rundir)
|
||||
{
|
||||
int pid, sid, i;
|
||||
/* Check if parent process id is set */
|
||||
if (getppid() == 1) {
|
||||
/* PPID exists, therefore we are already a daemon */
|
||||
return;
|
||||
}
|
||||
/* Fork*/
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
/* Could not fork */
|
||||
log(ERROR, "Failed to fork the parent process. Exiting!");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (pid > 0) {
|
||||
/* Child created ok, so exit parent process */
|
||||
log(INFO, "Child process created: %d", pid);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
/* Child continues */
|
||||
umask(027); /* Set file permissions 750 */
|
||||
/* Get a new process group */
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
log(ERROR, "Failed to create a process group. Exiting!");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* Close all file descriptors because we fork */
|
||||
close(0); /* stdin */
|
||||
close(1); /* stdout */
|
||||
close(2); /* stderr */
|
||||
/* Route I/O connections */
|
||||
/* Open STDIN */
|
||||
i = open("/dev/null", O_RDWR);
|
||||
/* STDOUT */
|
||||
dup(i);
|
||||
/* STDERR */
|
||||
dup(i);
|
||||
chdir(rundir); /* change running directory */
|
||||
}
|
||||
|
||||
static void spawn_pidfile(const char *pidfile)
|
||||
{
|
||||
char str[10];
|
||||
/* Ensure only one copy */
|
||||
pid_file_handle = open(pidfile, O_RDWR|O_CREAT, 0600);
|
||||
if (pid_file_handle == -1) {
|
||||
/* Couldn't open lock file */
|
||||
log(ERROR, "Could not create PID file %s - Exiting!", pidfile);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
atexit(cleanup);
|
||||
|
||||
/* Try to lock file */
|
||||
if (lockf(pid_file_handle, F_TLOCK, 0) == -1) {
|
||||
/* Couldn't get lock on lock file */
|
||||
log(ERROR, "Could not lock PID file %s - Exiting!", pidfile);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Get and format PID */
|
||||
sprintf(str, "%d\n", getpid());
|
||||
/* write pid to lockfile */
|
||||
write(pid_file_handle, str, strlen(str));
|
||||
}
|
||||
|
||||
static inline int set_reuse_addr(int sockfd)
|
||||
{
|
||||
int yes = 1;
|
||||
|
||||
return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
|
||||
&yes, sizeof(yes));
|
||||
}
|
||||
|
||||
static int open_listener(int port)
|
||||
{
|
||||
int sd;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
bzero(&addr, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
sd = socket(addr.sin_family, SOCK_STREAM, 0);
|
||||
if (sd < 0) {
|
||||
log(ERROR, "Failed to create socket - Aborting RMPS...");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (set_reuse_addr(sd) < 0) {
|
||||
log(ERROR,
|
||||
"Failed to set reuse on address - Aborting RMPS...", port);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
|
||||
log(ERROR, "Failed to bind on port: %d - Aborting RMPS...", port);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (listen(sd, 10) != 0) {
|
||||
log(ERROR, "Failed to start listener on port %d - Aborting RMPS...", port);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return sd;
|
||||
}
|
||||
|
||||
/* Init server and create context */
|
||||
static SSL_CTX *init_server_ctx(const char *cipherlist, int mode)
|
||||
{
|
||||
SSL_CTX *ctx;
|
||||
char ciphers[1024];
|
||||
|
||||
// OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
|
||||
// OpenSSL_add_all_ciphers(); /* load & register all cryptos, etc. */
|
||||
SSL_load_error_strings(); /* load all error messages */
|
||||
SSL_library_init();
|
||||
|
||||
/* create new context from method */
|
||||
ctx = SSL_CTX_new(TLS_method());
|
||||
if (ctx == NULL) {
|
||||
log(ERROR, "SSL_CTX_new() returned NULL - Aborting...");
|
||||
log(ERROR, "RMPS failed to start, shutting down...");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
SSL_CTX_set_verify(ctx, mode, NULL);
|
||||
|
||||
ciphers[0] = 0;
|
||||
strcat(ciphers, "-ALL"); /* Disable any ciphers we have by default */
|
||||
strcat(ciphers, cipherlist);
|
||||
/* This is very delicate, try to understand the ciphers */
|
||||
SSL_CTX_set_cipher_list(ctx, cipherlist);
|
||||
log(VERBOSE, "cipherlist = %s", cipherlist);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/*-------------------------------------------*/
|
||||
/*--- LoadCertificates - load from files. ---*/
|
||||
/*-------------------------------------------*/
|
||||
void load_certificates(SSL_CTX *ctx, const char *certfile,
|
||||
const char *keyfile, const char *cafile)
|
||||
{
|
||||
/* set the local certificate from certfile */
|
||||
if (SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM) <= 0) {
|
||||
log(ERROR, "Failed to load certfile! SSL error below:");
|
||||
log_ssl();
|
||||
log(INFO, "RMPS failed to start, shutting down...");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* set the private key from KeyFile (may be the same as CertFile) */
|
||||
if (SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM) <= 0) {
|
||||
log(ERROR, "Failed to load keyfile! SSL error below:");
|
||||
log_ssl();
|
||||
log(INFO, "RMPS failed to start, shutting down...");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* verify private key */
|
||||
if (!SSL_CTX_check_private_key(ctx)) {
|
||||
log(ERROR,
|
||||
"Private key does not match the public certificate.");
|
||||
log(INFO, "RMPS failed to start, shutting down...");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (cafile != NULL) {
|
||||
SSL_CTX_set_client_CA_list(ctx,
|
||||
SSL_load_client_CA_file(cafile));
|
||||
SSL_CTX_load_verify_locations(ctx, cafile, NULL);
|
||||
//SSL_CTX_set_verify_depth(ctx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void launch_rmps(struct conf_table *conf, int fork_flag)
|
||||
{
|
||||
pthread_t pool[2];
|
||||
struct pool_data pool_args[2];
|
||||
|
||||
log(INFO, "Starting up RMPS...");
|
||||
/* Set signal handling */
|
||||
set_env();
|
||||
/* Deamonize */
|
||||
if (fork_flag)
|
||||
daemonize("/tmp/");
|
||||
/* Spawn & lock pidfile */
|
||||
spawn_pidfile(conf->rmps.pidfile);
|
||||
|
||||
/* openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days XXX -nodes
|
||||
* -nodes is for not protecing with a passphrase
|
||||
* http://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl
|
||||
*/
|
||||
pool_args[0].ctx = init_server_ctx(conf->rmps.cipherlist,
|
||||
SSL_VERIFY_PEER |
|
||||
SSL_VERIFY_CLIENT_ONCE |
|
||||
SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
|
||||
log(VERBOSE, "Loading agent certs and keys.");
|
||||
load_certificates(pool_args[0].ctx, conf->rmps.agent_tls_crt,
|
||||
conf->rmps.agent_tls_key, conf->rmps.cafile);
|
||||
log(VERBOSE, "Starting agent listener on port: %d",
|
||||
atoi(conf->rmps.agent_port));
|
||||
pool_args[0].srv = open_listener(atoi(conf->rmps.agent_port));
|
||||
pool_args[0].size = conf->rmps.agent_poolsize;
|
||||
log(VERBOSE, "Creating agent thread pool (mutex).");
|
||||
pthread_create(&pool[0], NULL, agent_pool, &pool_args[0]);
|
||||
|
||||
pool_args[1].ctx = init_server_ctx(conf->rmps.cipherlist,
|
||||
SSL_VERIFY_NONE);
|
||||
log(VERBOSE, "Loading client certs and keys.");
|
||||
load_certificates(pool_args[1].ctx, conf->rmps.client_tls_crt,
|
||||
conf->rmps.client_tls_key, conf->rmps.cafile);
|
||||
log(VERBOSE, "Starting client listener on port: %d",
|
||||
atoi(conf->rmps.client_port));
|
||||
pool_args[1].srv = open_listener(atoi(conf->rmps.client_port));
|
||||
pool_args[1].size = conf->rmps.client_poolsize;
|
||||
log(VERBOSE, "Creating client thread pool (mutex).");
|
||||
pthread_create(&pool[1], NULL, client_pool, &pool_args[1]);
|
||||
if (start_job_queue(conf->rmps.agent_poolsize) == FAIL) {
|
||||
log(ERROR,
|
||||
"On start_job_queue(), RMPS failed to start, shutting down...");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pthread_join(pool[0], NULL);
|
||||
pthread_join(pool[1], NULL);
|
||||
}
|
||||
|
||||
16
src/rmps.h
Normal file
16
src/rmps.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef RMPS_H
|
||||
#define RMPS_H
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include "confparser.h"
|
||||
|
||||
struct pool_data {
|
||||
int srv;
|
||||
SSL_CTX *ctx;
|
||||
int size;
|
||||
};
|
||||
|
||||
extern void launch_rmps(struct conf_table *conf, int fork_flag);
|
||||
|
||||
#endif /* RMPS_H */
|
||||
|
||||
57
src/sql.c
Normal file
57
src/sql.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <mysql.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "log.h"
|
||||
#include "sql.h"
|
||||
#include "confparser.h"
|
||||
|
||||
int add_user(void)
|
||||
{
|
||||
MYSQL *con = mysql_init(NULL);
|
||||
char sql[200];
|
||||
|
||||
if (con == NULL) {
|
||||
log(ERROR, "Failed to add user: %s", mysql_error(con));
|
||||
return -1;
|
||||
}
|
||||
if (mysql_real_connect(con, conf_db_hostname(), "rmps", conf_db_pass(),
|
||||
NULL, 0, NULL, 0) == NULL) {
|
||||
log(ERROR, "Failed to add user: %s", mysql_error(con));
|
||||
mysql_close(con);
|
||||
return -1;
|
||||
}
|
||||
sprintf(sql, "call addUser(`%s`, `%s`, `%s`, `%s`, `%s`, `%s`)",
|
||||
"user", "noob", "asd@asd.asd", "asdsadasdassda", "salt", "more");
|
||||
if (mysql_query(con, sql)) {
|
||||
//fprintf(stderr, "%s\n", mysql_error(con));
|
||||
|
||||
mysql_close(con);
|
||||
exit(1);
|
||||
}
|
||||
MYSQL_RES *result = mysql_store_result(con);
|
||||
|
||||
if (result == NULL) {
|
||||
log(ERROR, "Failed to add user: %s", mysql_error(con));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int num_fields = mysql_num_fields(result);
|
||||
MYSQL_ROW row;
|
||||
MYSQL_FIELD *field;
|
||||
|
||||
while ((row = mysql_fetch_row(result))) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_fields; i++) {
|
||||
if (i == 0) {
|
||||
while ((field = mysql_fetch_field(result)))
|
||||
printf("| %s ", field->name);
|
||||
printf("\n");
|
||||
}
|
||||
printf("| %s ", row[i] ? row[i] : "NULL");
|
||||
}
|
||||
}
|
||||
mysql_free_result(result);
|
||||
mysql_close(con);
|
||||
exit(0);
|
||||
}
|
||||
Reference in New Issue
Block a user