diff --git a/config.c b/config.c index ef31489..2d36301 100644 --- a/config.c +++ b/config.c @@ -15,6 +15,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + +/* TODO: + * - Have each event protocol definition get its own configuration directives + */ + #include "includes.h" /* My global state */ @@ -23,6 +28,10 @@ const char *process_name = NULL; struct rsa_public_key *public_key = NULL; struct rsa_private_key *private_key = NULL; +configuration *get_modifiable_conf(void) { + return conf; +} + const configuration *get_conf(void) { return conf; } @@ -51,100 +60,107 @@ STATUS set_rsa_keys(struct rsa_public_key *pub, struct rsa_private_key *priv) { return ST_OK; } +STATUS read_rsa_keys(void) { + int res; + FILE *file; + uint8_t buf[1024]; + struct rsa_private_key *priv; + struct rsa_public_key *pub; + uint8_t *buffer = NULL; + size_t n, size=0; + + priv = talloc(conf, struct rsa_private_key); + pub = talloc(conf, struct rsa_public_key); + + rsa_public_key_init (pub); + rsa_private_key_init (priv); + + file = fopen(conf->rsa_key_file, "r"); + if (file == NULL) { + DEBUG(0, "Can't open configured rsa key file: %s", conf->rsa_key_file); + exit(ST_CONFIGURATION_ERROR); + } + + while (1) { + n = fread(&buf, 1, 1024, file); + buffer = talloc_realloc(conf, buffer, uint8_t, size + n); + memcpy(buffer + size, buf, n); + size += n; + if (n < 1024) + break; + } + + fclose(file); + + res = rsa_keypair_from_sexp(pub, priv, 0, size, buffer); + + conf->public_key = pub; + conf->private_key = priv; + + return res; +} STATUS read_configuration_file(TALLOC_CTX *mem_ctx) { GError *error = NULL; - GKeyFile *keyfile = g_key_file_new (); - - if (!g_key_file_load_from_file (keyfile, CONFIGFILE, 0, &error)) { - g_error (error->message); - return ST_CONFIGURATION_ERROR; - } + char *buf, *ptr; conf = talloc(mem_ctx, configuration); NO_MEM_RETURN(conf); - conf->database_host = g_key_file_get_string(keyfile, "database", - "host", &error); - if (error) { - fprintf(stderr, "No database host supplied in the configuration.\n"); - return ST_CONFIGURATION_ERROR; - } - conf->database_name = g_key_file_get_string(keyfile, "database", - "name", &error); - if (error) { - fprintf(stderr, "No database name supplied in the configuration.\n"); - return ST_CONFIGURATION_ERROR; - } - conf->database_driver = g_key_file_get_string(keyfile, "database", - "driver", &error); - if (error) { - fprintf(stderr, "No database driver supplied in the configuration.\n"); - return ST_CONFIGURATION_ERROR; - } - conf->database_username = g_key_file_get_string(keyfile, "database", - "username", &error); - if (error) { - fprintf(stderr, "No database username supplied in the configuration.\n"); - return ST_CONFIGURATION_ERROR; - } - conf->database_password = g_key_file_get_string(keyfile, "database", - "password", &error); - if (error) { - fprintf(stderr, "No database password supplied in the configuration.\n"); + conf->keyfile = g_key_file_new (); + + if (!g_key_file_load_from_file (conf->keyfile, CONFIGFILE, 0, &error)) { + g_error (error->message); return ST_CONFIGURATION_ERROR; } - conf->log_file = g_key_file_get_string(keyfile, "siahsd", "log file", &error); + buf = g_key_file_get_string(conf->keyfile, "siahsd", "event handlers", &error); if (error) { fprintf(stderr, "No log file supplied in the configuration.\n"); return ST_CONFIGURATION_ERROR; } - conf->log_level = g_key_file_get_integer(keyfile, "siahsd", "log level", &error); + + DEBUG(0, "%s\n", buf); + /* Initialize the required event handler backends */ + ptr = strtok(buf, " "); + if (ptr != NULL) { + do { + DEBUG(0, "%s\n", ptr); + if (strcmp(ptr, "database") == 0) { + database_init(); + } else if (strcmp(ptr, "jsonbot") == 0) { + jsonbot_init(); + } + } while((ptr = strtok(NULL, " ")) != NULL); + } + + conf->log_file = g_key_file_get_string(conf->keyfile, "siahsd", "log file", &error); + if (error) { + fprintf(stderr, "No log file supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + conf->log_level = g_key_file_get_integer(conf->keyfile, "siahsd", "log level", &error); if (error) { fprintf(stderr, "No log level supplied in the configuration.\n"); return ST_CONFIGURATION_ERROR; } - conf->pid_file = g_key_file_get_string(keyfile, "siahsd", "pid file", &error); + conf->pid_file = g_key_file_get_string(conf->keyfile, "siahsd", "pid file", &error); if (error) { fprintf(stderr, "No pid file supplied in the configuration.\n"); return ST_CONFIGURATION_ERROR; } - conf->jsonbot_address = g_key_file_get_string(keyfile, "jsonbot", "address", &error); - if (error) { - fprintf(stderr, "No jsonbot address supplied in the configuration.\n"); - return ST_CONFIGURATION_ERROR; - } - conf->jsonbot_port = g_key_file_get_integer(keyfile, "jsonbot", "port", &error); - if (error) { - fprintf(stderr, "No jsonbot port supplied in the configuration.\n"); - return ST_CONFIGURATION_ERROR; - } - conf->jsonbot_aeskey = g_key_file_get_string(keyfile, "jsonbot", "aes key", &error); - if (error) { - fprintf(stderr, "No jsonbot aes key supplied in the configuration.\n"); - return ST_CONFIGURATION_ERROR; - } - conf->jsonbot_password = g_key_file_get_string(keyfile, "jsonbot", "password", &error); - if (error) { - fprintf(stderr, "No jsonbot password supplied in the configuration.\n"); - return ST_CONFIGURATION_ERROR; - } - conf->jsonbot_privmsg_to = g_key_file_get_string(keyfile, "jsonbot", "privmsg to", &error); - if (error) { - fprintf(stderr, "No jsonbot privsmg to supplied in the configuration.\n"); - return ST_CONFIGURATION_ERROR; - } - conf->foreground = g_key_file_get_boolean(keyfile, "siahsd", "foreground", &error); + + conf->foreground = g_key_file_get_boolean(conf->keyfile, "siahsd", "foreground", &error); if (error) { conf->foreground = false; } - /* Optional parameters are protocol-specific */ - conf->siahs_port = g_key_file_get_integer(keyfile, "siahs", "port", &error); - conf->secip_port = g_key_file_get_integer(keyfile, "secip", "port", &error); - conf->rsa_key_file = g_key_file_get_string(keyfile, "secip", "rsa key file", &error); + /* Optional parameters are protocol-specific */ + /* FIXME Warn the user when these aren't configured */ + conf->siahs_port = g_key_file_get_integer(conf->keyfile, "siahs", "port", &error); + conf->secip_port = g_key_file_get_integer(conf->keyfile, "secip", "port", &error); + conf->rsa_key_file = g_key_file_get_string(conf->keyfile, "secip", "rsa key file", &error); return ST_OK; } diff --git a/config.h b/config.h index 9e3e65b..041b7ad 100644 --- a/config.h +++ b/config.h @@ -18,30 +18,49 @@ #define CONFIGFILE "/etc/siahsd.conf" +typedef STATUS (*event_function)(TALLOC_CTX *mem_ctx, const char *prom, const char *code, const char *description); + typedef struct { + /* Global configuration */ + char *log_file; + gint log_level; + gboolean foreground; + char *pid_file; /* FIXME Apparently the same for siahs and secip.. for now */ + + /* Alphatronics SIA-HS configuration */ + gint siahs_port; + + /* Vebon SecIP configuration */ + gint secip_port; + char *rsa_key_file; + + /* Database client configuration */ char *database_host; char *database_username; char *database_password; char *database_name; char *database_driver; - gint siahs_port; - char *log_file; - gint log_level; - gboolean foreground; - char *pid_file; - gint secip_port; - char *rsa_key_file; + + /* JSONbot client configuration */ char *jsonbot_address; gint jsonbot_port; char *jsonbot_aeskey; char *jsonbot_password; char *jsonbot_privmsg_to; + + /* Global configuration based state */ + GKeyFile *keyfile; + uint8_t event_handler_cnt; + event_function *event_handlers; + struct rsa_public_key *public_key; + struct rsa_private_key *private_key; } configuration; const configuration *get_conf(void); -STATUS get_rsa_keys(struct rsa_public_key **pub, struct rsa_private_key **priv); -STATUS set_rsa_keys(struct rsa_public_key *pub, struct rsa_private_key *priv); +configuration *get_modifiable_conf(void); + +STATUS read_rsa_keys(void); const char *get_process_name(void); STATUS set_process_name(const char *name); diff --git a/database.c b/database.c index ca90b92..ae919d3 100644 --- a/database.c +++ b/database.c @@ -18,6 +18,8 @@ #include "includes.h" +static dbi_conn conn; + /* * talloc_quoted_string escapes quotes in a string and encapsulates it in quotes. * It returns a pointer to talloc'ed memory, the quoted string. @@ -45,7 +47,7 @@ static char *talloc_quoted_string(TALLOC_CTX *mem_ctx, const char *string) { return ret; } -STATUS log_event_to_database(TALLOC_CTX *mem_ctx, dbi_conn conn, const char *prom, const char *code, const char *description) { +STATUS log_event_to_database(TALLOC_CTX *mem_ctx, const char *prom, const char *code, const char *description) { char *quoted_prom; char *quoted_code; char *quoted_long_code; @@ -73,22 +75,60 @@ STATUS log_event_to_database(TALLOC_CTX *mem_ctx, dbi_conn conn, const char *pro return ST_OK; } -STATUS connect_to_database(dbi_conn *conn) + + +STATUS database_init(void) { - const configuration *conf = get_conf(); + configuration *conf = get_modifiable_conf(); + GError *error = NULL; + + conf->database_host = g_key_file_get_string(conf->keyfile, "database", + "host", &error); + if (error) { + fprintf(stderr, "No database host supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + conf->database_name = g_key_file_get_string(conf->keyfile, "database", + "name", &error); + if (error) { + fprintf(stderr, "No database name supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + conf->database_driver = g_key_file_get_string(conf->keyfile, "database", + "driver", &error); + if (error) { + fprintf(stderr, "No database driver supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + conf->database_username = g_key_file_get_string(conf->keyfile, "database", + "username", &error); + if (error) { + fprintf(stderr, "No database username supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + conf->database_password = g_key_file_get_string(conf->keyfile, "database", + "password", &error); + if (error) { + fprintf(stderr, "No database password supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + + conf->event_handlers = talloc_realloc(conf, conf->event_handlers, event_function, conf->event_handler_cnt+1); + conf->event_handlers[conf->event_handler_cnt] = log_event_to_database; + conf->event_handler_cnt++; DEBUG(1, "Connecting to %s database %s at %s as user %s", conf->database_driver, conf->database_name, conf->database_host, conf->database_username); dbi_initialize(NULL); - *conn = dbi_conn_new(conf->database_driver); - dbi_conn_set_option(*conn, "host", conf->database_host); - dbi_conn_set_option(*conn, "username", conf->database_username); - dbi_conn_set_option(*conn, "password", conf->database_password); - dbi_conn_set_option(*conn, "dbname", conf->database_name); - dbi_conn_set_option(*conn, "encoding", "UTF-8"); + conn = dbi_conn_new(conf->database_driver); + dbi_conn_set_option(conn, "host", conf->database_host); + dbi_conn_set_option(conn, "username", conf->database_username); + dbi_conn_set_option(conn, "password", conf->database_password); + dbi_conn_set_option(conn, "dbname", conf->database_name); + dbi_conn_set_option(conn, "encoding", "UTF-8"); - if (dbi_conn_connect(*conn) < 0) { + if (dbi_conn_connect(conn) < 0) { DEBUG(0, "Could not connect to the database"); return ST_DATABASE_FAILURE; } diff --git a/database.h b/database.h index 9daf99d..c5be413 100644 --- a/database.h +++ b/database.h @@ -16,5 +16,5 @@ along with this program. If not, see . */ -STATUS log_event_to_database(TALLOC_CTX *mem_ctx, dbi_conn conn, const char *prom, const char *code, const char *description); -STATUS connect_to_database(dbi_conn *conn); +STATUS log_event_to_database(TALLOC_CTX *mem_ctx, const char *prom, const char *code, const char *description); +STATUS database_init(void); diff --git a/jsonbot.c b/jsonbot.c index 8e39d7a..ce11fa1 100644 --- a/jsonbot.c +++ b/jsonbot.c @@ -21,7 +21,7 @@ #include -STATUS jsonbot_notify(TALLOC_CTX *mem_ctx, dbi_conn conn, const char *prom, const char *code, const char *description) +STATUS jsonbot_notify(TALLOC_CTX *mem_ctx, const char *prom, const char *code, const char *description) { int sockfd; struct sockaddr_in servaddr; @@ -77,3 +77,40 @@ STATUS jsonbot_notify(TALLOC_CTX *mem_ctx, dbi_conn conn, const char *prom, cons return ST_OK; } + +STATUS jsonbot_init(void) { + GError *error = NULL; + configuration *conf = get_modifiable_conf(); + + conf->jsonbot_address = g_key_file_get_string(conf->keyfile, "jsonbot", "address", &error); + if (error) { + fprintf(stderr, "No jsonbot address supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + conf->jsonbot_port = g_key_file_get_integer(conf->keyfile, "jsonbot", "port", &error); + if (error) { + fprintf(stderr, "No jsonbot port supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + conf->jsonbot_aeskey = g_key_file_get_string(conf->keyfile, "jsonbot", "aes key", &error); + if (error) { + fprintf(stderr, "No jsonbot aes key supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + conf->jsonbot_password = g_key_file_get_string(conf->keyfile, "jsonbot", "password", &error); + if (error) { + fprintf(stderr, "No jsonbot password supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + conf->jsonbot_privmsg_to = g_key_file_get_string(conf->keyfile, "jsonbot", "privmsg to", &error); + if (error) { + fprintf(stderr, "No jsonbot privsmg to supplied in the configuration.\n"); + return ST_CONFIGURATION_ERROR; + } + + conf->event_handlers = talloc_realloc(conf, conf->event_handlers, event_function, conf->event_handler_cnt+1); + conf->event_handlers[conf->event_handler_cnt] = jsonbot_notify; + conf->event_handler_cnt++; + + return ST_OK; +} diff --git a/jsonbot.h b/jsonbot.h index f1df4c0..caa0848 100644 --- a/jsonbot.h +++ b/jsonbot.h @@ -18,4 +18,5 @@ */ -STATUS jsonbot_notify(TALLOC_CTX *mem_ctx, dbi_conn conn, const char *prom, const char *code, const char *description); +STATUS jsonbot_notify(TALLOC_CTX *mem_ctx, const char *prom, const char *code, const char *description); +STATUS jsonbot_init(void); diff --git a/secipd.c b/secipd.c index 236fe1a..067b2ab 100644 --- a/secipd.c +++ b/secipd.c @@ -18,55 +18,15 @@ #include "includes.h" #include "build/ndr_secip.h" -static int read_rsa_keys(void) { - int res; - FILE *file; - uint8_t buf[1024]; - struct rsa_private_key *priv; - struct rsa_public_key *pub; - const configuration *conf = get_conf(); - uint8_t *buffer = NULL; - size_t n, size=0; - priv = talloc(conf, struct rsa_private_key); - pub = talloc(conf, struct rsa_public_key); - - rsa_public_key_init (pub); - rsa_private_key_init (priv); - - file = fopen(conf->rsa_key_file, "r"); - if (file == NULL) { - DEBUG(0, "Can't open configured rsa key file: %s", conf->rsa_key_file); - exit(ST_CONFIGURATION_ERROR); - } - - while (1) { - n = fread(&buf, 1, 1024, file); - buffer = talloc_realloc(conf, buffer, uint8_t, size + n); - memcpy(buffer + size, buf, n); - size += n; - if (n < 1024) - break; - } - - fclose(file); - - res = rsa_keypair_from_sexp(pub, priv, 0, size, buffer); - - set_rsa_keys(pub, priv); - - return res; -} - -STATUS send_ppk_com(TALLOC_CTX *mem_ctx, int sock, struct sockaddr_in from, struct secip_packet *pkt) { +static STATUS send_ppk_com(TALLOC_CTX *mem_ctx, int sock, struct sockaddr_in from, struct secip_packet *pkt) { struct secip_setup_packet *setup_pkt; struct secip_out_packet *ppk_com; DATA_BLOB raw_pkt, raw_setup_pkt; enum ndr_err_code ndr_err; size_t n; - struct rsa_private_key *priv; - struct rsa_public_key *pub; size_t count; + const configuration *conf = get_conf(); setup_pkt = talloc_zero(mem_ctx, struct secip_setup_packet); @@ -78,9 +38,7 @@ STATUS send_ppk_com(TALLOC_CTX *mem_ctx, int sock, struct sockaddr_in from, stru memcpy(ppk_com->device_id, "MyFirstAlarm[TM]", strlen("MyFirstAlarm[TM]")); ppk_com->msg.ppk_com.session_id = 0; - get_rsa_keys(&pub, &priv); - - mpz_export(&ppk_com->msg.ppk_com.rsa_key, &count, 1, 4, 1, 0, pub->n); + mpz_export(&ppk_com->msg.ppk_com.rsa_key, &count, 1, 4, 1, 0, conf->public_key->n); DEBUG(0, "RSA Words written: %u", count); printf("%s\n", ndr_print_struct_string(pkt,(ndr_print_fn_t)ndr_print_secip_out_packet, "ppk_com packet", ppk_com)); @@ -116,7 +74,6 @@ int main (int argc, char **argv) { struct sockaddr_in server; struct sockaddr_in from; TALLOC_CTX *mem_ctx; - dbi_conn conn; STATUS rv; FILE *pidfile; pid_t pid; @@ -176,11 +133,6 @@ int main (int argc, char **argv) { DEBUG(0, "Started %s and waiting for SecIP packets on port %d", get_process_name(), conf->secip_port); - /* Open a connection to the database */ - rv = connect_to_database(&conn); - if (rv != ST_OK) - return rv; - /* * Wait for packets */ diff --git a/siahsd.c b/siahsd.c index b6477a4..8375609 100644 --- a/siahsd.c +++ b/siahsd.c @@ -34,12 +34,14 @@ * and writes the event to the database. * It returns nothing. */ -STATUS parse_message(TALLOC_CTX *mem_ctx, dbi_conn conn, struct siahs_packet *pkt) { +STATUS parse_message(TALLOC_CTX *mem_ctx, struct siahs_packet *pkt) { char *message = talloc_strdup(mem_ctx, pkt->message + strlen("MESSAGE ")); char *ptr = message; char *prom = ptr; char *pkt_prom; char *code; + const configuration *conf = get_conf(); + uint8_t i; NO_MEM_RETURN(message); @@ -75,8 +77,10 @@ STATUS parse_message(TALLOC_CTX *mem_ctx, dbi_conn conn, struct siahs_packet *pk return ST_OK; } - log_event_to_database(message, conn, prom, code, ptr); - jsonbot_notify(message, conn, prom, code, ptr); + /* Dispatch all configured event handlers */ + for (i = 0; conf->event_handlers[i] != NULL; i++) { + conf->event_handlers[i](message, prom, code, ptr); + } talloc_free(message); @@ -156,7 +160,6 @@ int main(int argc, char **argv) { struct sockaddr_in server; struct sockaddr_in from; TALLOC_CTX *mem_ctx; - dbi_conn conn; STATUS rv; FILE *pidfile; pid_t pid; @@ -216,11 +219,6 @@ int main(int argc, char **argv) { DEBUG(0, "Started %s and waiting for SIA-HS packets on port %d", get_process_name(), conf->siahs_port); - /* Open a connection to the database */ - rv = connect_to_database(&conn); - if (rv != ST_OK) - return rv; - /* * Wait for packets */ @@ -306,7 +304,7 @@ int main(int argc, char **argv) { } else if (strncmp(pkt->message, "MESSAGE ", strlen("MESSAGE ")) == 0) { send_reply(pkt, sock, from, pkt, "ACKNOWLEDGE MESSAGE"); - parse_message(pkt, conn, pkt); + parse_message(pkt, pkt); } else { DEBUG(0, "Could not parse this message:\n" diff --git a/siahsd.conf b/siahsd.conf index 73a95f8..5b6ddaf 100644 --- a/siahsd.conf +++ b/siahsd.conf @@ -3,6 +3,7 @@ pid file = /var/run/siahsd.pid log file = /var/log/siahsd/siahsd.log log level = 3 foreground = 1 +event handlers = database jsonbot [database] driver = mysql diff --git a/status.c b/status.c index 5b3c05f..e1c693e 100644 --- a/status.c +++ b/status.c @@ -33,8 +33,11 @@ STATUS debug(int loglevel, const char *location, const char *function, ...) } logfile = fopen(conf->log_file, "a"); - if (logfile == NULL && conf->foreground) { - fprintf(stderr, "Error opening log file: %s\n", strerror(errno)); + if (logfile == NULL) { + if (conf->foreground) { + fprintf(stderr, "Error opening log file: %s\n", strerror(errno)); + } + return ST_GENERAL_FAILURE; } time(&rawtime); diff --git a/wscript b/wscript index 62b66f4..1d95917 100644 --- a/wscript +++ b/wscript @@ -90,7 +90,7 @@ def configure(conf): def build(bld): bld.stlib(source="database.c", target="database", use='glib-2.0') bld.stlib(source="status.c", target="status", use='glib-2.0') - bld.stlib(source="config.c", target="config", use='glib-2.0') + bld.stlib(source="config.c", target="config", use='glib-2.0 database jsonbot') bld.stlib(source="sia.c", target="sia", use='glib-2.0') bld.stlib(source="jsonbot.c", target="jsonbot", use='glib-2.0')