summaryrefslogtreecommitdiffstats
path: root/src/util/server.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
commit74aa0bc6779af38018a03fd2cf4419fe85917904 (patch)
tree9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/util/server.c
parentInitial commit. (diff)
downloadsssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz
sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/util/server.c')
-rw-r--r--src/util/server.c794
1 files changed, 794 insertions, 0 deletions
diff --git a/src/util/server.c b/src/util/server.c
new file mode 100644
index 0000000..34e8a6d
--- /dev/null
+++ b/src/util/server.c
@@ -0,0 +1,794 @@
+/*
+ SSSD
+
+ Servers setup routines
+
+ Copyright (C) Andrew Tridgell 1992-2005
+ Copyright (C) Martin Pool 2002
+ Copyright (C) Jelmer Vernooij 2002
+ Copyright (C) James J Myers 2003 <myersjj@samba.org>
+ Copyright (C) Simo Sorce 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <ldb.h>
+#include "util/util.h"
+#include "confdb/confdb.h"
+#include "util/sss_chain_id.h"
+#include "util/sss_chain_id_tevent.h"
+
+#ifdef HAVE_PRCTL
+#include <sys/prctl.h>
+#endif
+
+static TALLOC_CTX *autofree_ctx;
+
+static void server_atexit(void)
+{
+ talloc_zfree(autofree_ctx);
+}
+
+/*******************************************************************
+ Close the low 3 FDs and open dev/null in their place.
+********************************************************************/
+static void close_low_fds(void)
+{
+#ifndef VALGRIND
+ /* try and use up these file descriptors, so silly
+ library routines writing to stdout etc. won't cause havoc */
+ if (freopen ("/dev/null", "r", stdin) == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Can't freopen() stdin to /dev/null\n");
+ }
+ if (freopen ("/dev/null", "w", stdout) == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Can't freopen() stdout to /dev/null\n");
+ }
+ if (freopen ("/dev/null", "w", stderr) == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Can't freopen() stderr to /dev/null\n");
+ }
+#endif
+}
+
+static void daemon_parent_sigterm(int sig)
+{
+ _exit(0);
+}
+
+/**
+ Become a daemon, discarding the controlling terminal.
+**/
+
+static void become_daemon(void)
+{
+ pid_t pid, cpid;
+ int status;
+ int ret, error;
+
+ pid = fork();
+ if (pid == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_FATAL_FAILURE, "fork() failed: %d [%s]\n",
+ ret, strerror(ret));
+ sss_log(SSS_LOG_ERR, "can't start: fork() failed");
+ _exit(1);
+ }
+ if (pid != 0) {
+ /* Terminate parent process on demand so we can hold systemd
+ * or initd from starting next service until SSSD is initialized.
+ * We use signals directly here because we don't have a tevent
+ * context yet. */
+ CatchSignal(SIGTERM, daemon_parent_sigterm);
+
+ /* or exit when child process (i.e. sssd monitor) is terminated
+ * and return error in this case */
+ ret = 1;
+ do {
+ error = 0;
+ cpid = waitpid(pid, &status, 0);
+ if (cpid == -1) {
+ /* An error occurred while waiting */
+ error = errno;
+ if (error != EINTR) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Error [%d][%s] while waiting for child\n",
+ error, strerror(error));
+ /* Forcibly kill this child */
+ kill(pid, SIGKILL);
+ }
+ } else {
+ if (WIFEXITED(status)) {
+ /* return our exit code if available */
+ ret = WEXITSTATUS(status);
+ }
+ }
+ } while (error == EINTR);
+
+ _exit(ret);
+ }
+
+ /* create new session, process group and detach from the terminal */
+ if (setsid() == (pid_t) -1) {
+ ret = errno;
+ DEBUG(SSSDBG_FATAL_FAILURE, "setsid() failed: %d [%s]\n",
+ ret, strerror(ret));
+ sss_log(SSS_LOG_ERR, "can't start: setsid() failed");
+ _exit(1);
+ }
+
+ /* chdir to / to be sure we're not on a remote filesystem */
+ errno = 0;
+ if(chdir("/") == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_FATAL_FAILURE, "Cannot change directory (%d [%s])\n",
+ ret, strerror(ret));
+ }
+
+ /* Close FDs 0,1,2. Needed if started by rsh */
+ close_low_fds();
+}
+
+int check_pidfile(const char *file)
+{
+ char pid_str[32];
+ pid_t pid;
+ int fd;
+ int ret, err;
+ ssize_t len;
+ ssize_t pidlen = sizeof(pid_str) - 1;
+
+ fd = open(file, O_RDONLY, 0644);
+ err = errno;
+ if (fd != -1) {
+ errno = 0;
+ len = sss_atomic_read_s(fd, pid_str, pidlen);
+ ret = errno;
+ close(fd);
+ if (len == -1) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "read failed [%d][%s].\n", ret, strerror(ret));
+ return EINVAL;
+ }
+
+ /* Ensure NULL-termination */
+ pid_str[len] = '\0';
+
+ /* let's check the pid */
+ pid = (pid_t)atoi(pid_str);
+ if (pid != 0) {
+ errno = 0;
+ ret = kill(pid, 0);
+ /* succeeded in signaling the process -> another sssd process */
+ if (ret == 0) {
+ return EEXIST;
+ }
+ if (ret != 0 && errno != ESRCH) {
+ err = errno;
+ return err;
+ }
+ }
+
+ /* nothing in the file or no process */
+ ret = unlink(file);
+ /* non-fatal failure */
+ if (ret != EOK) {
+ ret = errno;
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to remove file: %s - %d [%s]!\n",
+ file, ret, sss_strerror(ret));
+ }
+ } else {
+ if (err != ENOENT) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int pidfile(const char *file)
+{
+ char pid_str[32];
+ int fd;
+ int ret, err;
+ size_t size;
+ ssize_t written;
+
+ ret = check_pidfile(file);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ fd = open(file, O_CREAT | O_WRONLY | O_EXCL, 0644);
+ err = errno;
+ if (fd == -1) {
+ return err;
+ }
+
+ memset(pid_str, 0, sizeof(pid_str));
+ snprintf(pid_str, sizeof(pid_str) -1, "%u\n", (unsigned int) getpid());
+ size = strlen(pid_str);
+
+ errno = 0;
+ written = sss_atomic_write_s(fd, pid_str, size);
+ err = errno;
+ close(fd);
+ if (written == -1) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "write failed [%d][%s]\n", err, strerror(err));
+ return err;
+ }
+
+ if (written != size) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Wrote %zd bytes expected %zu\n", written, size);
+ return EIO;
+ }
+
+ return 0;
+}
+
+void orderly_shutdown(int status)
+{
+#if HAVE_GETPGRP
+ static int sent_sigterm;
+ int debug;
+
+ if (sent_sigterm == 0 && getpgrp() == getpid()) {
+ debug = is_socket_activated() ? SSSDBG_TRACE_INTERNAL
+ : SSSDBG_IMPORTANT_INFO;
+ DEBUG(debug, "SIGTERM: killing children\n");
+ sent_sigterm = 1;
+ kill(-getpgrp(), SIGTERM);
+ }
+#endif
+ DEBUG(SSSDBG_IMPORTANT_INFO, "Shutting down (status = %d)\n", status);
+ sss_log(SSS_LOG_INFO, "Shutting down (status = %d)", status);
+ exit(status);
+}
+
+static void default_quit(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ struct main_context *ctx = talloc_get_type(private_data, struct main_context);
+ talloc_free(ctx);
+
+ orderly_shutdown(0);
+}
+
+#ifndef HAVE_PRCTL
+static void sig_segv_abrt(int sig)
+{
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Received signal %s, shutting down\n", strsignal(sig));
+ orderly_shutdown(1);
+}
+#endif /* HAVE_PRCTL */
+
+/*
+ setup signal masks
+*/
+static void setup_signals(void)
+{
+ /* we are never interested in SIGPIPE */
+ BlockSignals(true, SIGPIPE);
+
+#if defined(SIGFPE)
+ /* we are never interested in SIGFPE */
+ BlockSignals(true, SIGFPE);
+#endif
+
+ /* We are no longer interested in USR1 */
+ BlockSignals(true, SIGUSR1);
+
+ /* We are no longer interested in SIGINT except for monitor */
+ BlockSignals(true, SIGINT);
+
+#if defined(SIGUSR2)
+ /* We are no longer interested in USR2 */
+ BlockSignals(true, SIGUSR2);
+#endif
+
+ /* POSIX demands that signals are inherited. If the invoking process has
+ * these signals masked, we will have problems, as we won't receive them. */
+ BlockSignals(false, SIGHUP);
+ BlockSignals(false, SIGTERM);
+
+#ifndef HAVE_PRCTL
+ /* If prctl is not defined on the system, try to handle
+ * some common termination signals gracefully */
+ CatchSignal(SIGSEGV, sig_segv_abrt);
+ CatchSignal(SIGABRT, sig_segv_abrt);
+#endif
+
+}
+
+/*
+ handle io on stdin
+*/
+static void server_stdin_handler(struct tevent_context *event_ctx,
+ struct tevent_fd *fde,
+ uint16_t flags, void *private)
+{
+ const char *binary_name = (const char *)private;
+ uint8_t c;
+
+ errno = 0;
+ if (sss_atomic_read_s(0, &c, 1) == 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "%s: EOF on stdin - terminating\n",
+ binary_name);
+#if HAVE_GETPGRP
+ if (getpgrp() == getpid()) {
+ kill(-getpgrp(), SIGTERM);
+ }
+#endif
+ exit(0);
+ }
+}
+
+/*
+ main server helpers.
+*/
+
+int die_if_parent_died(void)
+{
+#ifdef HAVE_PRCTL
+ int ret;
+
+ errno = 0;
+ ret = prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
+ if (ret != 0) {
+ ret = errno;
+ DEBUG(SSSDBG_OP_FAILURE, "prctl failed [%d]: %s\n",
+ ret, strerror(ret));
+ return ret;
+ }
+#endif
+ return EOK;
+}
+
+struct logrotate_ctx {
+ struct confdb_ctx *confdb;
+ const char *confdb_path;
+};
+
+static void te_server_hup(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ errno_t ret;
+ struct logrotate_ctx *lctx =
+ talloc_get_type(private_data, struct logrotate_ctx);
+
+ DEBUG(SSSDBG_IMPORTANT_INFO, "Received SIGHUP. Rotating logfiles.\n");
+
+ ret = server_common_rotate_logs(lctx->confdb, lctx->confdb_path);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not reopen log file [%s]\n",
+ strerror(ret));
+ }
+}
+
+errno_t server_common_rotate_logs(struct confdb_ctx *confdb,
+ const char *conf_path)
+{
+ errno_t ret;
+ int old_debug_level = debug_level;
+
+ ret = rotate_debug_files();
+ if (ret) {
+ sss_log(SSS_LOG_ALERT, "Could not rotate debug files! [%d][%s]\n",
+ ret, strerror(ret));
+ return ret;
+ }
+
+ /* Get new debug level from the confdb */
+ ret = confdb_get_int(confdb, conf_path,
+ CONFDB_SERVICE_DEBUG_LEVEL,
+ old_debug_level,
+ &debug_level);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) [%s]\n",
+ ret, strerror(ret));
+ /* Try to proceed with the old value */
+ debug_level = old_debug_level;
+ }
+
+ if (debug_level != old_debug_level) {
+ DEBUG(SSSDBG_IMPORTANT_INFO,
+ "Debug level changed to %#.4x\n", debug_level);
+ debug_level = debug_convert_old_level(debug_level);
+ }
+
+ return EOK;
+}
+
+errno_t generic_get_debug_level(TALLOC_CTX *mem_ctx,
+ struct sbus_request *sbus_req,
+ void *pvt_data,
+ uint32_t *_debug_level)
+{
+ *_debug_level = debug_level;
+ return EOK;
+}
+
+errno_t generic_set_debug_level(TALLOC_CTX *mem_ctx,
+ struct sbus_request *sbus_req,
+ void *pvt_data,
+ uint32_t new_debug_level)
+{
+ debug_level = new_debug_level;
+ return EOK;
+}
+
+static const char *get_db_path(void)
+{
+#ifdef UNIT_TESTING
+#ifdef TEST_DB_PATH
+ return TEST_DB_PATH;
+#else
+ #error "TEST_DB_PATH must be defined when unit testing server.c!"
+#endif /* TEST_DB_PATH */
+#else
+ return DB_PATH;
+#endif /* UNIT_TESTING */
+}
+
+static const char *get_pid_path(void)
+{
+#ifdef UNIT_TESTING
+#ifdef TEST_PID_PATH
+ return TEST_PID_PATH;
+#else
+ #error "TEST_PID_PATH must be defined when unit testing server.c!"
+#endif /* TEST_PID_PATH */
+#else
+ return PID_PATH;
+#endif
+}
+
+int server_setup(const char *name, bool is_responder,
+ int flags,
+ uid_t uid, gid_t gid,
+ const char *conf_entry,
+ struct main_context **main_ctx,
+ bool allow_sss_loop)
+{
+ struct tevent_context *event_ctx;
+ struct main_context *ctx;
+ uint16_t stdin_event_flags;
+ char *conf_db;
+ int ret = EOK;
+ bool dt;
+ bool dm;
+ bool backtrace_enabled;
+ struct tevent_signal *tes;
+ struct logrotate_ctx *lctx;
+ char *locale;
+ int watchdog_interval;
+ pid_t my_pid;
+ char *pidfile_name;
+ int cfg_debug_level = SSSDBG_INVALID;
+ bool dumpable = true;
+
+ if (is_responder) {
+ sss_chain_id_set_format(DEBUG_CHAIN_ID_FMT_CID);
+ } else {
+ sss_chain_id_set_format(DEBUG_CHAIN_ID_FMT_RID);
+ }
+
+ talloc_enable_null_tracking();
+
+ autofree_ctx = talloc_named_const(NULL, 0, "autofree_context");
+ if (autofree_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ atexit(server_atexit);
+
+ debug_prg_name = talloc_strdup(autofree_ctx, name);
+ if (!debug_prg_name) {
+ return ENOMEM;
+ }
+
+ my_pid = getpid();
+ ret = setpgid(my_pid, my_pid);
+ if (ret != EOK) {
+ ret = errno;
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed setting process group: %s[%d]. "
+ "We might leak processes in case of failure\n",
+ sss_strerror(ret), ret);
+ }
+
+ if (!is_socket_activated()) {
+ ret = chown_debug_file(NULL, uid, gid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot chown the debug files, debugging might not work!\n");
+ }
+
+ ret = become_user(uid, gid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FUNC_DATA,
+ "Cannot become user [%"SPRIuid"][%"SPRIgid"].\n", uid, gid);
+ return ret;
+ }
+ }
+
+ if (!allow_sss_loop) {
+ ret = setenv("_SSS_LOOPS", "NO", 0);
+ if (ret != 0) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to set _SSS_LOOPS.\n");
+ return ret;
+ }
+ }
+ /* To make sure the domain cannot be set from the environment, unset the
+ * variable explicitly when setting up any server. Backends later set the
+ * value after reading domain from the configuration */
+ ret = unsetenv(SSS_DOM_ENV);
+ if (ret != 0) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Unsetting "SSS_DOM_ENV" failed, journald "
+ "logging might not work as expected\n");
+ }
+
+ setup_signals();
+
+ /* we want default permissions on created files to be very strict */
+ umask(SSS_DFL_UMASK);
+
+ if (flags & FLAGS_DAEMON) {
+ DEBUG(SSSDBG_IMPORTANT_INFO, "Becoming a daemon.\n");
+ become_daemon();
+ }
+
+ if (flags & FLAGS_PID_FILE) {
+ pidfile_name = talloc_asprintf(NULL, "%s/%s.pid", get_pid_path(), name);
+ if (!pidfile_name) {
+ return ENOMEM;
+ }
+ ret = pidfile(pidfile_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Error creating pidfile: %s! "
+ "(%d [%s])\n", pidfile_name, ret, strerror(ret));
+ talloc_free(pidfile_name);
+ return ret;
+ }
+ talloc_free(pidfile_name);
+ }
+
+ /* Set up locale */
+ locale = setlocale(LC_ALL, "");
+ if (locale == NULL) {
+ /* Just print debug message and continue */
+ DEBUG(SSSDBG_TRACE_FUNC, "Unable to set locale\n");
+ }
+
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ /* the event context is the top level structure.
+ * Everything else should hang off that */
+ event_ctx = tevent_context_init(autofree_ctx);
+ if (event_ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "The event context initialization failed\n");
+ return 1;
+ }
+
+ ctx = talloc(event_ctx, struct main_context);
+ if (ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory, aborting!\n");
+ return ENOMEM;
+ }
+
+ ctx->parent_pid = getppid();
+ ctx->event_ctx = event_ctx;
+
+ /* Set up an event handler for a SIGINT */
+ tes = tevent_add_signal(event_ctx, event_ctx, SIGINT, 0,
+ default_quit, ctx);
+ if (tes == NULL) {
+ return EIO;
+ }
+
+ /* Set up an event handler for a SIGTERM */
+ tes = tevent_add_signal(event_ctx, event_ctx, SIGTERM, 0,
+ default_quit, ctx);
+ if (tes == NULL) {
+ return EIO;
+ }
+
+ conf_db = talloc_asprintf(ctx, "%s/%s",
+ get_db_path(), CONFDB_FILE);
+ if (conf_db == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory, aborting!\n");
+ return ENOMEM;
+ }
+
+ ret = confdb_init(ctx, &ctx->confdb_ctx, conf_db);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "The confdb initialization failed\n");
+ return ret;
+ }
+
+ if (debug_level == SSSDBG_UNRESOLVED) {
+ /* set debug level if any in conf_entry */
+ ret = confdb_get_int(ctx->confdb_ctx, conf_entry,
+ CONFDB_SERVICE_DEBUG_LEVEL,
+ SSSDBG_INVALID,
+ &cfg_debug_level);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) "
+ "[%s]\n", ret, strerror(ret));
+ return ret;
+ }
+
+ if (cfg_debug_level == SSSDBG_INVALID) {
+ /* Check for the `debug` alias */
+ ret = confdb_get_int(ctx->confdb_ctx, conf_entry,
+ CONFDB_SERVICE_DEBUG_LEVEL_ALIAS,
+ SSSDBG_DEFAULT,
+ &cfg_debug_level);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) "
+ "[%s]\n", ret, strerror(ret));
+ return ret;
+ }
+ }
+
+ debug_level = debug_convert_old_level(cfg_debug_level);
+ }
+
+ /* same for debug timestamps */
+ if (debug_timestamps == SSSDBG_TIMESTAMP_UNRESOLVED) {
+ ret = confdb_get_bool(ctx->confdb_ctx, conf_entry,
+ CONFDB_SERVICE_DEBUG_TIMESTAMPS,
+ SSSDBG_TIMESTAMP_DEFAULT,
+ &dt);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) "
+ "[%s]\n", ret, strerror(ret));
+ return ret;
+ }
+ if (dt) debug_timestamps = SSSDBG_TIMESTAMP_ENABLED;
+ else debug_timestamps = SSSDBG_TIMESTAMP_DISABLED;
+ }
+
+ /* same for debug microseconds */
+ if (debug_microseconds == SSSDBG_MICROSECONDS_UNRESOLVED) {
+ ret = confdb_get_bool(ctx->confdb_ctx, conf_entry,
+ CONFDB_SERVICE_DEBUG_MICROSECONDS,
+ SSSDBG_MICROSECONDS_DEFAULT,
+ &dm);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) "
+ "[%s]\n", ret, strerror(ret));
+ return ret;
+ }
+ if (dm) debug_microseconds = SSSDBG_MICROSECONDS_ENABLED;
+ else debug_microseconds = SSSDBG_MICROSECONDS_DISABLED;
+ }
+
+ ret = confdb_get_bool(ctx->confdb_ctx, conf_entry,
+ CONFDB_SERVICE_DEBUG_BACKTRACE_ENABLED,
+ true,
+ &backtrace_enabled);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Error reading %s from confdb (%d) [%s]\n",
+ CONFDB_SERVICE_DEBUG_BACKTRACE_ENABLED, ret, strerror(ret));
+ return ret;
+ }
+ sss_debug_backtrace_enable(backtrace_enabled);
+
+ /* before opening the log file set up log rotation */
+ lctx = talloc_zero(ctx, struct logrotate_ctx);
+ if (!lctx) return ENOMEM;
+
+ lctx->confdb = ctx->confdb_ctx;
+ lctx->confdb_path = conf_entry;
+
+ tes = tevent_add_signal(ctx->event_ctx, ctx, SIGHUP, 0,
+ te_server_hup, lctx);
+ if (tes == NULL) {
+ return EIO;
+ }
+
+ DEBUG(SSSDBG_IMPORTANT_INFO,
+ "Starting with debug level = %#.4x\n", debug_level);
+
+ /* Setup the internal watchdog */
+ ret = confdb_get_int(ctx->confdb_ctx, conf_entry,
+ CONFDB_DOMAIN_TIMEOUT,
+ 0, &watchdog_interval);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) [%s]\n",
+ ret, strerror(ret));
+ return ret;
+ }
+
+ if ((flags & FLAGS_NO_WATCHDOG) == 0) {
+ ret = setup_watchdog(ctx->event_ctx, watchdog_interval);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Watchdog setup failed.\n");
+ return ret;
+ }
+ }
+
+ ret = confdb_get_bool(ctx->confdb_ctx,
+ CONFDB_MONITOR_CONF_ENTRY,
+ CONFDB_MONITOR_DUMPABLE,
+ true, /* default value */
+ &dumpable);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to determine "CONFDB_MONITOR_DUMPABLE"\n");
+ return ret;
+ }
+ ret = prctl(PR_SET_DUMPABLE, dumpable ? 1 : 0);
+ if (ret != 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set PR_SET_DUMPABLE\n");
+ return ret;
+ } else if (!dumpable) {
+ DEBUG(SSSDBG_IMPORTANT_INFO, "Core dumps are disabled!\n");
+ }
+
+ sss_chain_id_setup(ctx->event_ctx);
+
+ sss_log(SSS_LOG_INFO, "Starting up");
+
+ DEBUG(SSSDBG_TRACE_FUNC, "CONFDB: %s\n", conf_db);
+
+ if (flags & FLAGS_INTERACTIVE) {
+ /* terminate when stdin goes away */
+ stdin_event_flags = TEVENT_FD_READ;
+ } else {
+ /* stay alive forever */
+ stdin_event_flags = 0;
+ }
+
+ /* catch EOF on stdin */
+#ifdef SIGTTIN
+ signal(SIGTTIN, SIG_IGN);
+#endif
+ tevent_add_fd(event_ctx, event_ctx, STDIN_FILENO, stdin_event_flags,
+ server_stdin_handler, discard_const(name));
+
+ *main_ctx = ctx;
+ return EOK;
+}
+
+void server_loop(struct main_context *main_ctx)
+{
+ /* wait for events - this is where the server sits for most of its
+ life */
+ tevent_loop_wait(main_ctx->event_ctx);
+
+ /* as everything hangs off this event context, freeing it
+ should initiate a clean shutdown of all services */
+ talloc_free(main_ctx->event_ctx);
+}