38#include "clientpipe.h"
39#include "cmdhandler.h"
42#include "scheduler/schedule.h"
43#include "scheduler/task.h"
57#include <libxml/parser.h>
63#include <sys/socket.h>
70static const char* engine_str =
"engine";
82 if (!engine)
return NULL;
84 pthread_mutex_init(&engine->signal_lock, NULL);
85 pthread_cond_init(&engine->signal_cond, NULL);
87 engine->dbcfg_list = NULL;
88 engine->taskq = schedule_create();
99 schedule_cleanup(engine->taskq);
100 pthread_mutex_destroy(&engine->signal_lock);
101 pthread_cond_destroy(&engine->signal_cond);
102 if (engine->dbcfg_list) {
112 ods_log_assert(engine);
113 ods_log_debug(
"[%s] start command handler", engine_str);
114 janitor_thread_create(&engine->cmdhandler->thread_id, workerthreadclass, (janitor_runfn_t)cmdhandler_start, engine->cmdhandler);
124 ods_status status = ODS_STATUS_OK;
128 ods_log_assert(engine);
129 ods_log_assert(engine->config);
130 ods_log_debug(
"[%s] drop privileges", engine_str);
132 if (engine->config->username && engine->config->group) {
133 ods_log_verbose(
"[%s] drop privileges to user %s, group %s",
134 engine_str, engine->config->username, engine->config->group);
135 }
else if (engine->config->username) {
136 ods_log_verbose(
"[%s] drop privileges to user %s", engine_str,
137 engine->config->username);
138 }
else if (engine->config->group) {
139 ods_log_verbose(
"[%s] drop privileges to group %s", engine_str,
140 engine->config->group);
142 if (engine->config->chroot) {
143 ods_log_verbose(
"[%s] chroot to %s", engine_str,
144 engine->config->chroot);
146 status = privdrop(engine->config->username, engine->config->group,
147 engine->config->chroot, &uid, &gid);
150 privclose(engine->config->username, engine->config->group);
163 ods_log_assert(engine);
164 ods_log_assert(engine->config);
165 engine->workers = (worker_type**) malloc(
166 (
size_t)engine->config->num_worker_threads *
sizeof(worker_type*));
167 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
168 asprintf(&name,
"worker[%d]", i+1);
169 engine->workers[i] = worker_create(name, engine->taskq);
178 ods_log_assert(engine);
179 ods_log_assert(engine->config);
180 ods_log_debug(
"[%s] start workers", engine_str);
181 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
182 engine->workers[i]->need_to_exit = 0;
184 if (!engine->workers[i]->context) {
185 ods_log_crit(
"Failed to start worker, could not connect to database");
187 janitor_thread_create(&engine->workers[i]->thread_id, workerthreadclass, (janitor_runfn_t)worker_start, engine->workers[i]);
197 ods_log_assert(engine);
198 ods_log_assert(engine->config);
199 ods_log_debug(
"[%s] stop workers", engine_str);
201 for (i=0; i < engine->config->num_worker_threads; i++) {
202 engine->workers[i]->need_to_exit = 1;
206 for (i=0; i < engine->config->num_worker_threads; i++) {
207 ods_log_debug(
"[%s] join worker %i", engine_str, i+1);
208 janitor_thread_join(engine->workers[i]->thread_id);
220 ods_log_assert(engine);
221 ods_log_debug(
"[%s] wake up workers", engine_str);
222 schedule_release_all(engine->taskq);
236 ods_log_crit(
"database connection failed");
273 fprintf(stderr,
"db_configuraiton_list_new failed\n");
284 engine->dbcfg_list = NULL;
285 fprintf(stderr,
"setup configuration backend failed\n");
295 engine->dbcfg_list = NULL;
296 fprintf(stderr,
"setup configuration file failed\n");
309 engine->dbcfg_list = NULL;
310 fprintf(stderr,
"setup configuration backend failed\n");
320 engine->dbcfg_list = NULL;
321 fprintf(stderr,
"setup configuration file failed\n");
325 if (engine->config->db_port) {
327 if (snprintf(&str[0],
sizeof(str),
"%d", engine->config->db_port) >= (
int)
sizeof(str)) {
329 engine->dbcfg_list = NULL;
330 fprintf(stderr,
"setup configuration file failed\n");
340 engine->dbcfg_list = NULL;
341 fprintf(stderr,
"setup configuration file failed\n");
353 engine->dbcfg_list = NULL;
354 fprintf(stderr,
"setup configuration file failed\n");
365 engine->dbcfg_list = NULL;
366 fprintf(stderr,
"setup configuration file failed\n");
377 engine->dbcfg_list = NULL;
378 fprintf(stderr,
"setup configuration file failed\n");
398 engine->dbcfg_list = NULL;
402signal_handler(sig_atomic_t sig)
407 engine->need_to_reload = 1;
408 pthread_mutex_lock(&engine->signal_lock);
409 pthread_cond_signal(&engine->signal_cond);
410 pthread_mutex_unlock(&engine->signal_lock);
416 engine->need_to_exit = 1;
417 pthread_mutex_lock(&engine->signal_lock);
418 pthread_cond_signal(&engine->signal_cond);
419 pthread_mutex_unlock(&engine->signal_lock);
438 ods_log_debug(
"[%s] enforcer setup", engine_str);
440 engine->pid = getpid();
442 if (!util_pidfile_avail(engine->config->pid_filename)) {
443 ods_log_error(
"[%s] Pidfile exists and process with PID is running", engine_str);
444 return ODS_STATUS_WRITE_PIDFILE_ERR;
447 if (setup_database(engine))
return ODS_STATUS_DB_ERR;
449 if (probe_database(engine)) {
450 ods_log_crit(
"Could not connect to database or database not set up properly.");
451 return ODS_STATUS_DB_ERR;
456 if (!engine->cmdhandler) {
457 ods_log_error(
"[%s] create command handler to %s failed",
458 engine_str, engine->config->clisock_filename);
459 return ODS_STATUS_CMDHANDLER_ERR;
463 ods_log_error(
"[%s] unable to pipe: %s", engine_str, strerror(errno));
464 return ODS_STATUS_PIPE_ERR;
467 if (!engine->init_setup_done) {
469 engine->uid = privuid(engine->config->username);
470 engine->gid = privgid(engine->config->group);
473 ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
474 ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
475 ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
476 if (engine->config->log_filename && !engine->config->use_syslog) {
477 ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
479 if (engine->config->working_dir &&
480 chdir(engine->config->working_dir) != 0) {
481 ods_log_error(
"[%s] chdir to %s failed: %s", engine_str,
482 engine->config->working_dir, strerror(errno));
483 return ODS_STATUS_CHDIR_ERR;
485 if (engine_privdrop(engine) != ODS_STATUS_OK) {
486 ods_log_error(
"[%s] unable to drop privileges", engine_str);
487 return ODS_STATUS_PRIVDROP_ERR;
491 if (engine->daemonize) {
494 ods_log_error(
"[%s] unable to fork daemon: %s",
495 engine_str, strerror(errno));
496 return ODS_STATUS_FORK_ERR;
498 if ((fd = open(
"/dev/null", O_RDWR, 0)) != -1) {
499 (void)dup2(fd, STDIN_FILENO);
500 (void)dup2(fd, STDOUT_FILENO);
501 (void)dup2(fd, STDERR_FILENO);
502 if (fd > 2) (void)close(fd);
509 while (read(pipefd[0], &buff, 1) != -1) {
510 if (buff <= 1)
break;
515 ods_log_error(
"[%s] fail to start enforcerd completely", engine_str);
518 ods_log_debug(
"[%s] enforcerd started successfully", engine_str);
521 if (setsid() == -1) {
522 ods_log_error(
"[%s] unable to setsid daemon (%s)",
523 engine_str, strerror(errno));
524 const char *err =
"unable to setsid daemon: ";
525 ods_writen(pipefd[1], err, strlen(err));
526 ods_writeln(pipefd[1], strerror(errno));
527 write(pipefd[1],
"\0", 1);
529 return ODS_STATUS_SETSID_ERR;
533 engine->init_setup_done = 1;
535 engine->pid = getpid();
536 ods_log_info(
"[%s] running as pid %lu", engine_str,
537 (
unsigned long) engine->pid);
540 engine_create_workers(engine);
543 if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
545 ods_log_error(
"[%s] unable to write pid file", engine_str);
546 if (engine->daemonize) {
547 ods_writeln(pipefd[1],
"unable to write pid file");
548 write(pipefd[1],
"\0", 1);
551 return ODS_STATUS_WRITE_PIDFILE_ERR;
553 ods_log_info(
"[%s] enforcer started", engine_str);
554 error = hsm_open2(engine->config->repositories, hsm_prompt_pin);
555 if (error != HSM_OK) {
556 char* errorstr = hsm_get_error(NULL);
558 (void)asprintf(&errorstr,
"error opening libhsm (errno %i)", error);
560 ods_log_error(
"[%s] %s", engine_str, errorstr);
561 if (engine->daemonize) {
562 if (errorstr) ods_writeln(pipefd[1], errorstr);
563 write(pipefd[1],
"\0", 1);
567 return ODS_STATUS_HSM_ERR;
569 engine->need_to_reload = 0;
570 engine_start_cmdhandler(engine);
572 write(pipefd[1],
"\1", 1);
574 if (!engine->daemonize) close(pipefd[0]);
575 engine->daemonize = 0;
576 return ODS_STATUS_OK;
589 if (engine->config) {
590 if (engine->config->pid_filename) {
591 (void)unlink(engine->config->pid_filename);
593 if (engine->config->clisock_filename) {
594 (void)unlink(engine->config->clisock_filename);
597 if (engine->workers && engine->config) {
598 for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
599 worker_cleanup(engine->workers[i]);
601 free(engine->workers);
602 engine->workers = NULL;
604 if (engine->cmdhandler) {
605 cmdhandler_cleanup(engine->cmdhandler);
606 engine->cmdhandler = NULL;
608 desetup_database(engine);
614 struct sigaction action;
616 engine->config = NULL;
617 engine->workers = NULL;
618 engine->cmdhandler = NULL;
619 engine->init_setup_done = 0;
620 engine->pid = getpid();
623 engine->need_to_exit = 0;
624 engine->need_to_reload = 0;
625 engine->daemonize = daemonize;
627 action.sa_handler = (void (*)(int))signal_handler;
628 sigfillset(&action.sa_mask);
630 sigaction(SIGHUP, &action, NULL);
631 sigaction(SIGTERM, &action, NULL);
632 sigaction(SIGINT, &action, NULL);
633 engine->dbcfg_list = NULL;
634 action.sa_handler = SIG_IGN;
635 sigaction(SIGPIPE, &action, NULL);
645 ods_log_assert(engine);
652 while (!engine->need_to_exit && !engine->need_to_reload) {
654 engine->need_to_exit = 1;
661 pthread_mutex_lock(&engine->signal_lock);
662 if (!engine->need_to_exit && !engine->need_to_reload && !single_run) {
667 ods_log_debug(
"[%s] taking a break", engine_str);
668 pthread_cond_wait(&engine->signal_cond, &engine->signal_lock);
670 pthread_mutex_unlock(&engine->signal_lock);
672 ods_log_debug(
"[%s] enforcer halted", engine_str);
674 cmdhandler_stop(engine->cmdhandler);
675 schedule_purge(engine->taskq);
@ ENFORCER_DATABASE_TYPE_MYSQL
@ ENFORCER_DATABASE_TYPE_SQLITE
int database_version_get_version(db_connection_t *connection)
db_configuration_t * db_configuration_new(void)
db_configuration_list_t * db_configuration_list_new(void)
void db_configuration_free(db_configuration_t *configuration)
int db_configuration_set_name(db_configuration_t *configuration, const char *name)
int db_configuration_list_add(db_configuration_list_t *configuration_list, db_configuration_t *configuration)
int db_configuration_set_value(db_configuration_t *configuration, const char *value)
void db_configuration_list_free(db_configuration_list_t *configuration_list)
struct db_configuration db_configuration_t
int db_connection_connect(const db_connection_t *connection)
db_connection_t * db_connection_new(void)
int db_connection_setup(db_connection_t *connection)
void db_connection_free(db_connection_t *connection)
int db_connection_set_configuration_list(db_connection_t *connection, const db_configuration_list_t *configuration_list)
struct db_connection db_connection_t
struct cmd_func_block ** enforcercommands
void engine_teardown(engine_type *engine)
void engine_init(engine_type *engine, int daemonize)
void engine_dealloc(engine_type *engine)
engine_type * engine_alloc(void)
void engine_wakeup_workers(engine_type *engine)
void engine_start_workers(engine_type *engine)
int engine_run(engine_type *engine, start_cb_t start, int single_run)
void engine_stop_workers(engine_type *engine)
db_connection_t * get_database_connection(engine_type *engine)
ods_status engine_setup()
void(* start_cb_t)(engine_type *engine)
struct engine_struct engine_type
void hsm_key_factory_deinit(void)