monitor.c revision d19c4785215305e6eb5f2fa2fc503a2ba50d3f10
f072359f493a5209335799da85ac16d6a273303bgryzor Service monitor
f072359f493a5209335799da85ac16d6a273303bgryzor Copyright (C) Simo Sorce 2008
f072359f493a5209335799da85ac16d6a273303bgryzor This program is free software; you can redistribute it and/or modify
f072359f493a5209335799da85ac16d6a273303bgryzor it under the terms of the GNU General Public License as published by
f072359f493a5209335799da85ac16d6a273303bgryzor the Free Software Foundation; either version 3 of the License, or
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen (at your option) any later version.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen This program is distributed in the hope that it will be useful,
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen but WITHOUT ANY WARRANTY; without even the implied warranty of
f072359f493a5209335799da85ac16d6a273303bgryzor MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f072359f493a5209335799da85ac16d6a273303bgryzor GNU General Public License for more details.
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen You should have received a copy of the GNU General Public License
3f08db06526d6901aa08c110b5bc7dde6bc39905nd along with this program. If not, see <http://www.gnu.org/licenses/>.
f072359f493a5209335799da85ac16d6a273303bgryzor/* Needed for res_init() */
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic/* ping time cannot be less then once every few seconds or the
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic * monitor will get crazy hammering children with messages */
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic/* terminate the child after this interval by default if it
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic * doesn't shutdown on receiving SIGTERM */
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic/* name of the monitor server instance */
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic#define SSSD_PIDFILE_PATH PID_PATH"/"MONITOR_NAME".pid"
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic/* Special value to leave the Kerberos Replay Cache set to use
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic * the libkrb5 defaults
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic#define KRB5_RCACHE_DIR_DISABLE "__LIBKRB5_DEFAULTS__"
f072359f493a5209335799da85ac16d6a273303bgryzor TALLOC_CTX *domain_ctx; /* Memory context for domain list */
f072359f493a5209335799da85ac16d6a273303bgryzor TALLOC_CTX *service_ctx; /* Memory context for services */
48c64aeceef385e19025b384bd719b2a9789592dnd const char *conf_path;
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int monitor_service_init(struct sbus_connection *conn, void *data);
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int service_signal_reset_offline(struct mt_svc *svc);
f072359f493a5209335799da85ac16d6a273303bgryzorstatic void ping_check(DBusPendingCall *pending, void *data);
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int get_service_config(struct mt_ctx *ctx, const char *name,
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int get_provider_config(struct mt_ctx *ctx, const char *name,
f072359f493a5209335799da85ac16d6a273303bgryzor const char *name,
f072359f493a5209335799da85ac16d6a273303bgryzor const char *name,
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int mark_service_as_started(struct mt_svc *svc);
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int monitor_cleanup(void);
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(SSSDBG_TRACE_INTERNAL, ("A networking status change detected "
f072359f493a5209335799da85ac16d6a273303bgryzor "signaling providers to reset offline status\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor for (iter = ctx->svc_list; iter; iter = iter->next) {
f072359f493a5209335799da85ac16d6a273303bgryzor /* Don't signal services, only providers */
f072359f493a5209335799da85ac16d6a273303bgryzor/* dbus_get_monitor_version
f072359f493a5209335799da85ac16d6a273303bgryzor * Return the monitor version over D-BUS */
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim /* send reply back */
ac2a72149b423e2e84596098d7e47af88ebd215asf/* registers a new client.
ac2a72149b423e2e84596098d7e47af88ebd215asf * if operation is successful also sends back the Monitor version */
ac2a72149b423e2e84596098d7e47af88ebd215asf /* First thing, cancel the timeout */
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim DEBUG(1, ("Failed to parse message, killing connection\n"));
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
ac2a72149b423e2e84596098d7e47af88ebd215asf /* FIXME: should we just talloc_zfree(conn) ? */
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim DEBUG(4, ("Received ID registration: (%s,%d)\n", svc_name, svc_ver));
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim /* search this service in the list */
ac2a72149b423e2e84596098d7e47af88ebd215asf if (ret == 0) {
ac2a72149b423e2e84596098d7e47af88ebd215asf DEBUG(0, ("Unable to find peer [%s] in list of services,"
ac2a72149b423e2e84596098d7e47af88ebd215asf /* FIXME: should we just talloc_zfree(conn) ? */
ac2a72149b423e2e84596098d7e47af88ebd215asf /* Fill in svc structure with connection data */
ac2a72149b423e2e84596098d7e47af88ebd215asf /* reply that all is ok */
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim /* send reply back */
ac2a72149b423e2e84596098d7e47af88ebd215asf /* init complete, get rid of temp init context */
ac2a72149b423e2e84596098d7e47af88ebd215asf struct mt_svc *svc = talloc_get_type(mem, struct mt_svc);
ac2a72149b423e2e84596098d7e47af88ebd215asf /* ?!?!? */
ac2a72149b423e2e84596098d7e47af88ebd215asf /* try to delist service */
ac2a72149b423e2e84596098d7e47af88ebd215asf /* Cancel any pending pings */
ac2a72149b423e2e84596098d7e47af88ebd215asf /* svc is beeing freed, neutralize the spy */
ac2a72149b423e2e84596098d7e47af88ebd215asf talloc_set_destructor((TALLOC_CTX *)svc->conn_spy, NULL);
ac2a72149b423e2e84596098d7e47af88ebd215asf && svc->mt_ctx != NULL && svc->mt_ctx->started_services > 0) {
f072359f493a5209335799da85ac16d6a273303bgryzor struct svc_spy *spy = talloc_get_type(mem, struct svc_spy);
f072359f493a5209335799da85ac16d6a273303bgryzor /* ?!?!? */
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim /* svc->conn has been freed, NULL the pointer in svc */
f072359f493a5209335799da85ac16d6a273303bgryzor talloc_set_destructor((TALLOC_CTX *)spy, svc_spy_destructor);
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int mark_service_as_started(struct mt_svc *svc)
f072359f493a5209335799da85ac16d6a273303bgryzor /* we need to attach a spy to the connection structure so that if some code
f072359f493a5209335799da85ac16d6a273303bgryzor * frees it we can zero it out in the service structure. Otherwise we may
f072359f493a5209335799da85ac16d6a273303bgryzor * try to access or even free, freed memory. */
f072359f493a5209335799da85ac16d6a273303bgryzor /* check if all providers are up */
f072359f493a5209335799da85ac16d6a273303bgryzor for (iter = ctx->svc_list; iter; iter = iter->next) {
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(5, ("Still waiting on %s provider.\n", iter->name));
eef716e54c415709ca9d53aad4678bf9d96186e6nd /* there are still unstarted providers */
f072359f493a5209335799da85ac16d6a273303bgryzor /* then start all services */
f072359f493a5209335799da85ac16d6a273303bgryzor /* Initialization is complete, terminate parent process if in daemon
f072359f493a5209335799da85ac16d6a273303bgryzor * mode. Make sure we send the signal to the right process */
f072359f493a5209335799da85ac16d6a273303bgryzor if (ctx->parent_pid <= 1 || ctx->parent_pid != getppid()) {
f072359f493a5209335799da85ac16d6a273303bgryzor /* the parent process was already terminated */
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(SSSDBG_MINOR_FAILURE, ("Invalid parent pid: %d\n",
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim "terminating parent process\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor if (ret != 0) {
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(SSSDBG_FATAL_FAILURE, ("Unable to terminate parent "
f072359f493a5209335799da85ac16d6a273303bgryzorstatic void services_startup_timeout(struct tevent_context *ev,
f072359f493a5209335799da85ac16d6a273303bgryzor struct mt_ctx *ctx = talloc_get_type(ptr, struct mt_ctx);
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic "forcing services startup!\n"));
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic /* then start all services */
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int add_services_startup_timeout(struct mt_ctx *ctx)
f072359f493a5209335799da85ac16d6a273303bgryzor /* 5 seconds should be plenty */
f072359f493a5209335799da85ac16d6a273303bgryzor to = tevent_add_timer(ctx->ev, ctx, tv, services_startup_timeout, ctx);
f072359f493a5209335799da85ac16d6a273303bgryzor/* monitor_dbus_init
f072359f493a5209335799da85ac16d6a273303bgryzor * Set up the monitor service as a D-BUS Server */
45a544a8bb3fa1f95e5edac9fb3e723e2bb7001drbowen ret = monitor_get_sbus_address(ctx, &monitor_address);
45a544a8bb3fa1f95e5edac9fb3e723e2bb7001drbowenstatic void tasks_check_handler(struct tevent_context *ev,
15e38d431fea66258ef33960b39edee496c3c9c2humbedooh struct mt_svc *svc = talloc_get_type(ptr, struct mt_svc);
15e38d431fea66258ef33960b39edee496c3c9c2humbedooh /* all fine */
15e38d431fea66258ef33960b39edee496c3c9c2humbedooh DEBUG(1,("Child (%s) not responding! (yet)\n", svc->name));
15e38d431fea66258ef33960b39edee496c3c9c2humbedooh /* TODO: should we tear it down ? */
15e38d431fea66258ef33960b39edee496c3c9c2humbedooh DEBUG(1,("Sending a message to service (%s) failed!!\n", svc->name));
f072359f493a5209335799da85ac16d6a273303bgryzor /* too long since we last heard of this process */
f072359f493a5209335799da85ac16d6a273303bgryzor ("Killing service [%s], not responding to pings!\n",
f072359f493a5209335799da85ac16d6a273303bgryzor /* Kill the service. The SIGCHLD handler will restart it */
f072359f493a5209335799da85ac16d6a273303bgryzor /* all fine, set up the task checker again */
f072359f493a5209335799da85ac16d6a273303bgryzor te = tevent_add_timer(svc->mt_ctx->ev, svc, tv, tasks_check_handler, svc);
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0, ("failed to add event, monitor offline for [%s]!\n",
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim /* FIXME: shutdown ? */
15e38d431fea66258ef33960b39edee496c3c9c2humbedooh ("Sending signal to child (%s:%d) failed! "
15e38d431fea66258ef33960b39edee496c3c9c2humbedooh "Ignore and pretend child is dead.\n",
f072359f493a5209335799da85ac16d6a273303bgryzor /* Set up a timer to send SIGKILL if this process
f072359f493a5209335799da85ac16d6a273303bgryzor * doesn't exit within sixty seconds
f072359f493a5209335799da85ac16d6a273303bgryzor svc->sigkill_ev = tevent_add_timer(svc->mt_ctx->ev, svc, tv,
f072359f493a5209335799da85ac16d6a273303bgryzor struct mt_svc *svc = talloc_get_type(ptr, struct mt_svc);
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim ("[%s][%d] is not responding to SIGTERM. Sending SIGKILL.\n",
f072359f493a5209335799da85ac16d6a273303bgryzor ("Sending signal to child (%s:%d) failed! "
f072359f493a5209335799da85ac16d6a273303bgryzor "Ignore and pretend child is dead.\n",
f072359f493a5209335799da85ac16d6a273303bgryzorstatic void reload_reply(DBusPendingCall *pending, void *data)
f072359f493a5209335799da85ac16d6a273303bgryzor struct mt_svc *svc = talloc_get_type(data, struct mt_svc);
f072359f493a5209335799da85ac16d6a273303bgryzor /* reply should never be null. This function shouldn't be called
f072359f493a5209335799da85ac16d6a273303bgryzor * until reply is valid or timeout has occurred. If reply is NULL
f072359f493a5209335799da85ac16d6a273303bgryzor * here, something is seriously wrong and we should bail out.
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0, ("A reply callback was called but no reply was received"
f072359f493a5209335799da85ac16d6a273303bgryzor " and no timeout occurred\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor /* Destroy this connection */
e797af4d7b0cada1278d72d6c8ac77210ef78632minfrin /* TODO: Handle cases where the call has timed out or returned
eef716e54c415709ca9d53aad4678bf9d96186e6nd * with an error.
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int service_signal_dns_reload(struct mt_svc *svc);
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int monitor_update_resolv(struct config_file_ctx *file_ctx,
f072359f493a5209335799da85ac16d6a273303bgryzor const char *filename)
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(2, ("Resolv.conf has been updated. Reloading.\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor /* Signal all services to reload their DNS configuration */
f072359f493a5209335799da85ac16d6a273303bgryzor for(cur_svc = file_ctx->mt_ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int service_signal(struct mt_svc *svc, const char *svc_signal)
b71e5eae594d54e9e56dc20208c6a7fb52610e29rbowen if (svc->provider && strcasecmp(svc->provider, "local") == 0) {
f072359f493a5209335799da85ac16d6a273303bgryzor /* The local provider requires no signaling */
f072359f493a5209335799da85ac16d6a273303bgryzor /* Avoid a race condition where we are trying to
f072359f493a5209335799da85ac16d6a273303bgryzor * order a service to reload that hasn't started
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(1,("Could not signal service [%s].\n", svc->name));
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int service_signal_dns_reload(struct mt_svc *svc)
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int service_signal_reset_offline(struct mt_svc *svc)
f072359f493a5209335799da85ac16d6a273303bgryzor return service_signal(svc, MON_CLI_METHOD_RESET_OFFLINE);
eef716e54c415709ca9d53aad4678bf9d96186e6ndstatic int service_signal_clear_memcache(struct mt_svc *svc)
f072359f493a5209335799da85ac16d6a273303bgryzor return service_signal(svc, MON_CLI_METHOD_CLEAR_MEMCACHE);
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int check_domain_ranges(struct sss_domain_info *domains)
f072359f493a5209335799da85ac16d6a273303bgryzor struct sss_domain_info *dom = domains, *other = NULL;
f072359f493a5209335799da85ac16d6a273303bgryzor ("Domain '%s' does not have a valid ID range\n", dom->name));
f072359f493a5209335799da85ac16d6a273303bgryzor id_max = MIN((dom->id_max ? dom->id_max : UINT32_MAX),
f072359f493a5209335799da85ac16d6a273303bgryzor ("Domains '%s' and '%s' overlap in range %u - %u\n",
eef716e54c415709ca9d53aad4678bf9d96186e6ndstatic int check_local_domain_unique(struct sss_domain_info *domains)
7f0952c0239ea2d6e37b472db6fde4ef2718343dsf const char *known_services[] = { "nss", "pam", "sudo", "autofs", "ssh",
7f0952c0239ea2d6e37b472db6fde4ef2718343dsf /* Check if services we are about to start are in the list if known */
7f0952c0239ea2d6e37b472db6fde4ef2718343dsf for (i = 0; services[i]; i++) {
f072359f493a5209335799da85ac16d6a273303bgryzor ctx->service_id_timeout = timeout_seconds * 1000; /* service_id_timeout is in ms */
f072359f493a5209335799da85ac16d6a273303bgryzor ret = confdb_get_string_as_list(ctx->cdb, ctx->service_ctx,
737a1f4117ce00c29a1b78b93db08e4a273ab2edtrawick DEBUG(0, ("More than one local domain configured.\n"));
737a1f4117ce00c29a1b78b93db08e4a273ab2edtrawick /* Check UID/GID overlaps */
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjimstatic errno_t get_ping_config(struct mt_ctx *ctx, const char *path,
f072359f493a5209335799da85ac16d6a273303bgryzor ("Failed to get ping timeout for '%s'\n", svc->name));
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim /* 'timeout = 0' should be translated to the default */
f072359f493a5209335799da85ac16d6a273303bgryzor /* 'force_timeout = 0' should be translated to the default */
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int get_service_config(struct mt_ctx *ctx, const char *name,
92fd3fe66fb218b9fdf129e7555bd851e5cbf487rbowen talloc_set_destructor((TALLOC_CTX *)svc, svc_destructor);
f072359f493a5209335799da85ac16d6a273303bgryzor path = talloc_asprintf(svc, CONFDB_SERVICE_PATH_TMPL, svc->name);
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0,("Failed to start service '%s'\n", svc->name));
f072359f493a5209335799da85ac16d6a273303bgryzor if (cmdline_debug_timestamps != SSSDBG_TIMESTAMP_UNRESOLVED) {
f072359f493a5209335799da85ac16d6a273303bgryzor svc->command, " --debug-timestamps=%d", cmdline_debug_timestamps
f072359f493a5209335799da85ac16d6a273303bgryzor if (cmdline_debug_microseconds != SSSDBG_MICROSECONDS_UNRESOLVED) {
f072359f493a5209335799da85ac16d6a273303bgryzor ("Failed to get ping timeouts for %s\n", svc->name));
f072359f493a5209335799da85ac16d6a273303bgryzor const char *name,
44a442483c2ae67ab94061b87ca3312bc83b059crbowen DEBUG(0,("Failed to start service '%s'\n", svc->name));
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int get_provider_config(struct mt_ctx *ctx, const char *name,
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim talloc_set_destructor((TALLOC_CTX *)svc, svc_destructor);
44a442483c2ae67ab94061b87ca3312bc83b059crbowen svc->identity = talloc_asprintf(svc, "%%BE_%s", svc->name);
92fd3fe66fb218b9fdf129e7555bd851e5cbf487rbowen path = talloc_asprintf(svc, CONFDB_DOMAIN_PATH_TMPL, name);
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0, ("Failed to find ID provider from [%s] configuration\n", name));
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim DEBUG(0, ("Failed to find command from [%s] configuration\n", name));
f072359f493a5209335799da85ac16d6a273303bgryzor /* if no provider is present do not run the domain */
ac2a72149b423e2e84596098d7e47af88ebd215asf /* if there are no custom commands, build a default one */
ac2a72149b423e2e84596098d7e47af88ebd215asf svc, "%s/sssd_be --domain %s", SSSD_LIBEXEC_PATH, svc->name
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe if (cmdline_debug_timestamps != SSSDBG_TIMESTAMP_UNRESOLVED) {
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe svc->command, " --debug-timestamps=%d", cmdline_debug_timestamps
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe if (cmdline_debug_microseconds != SSSDBG_MICROSECONDS_UNRESOLVED) {
f072359f493a5209335799da85ac16d6a273303bgryzor const char *name,
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0, ("Could not get provider configuration for [%s]\n",
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe /* The LOCAL provider requires no back-end currently
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe * We'll add it to the service list, but we don't need
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe * to poll it.
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0,("Failed to start service '%s'\n", svc->name));
48c64aeceef385e19025b384bd719b2a9789592dnd struct mt_ctx *ctx = talloc_get_type(private_data, struct mt_ctx);
f072359f493a5209335799da85ac16d6a273303bgryzor /* Send D-Bus message to other services to rotate their logs.
f072359f493a5209335799da85ac16d6a273303bgryzor * NSS service receives also message to clear memory caches. */
f072359f493a5209335799da85ac16d6a273303bgryzor for(cur_svc = ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int monitor_cleanup(void)
f072359f493a5209335799da85ac16d6a273303bgryzor ("Error removing pidfile! (%d [%s])\n", ret, strerror(ret)));
f072359f493a5209335799da85ac16d6a273303bgryzorstatic void monitor_quit(struct mt_ctx *mt_ctx, int ret)
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic DEBUG(SSSDBG_IMPORTANT_INFO, ("Returned with: %d\n", ret));
70f5253b24dd333c67fb6502d557a8b48ad3ba87igalic /* Kill all of our known children manually */
f072359f493a5209335799da85ac16d6a273303bgryzor /* The local provider has no PID */
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(1, ("Terminating [%s][%d]\n", svc->name, svc->pid));
ac2a72149b423e2e84596098d7e47af88ebd215asf /* An error occurred while waiting */
f072359f493a5209335799da85ac16d6a273303bgryzor /* Forcibly kill this child */
f072359f493a5209335799da85ac16d6a273303bgryzor } else if (pid != 0) {
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(1, ("Child [%s] exited gracefully\n", svc->name));
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(1, ("Child [%s] terminated with a signal\n", svc->name));
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0, ("Child [%s] did not exit cleanly\n", svc->name));
f072359f493a5209335799da85ac16d6a273303bgryzor /* Forcibly kill this child */
f072359f493a5209335799da85ac16d6a273303bgryzor /* Sleep 10ms and try again */
f072359f493a5209335799da85ac16d6a273303bgryzor } while (!killed);
f072359f493a5209335799da85ac16d6a273303bgryzor /* Kill any remaining children in our process group, just in case
48c64aeceef385e19025b384bd719b2a9789592dnd * we have any leftover children we don't expect. For example, if
f072359f493a5209335799da85ac16d6a273303bgryzor * a krb5_child or ldap_child is running at the same moment.
f4fa200e8481572da4d572759152b7c7c68facb4rbowenstatic void monitor_quit_signal(struct tevent_context *ev,
f4fa200e8481572da4d572759152b7c7c68facb4rbowen struct mt_ctx *mt_ctx = talloc_get_type(private_data, struct mt_ctx);
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(SSSDBG_TRACE_INTERNAL, ("Received shutdown command\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(SSSDBG_IMPORTANT_INFO, ("Monitor received %s: terminating "
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(SSSDBG_OP_FAILURE, ("Reloading Resolv.conf.\n"));
7f0952c0239ea2d6e37b472db6fde4ef2718343dsf if (ret == 0) {
7f0952c0239ea2d6e37b472db6fde4ef2718343dsf for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
f072359f493a5209335799da85ac16d6a273303bgryzor ("Signaling providers to go offline immediately.\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor /* Signal all providers to immediately go offline */
f072359f493a5209335799da85ac16d6a273303bgryzor for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
f072359f493a5209335799da85ac16d6a273303bgryzor /* Don't signal services, only providers */
f072359f493a5209335799da85ac16d6a273303bgryzorstatic void signal_offline_reset(struct tevent_context *ev,
f072359f493a5209335799da85ac16d6a273303bgryzor monitor = talloc_get_type(private_data, struct mt_ctx);
f072359f493a5209335799da85ac16d6a273303bgryzor ("Signaling providers to reset offline immediately.\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
f072359f493a5209335799da85ac16d6a273303bgryzor struct mt_ctx *mon = talloc_get_type(mem, struct mt_ctx);
f072359f493a5209335799da85ac16d6a273303bgryzor /* zero out references in svcs so that they don't try
f072359f493a5209335799da85ac16d6a273303bgryzor * to access the monitor context on process shutdown */
f072359f493a5209335799da85ac16d6a273303bgryzorstatic errno_t load_configuration(TALLOC_CTX *mem_ctx,
7f0952c0239ea2d6e37b472db6fde4ef2718343dsf talloc_set_destructor((TALLOC_CTX *)ctx, monitor_ctx_destructor);
7f0952c0239ea2d6e37b472db6fde4ef2718343dsf cdb_file = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
7f0952c0239ea2d6e37b472db6fde4ef2718343dsf /* Initialize the CDB from the configuration file */
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim /* First-time setup */
7159c12b7697fe9f5ab3a533cc6dfc3d57803053igalic /* Purge any existing confdb in case an old
7159c12b7697fe9f5ab3a533cc6dfc3d57803053igalic * misconfiguration gets in the way
5479b5fa65d8ec88ea9c4389fd1b2c2728585571nd /* Load special entries */
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim DEBUG(0, ("Unable to load special entries into confdb\n"));
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim /* Validate the configuration in the database */
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim /* Read in the monitor's configuration */
f072359f493a5209335799da85ac16d6a273303bgryzorstatic void process_config_file(struct tevent_context *ev,
f072359f493a5209335799da85ac16d6a273303bgryzorstatic void config_file_changed(struct tevent_context *ev,
44a442483c2ae67ab94061b87ca3312bc83b059crbowen file_ctx = talloc_get_type(data, struct config_file_ctx);
44a442483c2ae67ab94061b87ca3312bc83b059crbowen /* Skip updating. It's already queued for update.
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe /* We will queue the file for update in one second.
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe * This way, if there is a script writing to the file
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe * repeatedly, we won't be attempting to update multiple
f072359f493a5209335799da85ac16d6a273303bgryzor te = tevent_add_timer(ev, ev, tv, process_config_file, file_ctx);
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0, ("Unable to queue config file update! Exiting.\n"));
f072359f493a5209335799da85ac16d6a273303bgryzorstatic void rewatch_config_file(struct tevent_context *ev,
f072359f493a5209335799da85ac16d6a273303bgryzorstatic void process_config_file(struct tevent_context *ev,
f072359f493a5209335799da85ac16d6a273303bgryzor if (!tmp_ctx) return;
f072359f493a5209335799da85ac16d6a273303bgryzor len = sss_atomic_read_s(file_ctx->mt_ctx->inotify_fd, buf, event_size);
f072359f493a5209335799da85ac16d6a273303bgryzor ("Critical error reading inotify file descriptor [%d]: %s\n",
f072359f493a5209335799da85ac16d6a273303bgryzor /* Read in the name, even though we don't use it,
eef716e54c415709ca9d53aad4678bf9d96186e6nd * so that read ptr is in the right place
eef716e54c415709ca9d53aad4678bf9d96186e6nd len = sss_atomic_read_s(file_ctx->mt_ctx->inotify_fd, name, in_event->len);
f072359f493a5209335799da85ac16d6a273303bgryzor ("Critical error reading inotify file descriptor [%d]: %s\n",
f072359f493a5209335799da85ac16d6a273303bgryzor /* Some text editors will move a new file on top of the
f072359f493a5209335799da85ac16d6a273303bgryzor * existing one instead of modifying it. In this case,
f072359f493a5209335799da85ac16d6a273303bgryzor * the kernel will send us an IN_IGNORE signal.
f072359f493a5209335799da85ac16d6a273303bgryzor * We will try to open a new watch descriptor on the
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe * new file.
db8dceaf53a26fba6048c2ad4d86c5507344187drbowen DEBUG(0, ("Could not restore inotify watch. Quitting!\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor tev = tevent_add_timer(ev, rw_ctx, tv, rewatch_config_file, rw_ctx);
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0, ("Could not restore inotify watch. Quitting!\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor /* Tell the monitor to signal the children */
f072359f493a5209335799da85ac16d6a273303bgryzorerrno_t monitor_config_file_fallback(TALLOC_CTX *mem_ctx,
f072359f493a5209335799da85ac16d6a273303bgryzor const char *file,
737a1f4117ce00c29a1b78b93db08e4a273ab2edtrawickstatic void rewatch_config_file(struct tevent_context *ev,
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim /* Retry six times at five-second intervals before giving up */
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim ("Could not restore inotify watch. Switching to polling!\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor err = monitor_config_file_fallback(file_ctx->parent_ctx,
f072359f493a5209335799da85ac16d6a273303bgryzor /* A new callback was created in monitor_config_file_fallback()*/
f072359f493a5209335799da85ac16d6a273303bgryzor cb->wd = inotify_add_watch(file_ctx->mt_ctx->inotify_fd,
f072359f493a5209335799da85ac16d6a273303bgryzor ("Could not add inotify watch for file [%s]. Error [%d:%s]\n",
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe tev = tevent_add_timer(ev, ev, tv, rewatch_config_file, rw_ctx);
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe ("Could not restore inotify watch. Quitting!\n"));
f072359f493a5209335799da85ac16d6a273303bgryzor /* Tell the monitor to signal the children */
f072359f493a5209335799da85ac16d6a273303bgryzorstatic void poll_config_file(struct tevent_context *ev,
f072359f493a5209335799da85ac16d6a273303bgryzor file_ctx = talloc_get_type(ptr,struct config_file_ctx);
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0, ("Could not stat file [%s]. Error [%d:%s]\n",
f072359f493a5209335799da85ac16d6a273303bgryzor /* TODO: If the config file is missing, should we shut down? */
9534272616b71aaea50aeec4162e749a96aebd7fsf /* Parse the configuration file and signal the children */
9534272616b71aaea50aeec4162e749a96aebd7fsf /* Note: this will fire if the modification time changes into the past
9534272616b71aaea50aeec4162e749a96aebd7fsf * as well as the future.
9534272616b71aaea50aeec4162e749a96aebd7fsf /* Tell the monitor to signal the children */
9534272616b71aaea50aeec4162e749a96aebd7fsf file_ctx->timer = tevent_add_timer(ev, file_ctx->parent_ctx, tv,
9534272616b71aaea50aeec4162e749a96aebd7fsf DEBUG(0, ("Error: Config file no longer monitored for changes!\n"));
f072359f493a5209335799da85ac16d6a273303bgryzorstatic int try_inotify(struct config_file_ctx *file_ctx, const char *filename,
f072359f493a5209335799da85ac16d6a273303bgryzor /* Monitoring the file descriptor should be global */
3c13a815670b54d1c17bf02954f7d2b066cde95cnd /* Set up inotify to monitor the config file for changes */
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0, ("Could not initialize inotify, error [%d:%s]\n",
f072359f493a5209335799da85ac16d6a273303bgryzor fd_args = fcntl(file_ctx->mt_ctx->inotify_fd, F_GETFL, NULL);
f072359f493a5209335799da85ac16d6a273303bgryzor /* Could not set nonblocking */
f072359f493a5209335799da85ac16d6a273303bgryzor ret = fcntl(file_ctx->mt_ctx->inotify_fd, F_SETFL, fd_args);
f072359f493a5209335799da85ac16d6a273303bgryzor /* Could not set nonblocking */
f072359f493a5209335799da85ac16d6a273303bgryzor /* Add the inotify file descriptor to the TEvent context */
f072359f493a5209335799da85ac16d6a273303bgryzor cb = talloc_zero(file_ctx, struct config_file_callback);
f072359f493a5209335799da85ac16d6a273303bgryzor cb->wd = inotify_add_watch(file_ctx->mt_ctx->inotify_fd,
f072359f493a5209335799da85ac16d6a273303bgryzor DEBUG(0, ("Could not add inotify watch for file [%s]. Error [%d:%s]\n",
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim const char *file,
f072359f493a5209335799da85ac16d6a273303bgryzor ("file [%s] is missing. Will not update online status "
f072359f493a5209335799da85ac16d6a273303bgryzor ("Could not stat file [%s]. Error [%d:%s]\n",
f072359f493a5209335799da85ac16d6a273303bgryzor ctx->file_ctx = talloc_zero(mem_ctx, struct config_file_ctx);
f072359f493a5209335799da85ac16d6a273303bgryzor /* Could not monitor file with inotify, fall back to polling */
f072359f493a5209335799da85ac16d6a273303bgryzor ret = monitor_config_file_fallback(mem_ctx, ctx, file, fn, true);
f072359f493a5209335799da85ac16d6a273303bgryzorerrno_t monitor_config_file_fallback(TALLOC_CTX *mem_ctx,
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim const char *file,
f072359f493a5209335799da85ac16d6a273303bgryzor ("file [%s] is missing. Will not update online status "
f072359f493a5209335799da85ac16d6a273303bgryzor ("Could not stat file [%s]. Error [%d:%s]\n",
f072359f493a5209335799da85ac16d6a273303bgryzor cb = talloc_zero(ctx->file_ctx, struct config_file_callback);
27a7b74f8c50bd6074b0c71fae9927a71fde5b3fjim ctx->file_ctx->timer = tevent_add_timer(ctx->ev, mem_ctx, tv,
f072359f493a5209335799da85ac16d6a273303bgryzor /* Set up the environment variable for the Kerberos Replay Cache */
0844fff26cb7719e0f0a368d88544156ed6374b6sf if (ret < 0) {
0844fff26cb7719e0f0a368d88544156ed6374b6sf ("Unable to set KRB5RCACHEDIR: %s."
0844fff26cb7719e0f0a368d88544156ed6374b6sf "Will attempt to use libkrb5 defaults\n",
f072359f493a5209335799da85ac16d6a273303bgryzor /* Set up an event handler for a SIGHUP */
f072359f493a5209335799da85ac16d6a273303bgryzor /* Set up an event handler for a SIGINT */
f072359f493a5209335799da85ac16d6a273303bgryzor /* Set up an event handler for a SIGTERM */
f072359f493a5209335799da85ac16d6a273303bgryzor /* Handle SIGUSR1 (tell all providers to go offline) */
48c64aeceef385e19025b384bd719b2a9789592dnd /* Handle SIGUSR2 (tell all providers to go reset offline) */
f072359f493a5209335799da85ac16d6a273303bgryzor /* Set up the SIGCHLD handler */
f072359f493a5209335799da85ac16d6a273303bgryzor ret = sss_sigchld_init(ctx, ctx->ev, &ctx->sigchld_ctx);
f072359f493a5209335799da85ac16d6a273303bgryzor This feature is incomplete and can leave the SSSD in a bad state if the
f072359f493a5209335799da85ac16d6a273303bgryzor Uncomment this once the backends are honoring reloadConfig()
f072359f493a5209335799da85ac16d6a273303bgryzor /* Watch for changes to the confdb config file */
f072359f493a5209335799da85ac16d6a273303bgryzor ret = monitor_config_file(ctx, ctx, config_file, monitor_signal_reconf,
f072359f493a5209335799da85ac16d6a273303bgryzor /* Watch for changes to the DNS resolv.conf */
f072359f493a5209335799da85ac16d6a273303bgryzor ret = monitor_config_file(ctx, ctx, RESOLV_CONF_PATH,
f072359f493a5209335799da85ac16d6a273303bgryzor /* Avoid a startup race condition between process.
f072359f493a5209335799da85ac16d6a273303bgryzor * We need to handle DB upgrades or DB creation only
f072359f493a5209335799da85ac16d6a273303bgryzor * in one process before all other start.
48c64aeceef385e19025b384bd719b2a9789592dnd ret = sysdb_init(tmp_ctx, ctx->cdb, NULL, true, &db_list);
f072359f493a5209335799da85ac16d6a273303bgryzor /* Initialize D-BUS Server
f072359f493a5209335799da85ac16d6a273303bgryzor * The monitor will act as a D-BUS server for all
f072359f493a5209335799da85ac16d6a273303bgryzor * SSSD processes */
0d0ba3a410038e179b695446bb149cce6264e0abnd ret = setup_netlink(ctx, ctx->ev, network_status_change_cb,
0d0ba3a410038e179b695446bb149cce6264e0abnd DEBUG(2, ("Cannot set up listening for network notifications\n"));
0d0ba3a410038e179b695446bb149cce6264e0abnd /* start providers */
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd /* now set the services stratup timeout *
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * (responders will be started automatically when all
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * providers are up and running or when the tomeout
f072359f493a5209335799da85ac16d6a273303bgryzor * expires) */
return ret;
return EOK;
if (!mini) {
return ENOMEM;
return ENOMEM;
return EOK;
int ret;
return ENXIO;
if (!msg) {
return ENOMEM;
return ret;
const char *dbus_error_name;
int type;
if (!svc) {
if (!reply) {
goto done;
switch (type) {
case DBUS_MESSAGE_TYPE_ERROR:
if (!dbus_error_name) {
done:
return ENOMEM;
return EOK;
char **args;
int opt;
int opt_daemon = 0;
int opt_interactive = 0;
int opt_version = 0;
int flags = 0;
int ret;
switch(opt) {
if (opt_version) {
return EXIT_SUCCESS;
if (uid != 0) {
if (!tmp_ctx) {
if (opt_config_file) {
if (!config_file) {
if (debug_to_file) {
if (ret) {
#ifdef USE_KEYRING