LCOV - code coverage report
Current view: top level - monitor - monitor.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 1233 0.0 %
Date: 2015-10-19 Functions: 0 64 0.0 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    Service monitor
       5             : 
       6             :    Copyright (C) Simo Sorce                     2008
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "util/util.h"
      23             : #include "util/child_common.h"
      24             : #include <sys/types.h>
      25             : #include <sys/wait.h>
      26             : #include <sys/time.h>
      27             : #include <sys/param.h>
      28             : #include <time.h>
      29             : #include <string.h>
      30             : #ifdef HAVE_SYS_INOTIFY_H
      31             : #include <sys/inotify.h>
      32             : #endif
      33             : #include <sys/types.h>
      34             : #include <sys/stat.h>
      35             : #include <unistd.h>
      36             : #include <fcntl.h>
      37             : #include <popt.h>
      38             : #include <tevent.h>
      39             : #include <dbus/dbus.h>
      40             : 
      41             : /* Needed for res_init() */
      42             : #include <netinet/in.h>
      43             : #include <arpa/nameser.h>
      44             : #include <resolv.h>
      45             : 
      46             : #include "confdb/confdb.h"
      47             : #include "confdb/confdb_setup.h"
      48             : #include "db/sysdb.h"
      49             : #include "monitor/monitor.h"
      50             : #include "sbus/sssd_dbus.h"
      51             : #include "monitor/monitor_interfaces.h"
      52             : #include "responder/common/responder_sbus.h"
      53             : 
      54             : #ifdef USE_KEYRING
      55             : #include <keyutils.h>
      56             : #endif
      57             : 
      58             : /* ping time cannot be less then once every few seconds or the
      59             :  * monitor will get crazy hammering children with messages */
      60             : #define MONITOR_DEF_PING_TIME 10
      61             : /* terminate the child after this interval by default if it
      62             :  * doesn't shutdown on receiving SIGTERM */
      63             : #define MONITOR_DEF_FORCE_TIME 60
      64             : 
      65             : /* TODO: get the restart related values from config */
      66             : #define MONITOR_RESTART_CNT_INTERVAL_RESET   30
      67             : /* maximum allowed number of service restarts if the restarts
      68             :  * were less than MONITOR_RESTART_CNT_INTERVAL_RESET apart, which would
      69             :  * indicate a crash after startup or after every request */
      70             : #define MONITOR_MAX_SVC_RESTARTS    2
      71             : /* The services are restarted with a delay in case the restart was
      72             :  * hitting a race condition where the DP is not ready yet either.
      73             :  * The MONITOR_MAX_RESTART_DELAY defines the maximum delay between
      74             :  * restarts.
      75             :  */
      76             : #define MONITOR_MAX_RESTART_DELAY   4
      77             : 
      78             : /* name of the monitor server instance */
      79             : #define MONITOR_NAME        "sssd"
      80             : #define SSSD_PIDFILE_PATH   PID_PATH"/"MONITOR_NAME".pid"
      81             : 
      82             : /* Special value to leave the Kerberos Replay Cache set to use
      83             :  * the libkrb5 defaults
      84             :  */
      85             : #define KRB5_RCACHE_DIR_DISABLE "__LIBKRB5_DEFAULTS__"
      86             : 
      87             : /* Warning messages */
      88             : #define CONF_FILE_PERM_ERROR_MSG "Cannot read config file %s. Please check "\
      89             :                                  "that the file is accessible only by the "\
      90             :                                  "owner and owned by root.root.\n"
      91             : 
      92             : int cmdline_debug_level;
      93             : int cmdline_debug_timestamps;
      94             : int cmdline_debug_microseconds;
      95             : 
      96             : struct svc_spy;
      97             : 
      98             : enum mt_svc_type {
      99             :     MT_SVC_SERVICE,
     100             :     MT_SVC_PROVIDER
     101             : };
     102             : 
     103             : struct mt_svc {
     104             :     struct mt_svc *prev;
     105             :     struct mt_svc *next;
     106             :     enum mt_svc_type type;
     107             : 
     108             :     struct sbus_connection *conn;
     109             :     struct svc_spy *conn_spy;
     110             : 
     111             :     struct mt_ctx *mt_ctx;
     112             : 
     113             :     char *provider;
     114             :     char *command;
     115             :     char *name;
     116             :     char *identity;
     117             :     pid_t pid;
     118             : 
     119             :     int ping_time;
     120             :     int kill_time;
     121             : 
     122             :     struct tevent_timer *kill_timer;
     123             : 
     124             :     bool svc_started;
     125             : 
     126             :     int restarts;
     127             :     time_t last_restart;
     128             :     int failed_pongs;
     129             :     DBusPendingCall *pending;
     130             : 
     131             :     int debug_level;
     132             : 
     133             :     struct tevent_timer *ping_ev;
     134             : 
     135             :     struct sss_child_ctx *child_ctx;
     136             : };
     137             : 
     138             : struct config_file_callback {
     139             :     int wd;
     140             :     int retries;
     141             :     monitor_reconf_fn fn;
     142             :     char *filename;
     143             :     time_t modified;
     144             :     struct config_file_callback *next;
     145             :     struct config_file_callback *prev;
     146             : };
     147             : 
     148             : struct config_file_ctx {
     149             :     TALLOC_CTX *parent_ctx;
     150             :     struct tevent_timer *timer;
     151             :     bool needs_update;
     152             :     struct mt_ctx *mt_ctx;
     153             :     struct config_file_callback *callbacks;
     154             : };
     155             : 
     156             : struct mt_ctx {
     157             :     struct tevent_context *ev;
     158             :     struct confdb_ctx *cdb;
     159             :     struct sss_domain_info *domains;
     160             :     char **services;
     161             :     int num_services;
     162             :     int started_services;
     163             :     struct mt_svc *svc_list;
     164             :     struct sbus_connection *sbus_srv;
     165             :     struct config_file_ctx *file_ctx;
     166             :     int inotify_fd;
     167             :     int service_id_timeout;
     168             :     bool check_children;
     169             :     bool services_started;
     170             :     struct netlink_ctx *nlctx;
     171             :     const char *conf_path;
     172             :     struct sss_sigchild_ctx *sigchld_ctx;
     173             :     bool is_daemon;
     174             :     pid_t parent_pid;
     175             : 
     176             :     /* For running unprivileged services */
     177             :     uid_t uid;
     178             :     gid_t gid;
     179             : };
     180             : 
     181             : static int start_service(struct mt_svc *mt_svc);
     182             : 
     183             : static int monitor_service_init(struct sbus_connection *conn, void *data);
     184             : 
     185             : static int service_send_ping(struct mt_svc *svc);
     186             : static int service_signal_reset_offline(struct mt_svc *svc);
     187             : static void ping_check(DBusPendingCall *pending, void *data);
     188             : 
     189             : static void set_tasks_checker(struct mt_svc *srv);
     190             : static int monitor_kill_service (struct mt_svc *svc);
     191             : 
     192             : static int get_service_config(struct mt_ctx *ctx, const char *name,
     193             :                               struct mt_svc **svc_cfg);
     194             : static int get_provider_config(struct mt_ctx *ctx, const char *name,
     195             :                               struct mt_svc **svc_cfg);
     196             : static int add_new_service(struct mt_ctx *ctx,
     197             :                            const char *name,
     198             :                            int restarts);
     199             : static int add_new_provider(struct mt_ctx *ctx,
     200             :                             const char *name,
     201             :                             int restarts);
     202             : 
     203             : static int mark_service_as_started(struct mt_svc *svc);
     204             : 
     205             : static int monitor_cleanup(void);
     206             : 
     207           0 : static void network_status_change_cb(void *cb_data)
     208             : {
     209             :     struct mt_svc *iter;
     210           0 :     struct mt_ctx *ctx = (struct mt_ctx *) cb_data;
     211             : 
     212           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "A networking status change detected "
     213             :           "signaling providers to reset offline status\n");
     214           0 :     for (iter = ctx->svc_list; iter; iter = iter->next) {
     215             :         /* Don't signal services, only providers */
     216           0 :         if (iter->provider) {
     217           0 :             service_signal_reset_offline(iter);
     218             :         }
     219             :     }
     220           0 : }
     221             : 
     222             : /* dbus_get_monitor_version
     223             :  * Return the monitor version over D-BUS */
     224           0 : static int get_monitor_version(struct sbus_request *dbus_req, void *data)
     225             : {
     226           0 :     dbus_uint16_t version = MONITOR_VERSION;
     227             : 
     228           0 :     return sbus_request_return_and_finish(dbus_req,
     229             :                                           DBUS_TYPE_UINT16, &version,
     230             :                                           DBUS_TYPE_INVALID);
     231             : }
     232             : 
     233             : struct mon_init_conn {
     234             :     struct mt_ctx *ctx;
     235             :     struct sbus_connection *conn;
     236             :     struct tevent_timer *timeout;
     237             : };
     238             : 
     239             : static int add_svc_conn_spy(struct mt_svc *svc);
     240             : 
     241             : /* registers a new client.
     242             :  * if operation is successful also sends back the Monitor version */
     243           0 : static int client_registration(struct sbus_request *dbus_req, void *data)
     244             : {
     245           0 :     dbus_uint16_t version = MONITOR_VERSION;
     246             :     struct mon_init_conn *mini;
     247             :     struct mt_svc *svc;
     248             :     DBusError dbus_error;
     249             :     dbus_uint16_t svc_ver;
     250             :     char *svc_name;
     251             :     dbus_bool_t dbret;
     252             :     int ret;
     253             : 
     254           0 :     mini = talloc_get_type(data, struct mon_init_conn);
     255           0 :     if (!mini) {
     256           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
     257           0 :         return EINVAL;
     258             :     }
     259             : 
     260             :     /* First thing, cancel the timeout */
     261           0 :     talloc_zfree(mini->timeout);
     262             : 
     263           0 :     dbus_error_init(&dbus_error);
     264             : 
     265           0 :     dbret = dbus_message_get_args(dbus_req->message, &dbus_error,
     266             :                                   DBUS_TYPE_STRING, &svc_name,
     267             :                                   DBUS_TYPE_UINT16, &svc_ver,
     268             :                                   DBUS_TYPE_INVALID);
     269           0 :     if (!dbret) {
     270           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     271             :               "Failed to parse message, killing connection\n");
     272           0 :         if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
     273           0 :         sbus_disconnect(dbus_req->conn);
     274           0 :         sbus_request_finish(dbus_req, NULL);
     275             :         /* FIXME: should we just talloc_zfree(conn) ? */
     276           0 :         goto done;
     277             :     }
     278             : 
     279           0 :     DEBUG(SSSDBG_CONF_SETTINGS,
     280             :           "Received ID registration: (%s,%d)\n", svc_name, svc_ver);
     281             : 
     282             :     /* search this service in the list */
     283           0 :     svc = mini->ctx->svc_list;
     284           0 :     while (svc) {
     285           0 :         ret = strcasecmp(svc->identity, svc_name);
     286           0 :         if (ret == 0) {
     287           0 :             break;
     288             :         }
     289           0 :         svc = svc->next;
     290             :     }
     291           0 :     if (!svc) {
     292           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     293             :               "Unable to find peer [%s] in list of services,"
     294             :                   " killing connection!\n", svc_name);
     295           0 :         sbus_disconnect(dbus_req->conn);
     296           0 :         sbus_request_finish(dbus_req, NULL);
     297             :         /* FIXME: should we just talloc_zfree(conn) ? */
     298           0 :         goto done;
     299             :     }
     300             : 
     301             :     /* Fill in svc structure with connection data */
     302           0 :     svc->conn = mini->conn;
     303             : 
     304           0 :     ret = mark_service_as_started(svc);
     305           0 :     if (ret) {
     306           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to mark service [%s]!\n", svc_name);
     307           0 :         goto done;
     308             :     }
     309             : 
     310             :     /* reply that all is ok */
     311           0 :     sbus_request_return_and_finish(dbus_req,
     312             :                                    DBUS_TYPE_UINT16, &version,
     313             :                                    DBUS_TYPE_INVALID);
     314             : 
     315             : done:
     316             :     /* init complete, get rid of temp init context */
     317           0 :     talloc_zfree(mini);
     318             : 
     319           0 :     return EOK;
     320             : }
     321             : 
     322             : struct svc_spy {
     323             :     struct mt_svc *svc;
     324             : };
     325             : 
     326           0 : static int svc_destructor(void *mem)
     327             : {
     328           0 :     struct mt_svc *svc = talloc_get_type(mem, struct mt_svc);
     329           0 :     if (!svc) {
     330             :         /* ?!?!? */
     331           0 :         return 0;
     332             :     }
     333             : 
     334             :     /* try to delist service */
     335           0 :     if (svc->mt_ctx) {
     336           0 :         DLIST_REMOVE(svc->mt_ctx->svc_list, svc);
     337             :     }
     338             : 
     339             :     /* Cancel any pending pings */
     340           0 :     if (svc->pending) {
     341           0 :         dbus_pending_call_cancel(svc->pending);
     342             :     }
     343             : 
     344             :     /* svc is being freed, neutralize the spy */
     345           0 :     if (svc->conn_spy) {
     346           0 :         talloc_set_destructor((TALLOC_CTX *)svc->conn_spy, NULL);
     347           0 :         talloc_zfree(svc->conn_spy);
     348             :     }
     349             : 
     350           0 :     if (svc->type == MT_SVC_SERVICE && svc->svc_started
     351           0 :             && svc->mt_ctx != NULL && svc->mt_ctx->started_services > 0) {
     352           0 :         svc->mt_ctx->started_services--;
     353             :     }
     354             : 
     355           0 :     return 0;
     356             : }
     357             : 
     358           0 : static int svc_spy_destructor(void *mem)
     359             : {
     360           0 :     struct svc_spy *spy = talloc_get_type(mem, struct svc_spy);
     361           0 :     if (!spy) {
     362             :         /* ?!?!? */
     363           0 :         return 0;
     364             :     }
     365             : 
     366             :     /* svc->conn has been freed, NULL the pointer in svc */
     367           0 :     spy->svc->conn_spy = NULL;
     368           0 :     spy->svc->conn = NULL;
     369           0 :     return 0;
     370             : }
     371             : 
     372           0 : static int add_svc_conn_spy(struct mt_svc *svc)
     373             : {
     374             :     struct svc_spy *spy;
     375             : 
     376           0 :     spy = talloc(svc->conn, struct svc_spy);
     377           0 :     if (!spy) return ENOMEM;
     378             : 
     379           0 :     spy->svc = svc;
     380           0 :     talloc_set_destructor((TALLOC_CTX *)spy, svc_spy_destructor);
     381           0 :     svc->conn_spy = spy;
     382             : 
     383           0 :     return EOK;
     384             : }
     385             : 
     386           0 : static int mark_service_as_started(struct mt_svc *svc)
     387             : {
     388           0 :     struct mt_ctx *ctx = svc->mt_ctx;
     389             :     struct mt_svc *iter;
     390             :     int ret;
     391             :     int i;
     392             : 
     393           0 :     DEBUG(SSSDBG_FUNC_DATA, "Marking %s as started.\n", svc->name);
     394           0 :     svc->svc_started = true;
     395             : 
     396             :     /* we need to attach a spy to the connection structure so that if some code
     397             :      * frees it we can zero it out in the service structure. Otherwise we may
     398             :      * try to access or even free, freed memory. */
     399           0 :     ret = add_svc_conn_spy(svc);
     400           0 :     if (ret) {
     401           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to attch spy\n");
     402           0 :         goto done;
     403             :     }
     404             : 
     405           0 :     if (!ctx->services_started) {
     406             : 
     407             :         /* check if all providers are up */
     408           0 :         for (iter = ctx->svc_list; iter; iter = iter->next) {
     409           0 :             if (iter->provider && !iter->svc_started) {
     410           0 :                 DEBUG(SSSDBG_FUNC_DATA,
     411             :                       "Still waiting on %s provider.\n", iter->name);
     412           0 :                 break;
     413             :             }
     414             :         }
     415             : 
     416           0 :         if (iter) {
     417             :             /* there are still unstarted providers */
     418           0 :             goto done;
     419             :         }
     420             : 
     421           0 :         ctx->services_started = true;
     422             : 
     423           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Now starting services!\n");
     424             :         /* then start all services */
     425           0 :         for (i = 0; ctx->services[i]; i++) {
     426           0 :             add_new_service(ctx, ctx->services[i], 0);
     427             :         }
     428             :     }
     429             : 
     430           0 :     if (svc->type == MT_SVC_SERVICE) {
     431           0 :         ctx->started_services++;
     432             :     }
     433             : 
     434           0 :     if (ctx->started_services == ctx->num_services) {
     435             :         /* Initialization is complete, terminate parent process if in daemon
     436             :          * mode. Make sure we send the signal to the right process */
     437           0 :         if (ctx->is_daemon) {
     438           0 :             if (ctx->parent_pid <= 1 || ctx->parent_pid != getppid()) {
     439             :                 /* the parent process was already terminated */
     440           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Invalid parent pid: %d\n",
     441             :                       ctx->parent_pid);
     442           0 :                 goto done;
     443             :             }
     444             : 
     445           0 :             DEBUG(SSSDBG_TRACE_FUNC, "SSSD is initialized, "
     446             :                                       "terminating parent process\n");
     447             : 
     448           0 :             errno = 0;
     449           0 :             ret = kill(ctx->parent_pid, SIGTERM);
     450           0 :             if (ret != 0) {
     451           0 :                 ret = errno;
     452           0 :                 DEBUG(SSSDBG_FATAL_FAILURE, "Unable to terminate parent "
     453             :                       "process [%d]: %s\n", ret, strerror(ret));
     454             :             }
     455             :         }
     456             :     }
     457             : 
     458             : done:
     459           0 :     return ret;
     460             : }
     461             : 
     462           0 : static void services_startup_timeout(struct tevent_context *ev,
     463             :                                      struct tevent_timer *te,
     464             :                                      struct timeval t, void *ptr)
     465             : {
     466           0 :     struct mt_ctx *ctx = talloc_get_type(ptr, struct mt_ctx);
     467             :     int i;
     468             : 
     469           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Handling timeout\n");
     470             : 
     471           0 :     if (!ctx->services_started) {
     472             : 
     473           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Providers did not start in time, "
     474             :                   "forcing services startup!\n");
     475             : 
     476           0 :         ctx->services_started = true;
     477             : 
     478           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Now starting services!\n");
     479             :         /* then start all services */
     480           0 :         for (i = 0; ctx->services[i]; i++) {
     481           0 :             add_new_service(ctx, ctx->services[i], 0);
     482             :         }
     483             :     }
     484           0 : }
     485             : 
     486           0 : static int add_services_startup_timeout(struct mt_ctx *ctx)
     487             : {
     488             :     struct tevent_timer *to;
     489             :     struct timeval tv;
     490             : 
     491             :     /* 5 seconds should be plenty */
     492           0 :     tv = tevent_timeval_current_ofs(5, 0);
     493           0 :     to = tevent_add_timer(ctx->ev, ctx, tv, services_startup_timeout, ctx);
     494           0 :     if (!to) {
     495           0 :         DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
     496           0 :         return ENOMEM;
     497             :     }
     498             : 
     499           0 :     return EOK;
     500             : }
     501             : 
     502             : struct mon_srv_iface monitor_methods = {
     503             :     { &mon_srv_iface_meta, 0 },
     504             :     .getVersion = get_monitor_version,
     505             :     .RegisterService = client_registration,
     506             : };
     507             : 
     508             : /* monitor_dbus_init
     509             :  * Set up the monitor service as a D-BUS Server */
     510           0 : static int monitor_dbus_init(struct mt_ctx *ctx)
     511             : {
     512             :     char *monitor_address;
     513             :     int ret;
     514             : 
     515           0 :     ret = monitor_get_sbus_address(ctx, &monitor_address);
     516           0 :     if (ret != EOK) {
     517           0 :         return ret;
     518             :     }
     519             : 
     520             :     /* If a service is running as unprivileged user, we need to make sure this
     521             :      * user can access the monitor sbus server. root is still king, so we don't
     522             :      * lose any access.
     523             :      */
     524           0 :     ret = sbus_new_server(ctx, ctx->ev, monitor_address, ctx->uid, ctx->gid,
     525             :                           false, &ctx->sbus_srv, monitor_service_init, ctx);
     526             : 
     527           0 :     talloc_free(monitor_address);
     528             : 
     529           0 :     return ret;
     530             : }
     531             : 
     532           0 : static void tasks_check_handler(struct tevent_context *ev,
     533             :                                 struct tevent_timer *te,
     534             :                                 struct timeval t, void *ptr)
     535             : {
     536           0 :     struct mt_svc *svc = talloc_get_type(ptr, struct mt_svc);
     537             :     int ret;
     538             : 
     539           0 :     ret = service_send_ping(svc);
     540           0 :     switch (ret) {
     541             :     case EOK:
     542             :         /* all fine */
     543           0 :         break;
     544             : 
     545             :     case ENXIO:
     546           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     547             :               "Child (%s) not responding! (yet)\n", svc->name);
     548           0 :         break;
     549             : 
     550             :     default:
     551             :         /* TODO: should we tear it down ? */
     552           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     553             :               "Sending a message to service (%s) failed!!\n", svc->name);
     554           0 :         break;
     555             :     }
     556             : 
     557           0 :     if (svc->failed_pongs >= 3) {
     558             :         /* too long since we last heard of this process */
     559           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     560             :               "Killing service [%s], not responding to pings!\n",
     561             :                svc->name);
     562           0 :         sss_log(SSS_LOG_ERR,
     563             :                 "Killing service [%s], not responding to pings!\n",
     564             :                 svc->name);
     565             : 
     566             :         /* Kill the service. The SIGCHLD handler will restart it */
     567           0 :         monitor_kill_service(svc);
     568           0 :         return;
     569             :     }
     570             : 
     571             :     /* all fine, set up the task checker again */
     572           0 :     set_tasks_checker(svc);
     573             : }
     574             : 
     575           0 : static void set_tasks_checker(struct mt_svc *svc)
     576             : {
     577           0 :     struct tevent_timer *te = NULL;
     578             :     struct timeval tv;
     579             : 
     580           0 :     gettimeofday(&tv, NULL);
     581           0 :     tv.tv_sec += svc->ping_time;
     582           0 :     tv.tv_usec = 0;
     583           0 :     te = tevent_add_timer(svc->mt_ctx->ev, svc, tv, tasks_check_handler, svc);
     584           0 :     if (te == NULL) {
     585           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     586             :               "failed to add event, monitor offline for [%s]!\n",
     587             :                   svc->name);
     588             :         /* FIXME: shutdown ? */
     589             :     }
     590           0 :     svc->ping_ev = te;
     591           0 : }
     592             : 
     593             : static void monitor_restart_service(struct mt_svc *svc);
     594             : static void mt_svc_sigkill(struct tevent_context *ev,
     595             :                            struct tevent_timer *te,
     596             :                            struct timeval t, void *ptr);
     597           0 : static int monitor_kill_service (struct mt_svc *svc)
     598             : {
     599             :     int ret;
     600             :     struct timeval tv;
     601             : 
     602           0 :     ret = kill(svc->pid, SIGTERM);
     603           0 :     if (ret == -1) {
     604           0 :         ret = errno;
     605           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     606             :               "Sending signal to child (%s:%d) failed: [%d]: %s! "
     607             :                "Ignore and pretend child is dead.\n",
     608             :                svc->name, svc->pid, ret, strerror(ret));
     609             :         /* The only thing we can try here is to launch a new process
     610             :          * and hope that it works.
     611             :          */
     612           0 :         monitor_restart_service(svc);
     613           0 :         return EOK;
     614             :     }
     615             : 
     616             :     /* Set up a timer to send SIGKILL if this process
     617             :      * doesn't exit within sixty seconds
     618             :      */
     619           0 :     tv = tevent_timeval_current_ofs(svc->kill_time, 0);
     620           0 :     svc->kill_timer = tevent_add_timer(svc->mt_ctx->ev,
     621             :                                        svc,
     622             :                                        tv,
     623             :                                        mt_svc_sigkill,
     624             :                                        svc);
     625           0 :     if (svc->kill_timer == NULL) {
     626             :         /* Nothing much we can do */
     627           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     628             :               "Failed to allocate timed event: mt_svc_sigkill.\n");
     629             :         /* We'll just have to hope that the SIGTERM succeeds */
     630             :     }
     631             : 
     632           0 :     return EOK;
     633             : }
     634             : 
     635           0 : static void mt_svc_sigkill(struct tevent_context *ev,
     636             :                            struct tevent_timer *te,
     637             :                            struct timeval t, void *ptr)
     638             : {
     639             :     int ret;
     640           0 :     struct mt_svc *svc = talloc_get_type(ptr, struct mt_svc);
     641             : 
     642           0 :     DEBUG(SSSDBG_FATAL_FAILURE,
     643             :           "[%s][%d] is not responding to SIGTERM. Sending SIGKILL.\n",
     644             :            svc->name, svc->pid);
     645           0 :     sss_log(SSS_LOG_ERR,
     646             :             "[%s][%d] is not responding to SIGTERM. Sending SIGKILL.\n",
     647             :             svc->name, svc->pid);
     648             : 
     649             :     /* timer was succesfully executed and it will be released by tevent */
     650           0 :     svc->kill_timer = NULL;
     651             : 
     652           0 :     ret = kill(svc->pid, SIGKILL);
     653           0 :     if (ret != EOK) {
     654           0 :         ret = errno;
     655           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     656             :               "Sending signal to child (%s:%d) failed! "
     657             :               "Ignore and pretend child is dead.\n",
     658             :               svc->name, svc->pid);
     659             : 
     660           0 :         if (ret == ESRCH) {
     661             :             /* The process doesn't exist
     662             :              * This most likely means we hit a race where
     663             :              * the SIGTERM concluded just after the timer
     664             :              * fired but before we called kill() here.
     665             :              * We'll just do nothing, since the
     666             :              * mt_svc_exit_handler() should be doing the
     667             :              * necessary work.
     668             :              */
     669           0 :             return;
     670             :         }
     671             : 
     672             :         /* Something went really wrong.
     673             :          * The only thing we can try here is to launch a new process
     674             :          * and hope that it works.
     675             :          */
     676           0 :         monitor_restart_service(svc);
     677             :     }
     678             : 
     679             :     /* The process should terminate immediately and then be
     680             :      * restarted by the mt_svc_exit_handler()
     681             :      */
     682           0 :     return;
     683             : }
     684             : 
     685           0 : static void reload_reply(DBusPendingCall *pending, void *data)
     686             : {
     687             :     DBusMessage *reply;
     688           0 :     struct mt_svc *svc = talloc_get_type(data, struct mt_svc);
     689             : 
     690           0 :     reply = dbus_pending_call_steal_reply(pending);
     691           0 :     if (!reply) {
     692             :         /* reply should never be null. This function shouldn't be called
     693             :          * until reply is valid or timeout has occurred. If reply is NULL
     694             :          * here, something is seriously wrong and we should bail out.
     695             :          */
     696           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     697             :               "A reply callback was called but no reply was received"
     698             :                   " and no timeout occurred\n");
     699             :         /* Destroy this connection */
     700           0 :         sbus_disconnect(svc->conn);
     701           0 :         dbus_pending_call_unref(pending);
     702           0 :         return;
     703             :     }
     704             : 
     705             :     /* TODO: Handle cases where the call has timed out or returned
     706             :      * with an error.
     707             :      */
     708             : 
     709           0 :     dbus_pending_call_unref(pending);
     710           0 :     dbus_message_unref(reply);
     711             : }
     712             : 
     713             : static int service_signal_dns_reload(struct mt_svc *svc);
     714           0 : static int monitor_update_resolv(struct config_file_ctx *file_ctx,
     715             :                           const char *filename)
     716             : {
     717             :     int ret;
     718             :     struct mt_svc *cur_svc;
     719           0 :     DEBUG(SSSDBG_OP_FAILURE, "Resolv.conf has been updated. Reloading.\n");
     720             : 
     721           0 :     ret = res_init();
     722           0 :     if(ret != 0) {
     723           0 :         return EIO;
     724             :     }
     725             : 
     726             :     /* Signal all services to reload their DNS configuration */
     727           0 :     for(cur_svc = file_ctx->mt_ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
     728           0 :         service_signal_dns_reload(cur_svc);
     729             :     }
     730           0 :     return EOK;
     731             : }
     732             : 
     733           0 : static int service_signal(struct mt_svc *svc, const char *svc_signal)
     734             : {
     735             :     DBusMessage *msg;
     736             :     int ret;
     737             : 
     738           0 :     if (svc->provider && strcasecmp(svc->provider, "local") == 0) {
     739             :         /* The local provider requires no signaling */
     740           0 :         return EOK;
     741             :     }
     742             : 
     743           0 :     if (!svc->conn) {
     744             :         /* Avoid a race condition where we are trying to
     745             :          * order a service to reload that hasn't started
     746             :          * yet.
     747             :          */
     748           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     749             :               "Could not signal service [%s].\n", svc->name);
     750           0 :         return EIO;
     751             :     }
     752             : 
     753           0 :     msg = dbus_message_new_method_call(NULL,
     754             :                                        MONITOR_PATH,
     755             :                                        MON_CLI_IFACE,
     756             :                                        svc_signal);
     757           0 :     if (msg == NULL) {
     758           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     759             :               "Out of memory trying to allocate memory to invoke: %s\n",
     760             :                svc_signal);
     761           0 :         monitor_kill_service(svc);
     762           0 :         return ENOMEM;
     763             :     }
     764             : 
     765           0 :     ret = sbus_conn_send(svc->conn, msg,
     766           0 :                          svc->mt_ctx->service_id_timeout,
     767             :                          reload_reply, svc, NULL);
     768             : 
     769           0 :     dbus_message_unref(msg);
     770           0 :     return ret;
     771             : }
     772             : 
     773           0 : static int service_signal_dns_reload(struct mt_svc *svc)
     774             : {
     775           0 :     return service_signal(svc, MON_CLI_IFACE_RESINIT);
     776             : }
     777           0 : static int service_signal_offline(struct mt_svc *svc)
     778             : {
     779           0 :     return service_signal(svc, MON_CLI_IFACE_GOOFFLINE);
     780             : }
     781           0 : static int service_signal_reset_offline(struct mt_svc *svc)
     782             : {
     783           0 :     return service_signal(svc, MON_CLI_IFACE_RESETOFFLINE);
     784             : }
     785           0 : static int service_signal_rotate(struct mt_svc *svc)
     786             : {
     787           0 :     return service_signal(svc, MON_CLI_IFACE_ROTATELOGS);
     788             : }
     789           0 : static int service_signal_clear_memcache(struct mt_svc *svc)
     790             : {
     791           0 :     return service_signal(svc, MON_CLI_IFACE_CLEARMEMCACHE);
     792             : }
     793           0 : static int service_signal_clear_enum_cache(struct mt_svc *svc)
     794             : {
     795           0 :     return service_signal(svc, MON_CLI_IFACE_CLEARENUMCACHE);
     796             : }
     797           0 : static int service_signal_sysbus_reconnect(struct mt_svc *svc)
     798             : {
     799           0 :     return service_signal(svc, MON_CLI_IFACE_SYSBUSRECONNECT);
     800             : }
     801             : 
     802           0 : static int check_domain_ranges(struct sss_domain_info *domains)
     803             : {
     804           0 :     struct sss_domain_info *dom = domains, *other = NULL;
     805             :     uint32_t id_min, id_max;
     806             : 
     807           0 :     while (dom) {
     808           0 :         other = get_next_domain(dom, false);
     809           0 :         if (dom->id_max && dom->id_min > dom->id_max) {
     810           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     811             :                   "Domain '%s' does not have a valid ID range\n", dom->name);
     812           0 :             return EINVAL;
     813             :         }
     814             : 
     815           0 :         while (other) {
     816           0 :             id_min = MAX(dom->id_min, other->id_min);
     817           0 :             id_max = MIN((dom->id_max ? dom->id_max : UINT32_MAX),
     818             :                          (other->id_max ? other->id_max : UINT32_MAX));
     819           0 :             if (id_min <= id_max) {
     820           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
     821             :                       "Domains '%s' and '%s' overlap in range %u - %u\n",
     822             :                       dom->name, other->name, id_min, id_max);
     823             :             }
     824           0 :             other = get_next_domain(other, false);
     825             :         }
     826           0 :         dom = get_next_domain(dom, false);
     827             :     }
     828             : 
     829           0 :     return EOK;
     830             : }
     831             : 
     832           0 : static int check_local_domain_unique(struct sss_domain_info *domains)
     833             : {
     834           0 :     uint8_t count = 0;
     835             : 
     836           0 :     struct sss_domain_info *dom = domains;
     837             : 
     838           0 :     while (dom) {
     839           0 :         if (strcasecmp(dom->provider, "local") == 0) {
     840           0 :             count++;
     841             :         }
     842             : 
     843           0 :         if (count > 1) {
     844           0 :             break;
     845             :         }
     846             : 
     847           0 :         dom = get_next_domain(dom, false);
     848             :     }
     849             : 
     850           0 :     if (count > 1) {
     851           0 :         return EINVAL;
     852             :     }
     853             : 
     854           0 :     return EOK;
     855             : }
     856             : 
     857           0 : static errno_t add_implicit_services(struct confdb_ctx *cdb, TALLOC_CTX *mem_ctx,
     858             :                                      char ***_services)
     859             : {
     860             :     int ret;
     861             :     char **domain_names;
     862             :     TALLOC_CTX *tmp_ctx;
     863             :     size_t c;
     864             :     char *conf_path;
     865             :     char *id_provider;
     866           0 :     bool add_pac = false;
     867             : 
     868           0 :     tmp_ctx = talloc_new(NULL);
     869           0 :     if (tmp_ctx == NULL) {
     870           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
     871           0 :         return ENOMEM;
     872             :     }
     873             : 
     874           0 :     ret = confdb_get_string_as_list(cdb, tmp_ctx,
     875             :                                     CONFDB_MONITOR_CONF_ENTRY,
     876             :                                     CONFDB_MONITOR_ACTIVE_DOMAINS,
     877             :                                     &domain_names);
     878           0 :     if (ret == ENOENT) {
     879           0 :         DEBUG(SSSDBG_OP_FAILURE, "No domains configured!\n");
     880           0 :         goto done;
     881             :     }
     882             : 
     883           0 :     for (c = 0; domain_names[c] != NULL; c++) {
     884           0 :         conf_path = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL,
     885           0 :                                     domain_names[c]);
     886           0 :         if (conf_path == NULL) {
     887           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
     888           0 :             ret = ENOMEM;
     889           0 :             goto done;
     890             :         }
     891             : 
     892           0 :         ret = confdb_get_string(cdb, tmp_ctx, conf_path,
     893             :                                 CONFDB_DOMAIN_ID_PROVIDER, NULL, &id_provider);
     894           0 :         if (ret == EOK) {
     895           0 :             if (id_provider == NULL) {
     896           0 :                 DEBUG(SSSDBG_OP_FAILURE, "id_provider is not set for "
     897             :                       "domain [%s], trying next domain.\n", domain_names[c]);
     898           0 :                 continue;
     899             :             }
     900             : 
     901           0 :             if (strcasecmp(id_provider, "IPA") == 0) {
     902           0 :                 add_pac = true;
     903             :             }
     904             :         } else {
     905           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to get id_provider for " \
     906             :                                       "domain [%s], trying next domain.\n",
     907             :                                       domain_names[c]);
     908             :         }
     909             :     }
     910             : 
     911           0 :     if (BUILD_WITH_PAC_RESPONDER && add_pac &&
     912           0 :         !string_in_list("pac", *_services, false)) {
     913           0 :         ret = add_string_to_list(mem_ctx, "pac", _services);
     914           0 :         if (ret != EOK) {
     915           0 :             DEBUG(SSSDBG_OP_FAILURE, "add_string_to_list failed.\n");
     916           0 :             goto done;
     917             :         }
     918             :     }
     919             : 
     920           0 :     ret = EOK;
     921             : 
     922             : done:
     923           0 :     talloc_free(tmp_ctx);
     924             : 
     925           0 :     return ret;
     926             : }
     927             : 
     928           0 : static char *check_services(char **services)
     929             : {
     930           0 :     const char * const *known_services = get_known_services();
     931             :     int i;
     932             :     int ii;
     933             : 
     934             :     /* Check if services we are about to start are in the list if known */
     935           0 :     for (i = 0; services[i]; i++) {
     936           0 :         for (ii=0; known_services[ii]; ii++) {
     937           0 :             if (strcasecmp(services[i], known_services[ii]) == 0) {
     938           0 :                 break;
     939             :             }
     940             :         }
     941             : 
     942           0 :         if (known_services[ii] == NULL) {
     943           0 :             return services[i];
     944             :         }
     945             :     }
     946             : 
     947           0 :     return NULL;
     948             : }
     949             : 
     950           0 : static int get_service_user(struct mt_ctx *ctx)
     951             : {
     952             :     errno_t ret;
     953             :     char *user_str;
     954             : 
     955           0 :     ret = confdb_get_string(ctx->cdb, ctx, CONFDB_MONITOR_CONF_ENTRY,
     956             :                             CONFDB_MONITOR_USER_RUNAS,
     957             :                             SSSD_USER, &user_str);
     958           0 :     if (ret != EOK) {
     959           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get the user to run as\n");
     960           0 :         return ret;
     961             :     }
     962             : 
     963           0 :     ret = sss_user_by_name_or_uid(user_str, &ctx->uid, &ctx->gid);
     964           0 :     talloc_free(user_str);
     965           0 :     if (ret != EOK) {
     966           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to set allowed UIDs.\n");
     967           0 :         return ret;
     968             :     }
     969             : 
     970           0 :     return EOK;
     971             : }
     972             : 
     973           0 : static int get_monitor_config(struct mt_ctx *ctx)
     974             : {
     975             :     int ret;
     976             :     int timeout_seconds;
     977           0 :     char *badsrv = NULL;
     978             :     int i;
     979             : 
     980           0 :     ret = confdb_get_int(ctx->cdb,
     981             :                          CONFDB_MONITOR_CONF_ENTRY,
     982             :                          CONFDB_MONITOR_SBUS_TIMEOUT,
     983             :                          10, &timeout_seconds);
     984           0 :     if (ret != EOK) {
     985           0 :         return ret;
     986             :     }
     987             : 
     988           0 :     ctx->service_id_timeout = timeout_seconds * 1000; /* service_id_timeout is in ms */
     989             : 
     990           0 :     ret = confdb_get_string_as_list(ctx->cdb, ctx,
     991             :                                     CONFDB_MONITOR_CONF_ENTRY,
     992             :                                     CONFDB_MONITOR_ACTIVE_SERVICES,
     993             :                                     &ctx->services);
     994           0 :     if (ret != EOK) {
     995           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "No services configured!\n");
     996           0 :         return EINVAL;
     997             :     }
     998             : 
     999           0 :     ret = add_implicit_services(ctx->cdb, ctx, &ctx->services);
    1000           0 :     if (ret != EOK) {
    1001           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to add implicit configured "
    1002             :                                  "services. Some functionality might "
    1003             :                                  "be missing\n");
    1004             :     }
    1005             : 
    1006           0 :     badsrv = check_services(ctx->services);
    1007           0 :     if (badsrv != NULL) {
    1008           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Invalid service %s\n", badsrv);
    1009           0 :         return EINVAL;
    1010             :     }
    1011             : 
    1012           0 :     ctx->started_services = 0;
    1013           0 :     ctx->num_services = 0;
    1014           0 :     for (i = 0; ctx->services[i] != NULL; i++) {
    1015           0 :         ctx->num_services++;
    1016             :     }
    1017             : 
    1018           0 :     ret = get_service_user(ctx);
    1019           0 :     if (ret != EOK) {
    1020           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to get the unprivileged user\n");
    1021           0 :         return ret;
    1022             :     }
    1023             : 
    1024           0 :     ret = confdb_get_domains(ctx->cdb, &ctx->domains);
    1025           0 :     if (ret != EOK) {
    1026           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured.\n");
    1027           0 :         return ret;
    1028             :     }
    1029             : 
    1030           0 :     ret = check_local_domain_unique(ctx->domains);
    1031           0 :     if (ret != EOK) {
    1032           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "More than one local domain configured.\n");
    1033           0 :         return ret;
    1034             :     }
    1035             : 
    1036             :     /* Check UID/GID overlaps */
    1037           0 :     ret = check_domain_ranges(ctx->domains);
    1038           0 :     if (ret != EOK) {
    1039           0 :         return ret;
    1040             :     }
    1041             : 
    1042           0 :     return EOK;
    1043             : }
    1044             : 
    1045           0 : static errno_t get_ping_config(struct mt_ctx *ctx, const char *path,
    1046             :                                struct mt_svc *svc)
    1047             : {
    1048             :     errno_t ret;
    1049             : 
    1050           0 :     ret = confdb_get_int(ctx->cdb, path,
    1051             :                          CONFDB_DOMAIN_TIMEOUT,
    1052             :                          MONITOR_DEF_PING_TIME, &svc->ping_time);
    1053           0 :     if (ret != EOK) {
    1054           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1055             :                "Failed to get ping timeout for '%s'\n", svc->name);
    1056           0 :         return ret;
    1057             :     }
    1058             : 
    1059             :     /* 'timeout = 0' should be translated to the default */
    1060           0 :     if (svc->ping_time == 0) {
    1061           0 :         svc->ping_time = MONITOR_DEF_PING_TIME;
    1062             :     }
    1063             : 
    1064           0 :     DEBUG(SSSDBG_CONF_SETTINGS,
    1065             :           "Time between service pings for [%s]: [%d]\n",
    1066             :            svc->name, svc->ping_time);
    1067             : 
    1068           0 :     ret = confdb_get_int(ctx->cdb, path,
    1069             :                          CONFDB_SERVICE_FORCE_TIMEOUT,
    1070             :                          MONITOR_DEF_FORCE_TIME, &svc->kill_time);
    1071           0 :     if (ret != EOK) {
    1072           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1073             :               "Failed to get kill timeout for %s\n", svc->name);
    1074           0 :         return ret;
    1075             :     }
    1076             : 
    1077             :     /* 'force_timeout = 0' should be translated to the default */
    1078           0 :     if (svc->kill_time == 0) {
    1079           0 :         svc->kill_time = MONITOR_DEF_FORCE_TIME;
    1080             :     }
    1081             : 
    1082           0 :     DEBUG(SSSDBG_CONF_SETTINGS,
    1083             :           "Time between SIGTERM and SIGKILL for [%s]: [%d]\n",
    1084             :            svc->name, svc->kill_time);
    1085             : 
    1086           0 :     return EOK;
    1087             : }
    1088             : 
    1089             : /* This is a temporary function that returns false if the service
    1090             :  * being started was only tested when running as root.
    1091             :  */
    1092           0 : static bool svc_supported_as_nonroot(const char *svc_name)
    1093             : {
    1094           0 :     if ((strcmp(svc_name, "nss") == 0)
    1095           0 :         || (strcmp(svc_name, "pam") == 0)
    1096           0 :         || (strcmp(svc_name, "autofs") == 0)
    1097           0 :         || (strcmp(svc_name, "pac") == 0)
    1098           0 :         || (strcmp(svc_name, "sudo") == 0)
    1099           0 :         || (strcmp(svc_name, "ssh") == 0)) {
    1100           0 :         return true;
    1101             :     }
    1102           0 :     return false;
    1103             : }
    1104             : 
    1105           0 : static int get_service_config(struct mt_ctx *ctx, const char *name,
    1106             :                               struct mt_svc **svc_cfg)
    1107             : {
    1108             :     int ret;
    1109             :     char *path;
    1110             :     struct mt_svc *svc;
    1111           0 :     time_t now = time(NULL);
    1112           0 :     uid_t uid = 0;
    1113           0 :     gid_t gid = 0;
    1114             : 
    1115           0 :     *svc_cfg = NULL;
    1116             : 
    1117           0 :     svc = talloc_zero(ctx, struct mt_svc);
    1118           0 :     if (!svc) {
    1119           0 :         return ENOMEM;
    1120             :     }
    1121           0 :     svc->mt_ctx = ctx;
    1122           0 :     svc->type = MT_SVC_SERVICE;
    1123             : 
    1124           0 :     talloc_set_destructor((TALLOC_CTX *)svc, svc_destructor);
    1125             : 
    1126           0 :     svc->name = talloc_strdup(svc, name);
    1127           0 :     if (!svc->name) {
    1128           0 :         talloc_free(svc);
    1129           0 :         return ENOMEM;
    1130             :     }
    1131             : 
    1132           0 :     svc->identity = talloc_strdup(svc, name);
    1133           0 :     if (!svc->identity) {
    1134           0 :         talloc_free(svc);
    1135           0 :         return ENOMEM;
    1136             :     }
    1137             : 
    1138           0 :     path = talloc_asprintf(svc, CONFDB_SERVICE_PATH_TMPL, svc->name);
    1139           0 :     if (!path) {
    1140           0 :         talloc_free(svc);
    1141           0 :         return ENOMEM;
    1142             :     }
    1143             : 
    1144           0 :     ret = confdb_get_string(ctx->cdb, svc, path,
    1145             :                             CONFDB_SERVICE_COMMAND,
    1146             :                             NULL, &svc->command);
    1147           0 :     if (ret != EOK) {
    1148           0 :         DEBUG(SSSDBG_FATAL_FAILURE,"Failed to start service '%s'\n", svc->name);
    1149           0 :         talloc_free(svc);
    1150           0 :         return ret;
    1151             :     }
    1152             : 
    1153           0 :     if (svc_supported_as_nonroot(svc->name)) {
    1154           0 :         uid = ctx->uid;
    1155           0 :         gid = ctx->gid;
    1156             :     }
    1157             : 
    1158           0 :     if (!svc->command) {
    1159           0 :         svc->command = talloc_asprintf(
    1160             :             svc, "%s/sssd_%s", SSSD_LIBEXEC_PATH, svc->name
    1161             :         );
    1162           0 :         if (!svc->command) {
    1163           0 :             talloc_free(svc);
    1164           0 :             return ENOMEM;
    1165             :         }
    1166             : 
    1167           0 :         svc->command = talloc_asprintf_append(svc->command,
    1168             :                 " --uid %"SPRIuid" --gid %"SPRIgid,
    1169             :                 uid, gid);
    1170           0 :         if (!svc->command) {
    1171           0 :             talloc_free(svc);
    1172           0 :             return ENOMEM;
    1173             :         }
    1174             : 
    1175           0 :         if (cmdline_debug_level != SSSDBG_UNRESOLVED) {
    1176           0 :             svc->command = talloc_asprintf_append(
    1177             :                 svc->command, " -d %#.4x", cmdline_debug_level
    1178             :             );
    1179           0 :             if (!svc->command) {
    1180           0 :                 talloc_free(svc);
    1181           0 :                 return ENOMEM;
    1182             :             }
    1183             :         }
    1184             : 
    1185           0 :         if (cmdline_debug_timestamps != SSSDBG_TIMESTAMP_UNRESOLVED) {
    1186           0 :             svc->command = talloc_asprintf_append(
    1187             :                 svc->command, " --debug-timestamps=%d", cmdline_debug_timestamps
    1188             :             );
    1189           0 :             if (!svc->command) {
    1190           0 :                 talloc_free(svc);
    1191           0 :                 return ENOMEM;
    1192             :             }
    1193             :         }
    1194             : 
    1195           0 :         if (cmdline_debug_microseconds != SSSDBG_MICROSECONDS_UNRESOLVED) {
    1196           0 :             svc->command = talloc_asprintf_append(
    1197             :                 svc->command, " --debug-microseconds=%d",
    1198             :                 cmdline_debug_microseconds
    1199             :             );
    1200           0 :             if (!svc->command) {
    1201           0 :                 talloc_free(svc);
    1202           0 :                 return ENOMEM;
    1203             :             }
    1204             :         }
    1205             : 
    1206           0 :         if (debug_to_file) {
    1207           0 :             svc->command = talloc_strdup_append(
    1208             :                 svc->command, " --debug-to-files"
    1209             :             );
    1210           0 :             if (!svc->command) {
    1211           0 :                 talloc_free(svc);
    1212           0 :                 return ENOMEM;
    1213             :             }
    1214           0 :         } else if (ctx->is_daemon == false) {
    1215           0 :             svc->command = talloc_strdup_append(
    1216             :                 svc->command, " --debug-to-stderr"
    1217             :             );
    1218           0 :             if (!svc->command) {
    1219           0 :                 talloc_free(svc);
    1220           0 :                 return ENOMEM;
    1221             :             }
    1222             :         }
    1223             :     }
    1224             : 
    1225           0 :     ret = get_ping_config(ctx, path, svc);
    1226           0 :     if (ret != EOK) {
    1227           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1228             :               "Failed to get ping timeouts for %s\n", svc->name);
    1229           0 :         talloc_free(svc);
    1230           0 :         return ret;
    1231             :     }
    1232             : 
    1233           0 :     svc->last_restart = now;
    1234             : 
    1235           0 :     *svc_cfg = svc;
    1236           0 :     talloc_free(path);
    1237             : 
    1238           0 :     return EOK;
    1239             : }
    1240             : 
    1241           0 : static int add_new_service(struct mt_ctx *ctx,
    1242             :                            const char *name,
    1243             :                            int restarts)
    1244             : {
    1245             :     int ret;
    1246             :     struct mt_svc *svc;
    1247             : 
    1248           0 :     ret = get_service_config(ctx, name, &svc);
    1249           0 :     if (ret != EOK) {
    1250           0 :         return ret;
    1251             :     }
    1252           0 :     svc->restarts = restarts;
    1253             : 
    1254           0 :     ret = start_service(svc);
    1255           0 :     if (ret != EOK) {
    1256           0 :         DEBUG(SSSDBG_FATAL_FAILURE,"Failed to start service '%s'\n", svc->name);
    1257           0 :         talloc_free(svc);
    1258             :     }
    1259             : 
    1260           0 :     return ret;
    1261             : }
    1262             : 
    1263           0 : static int get_provider_config(struct mt_ctx *ctx, const char *name,
    1264             :                               struct mt_svc **svc_cfg)
    1265             : {
    1266             :     int ret;
    1267             :     char *path;
    1268             :     struct mt_svc *svc;
    1269           0 :     time_t now = time(NULL);
    1270             : 
    1271           0 :     *svc_cfg = NULL;
    1272             : 
    1273           0 :     svc = talloc_zero(ctx, struct mt_svc);
    1274           0 :     if (!svc) {
    1275           0 :         return ENOMEM;
    1276             :     }
    1277           0 :     svc->mt_ctx = ctx;
    1278           0 :     svc->type = MT_SVC_PROVIDER;
    1279             : 
    1280           0 :     talloc_set_destructor((TALLOC_CTX *)svc, svc_destructor);
    1281             : 
    1282           0 :     svc->name = talloc_strdup(svc, name);
    1283           0 :     if (!svc->name) {
    1284           0 :         talloc_free(svc);
    1285           0 :         return ENOMEM;
    1286             :     }
    1287             : 
    1288           0 :     svc->identity = talloc_asprintf(svc, "%%BE_%s", svc->name);
    1289           0 :     if (!svc->identity) {
    1290           0 :         talloc_free(svc);
    1291           0 :         return ENOMEM;
    1292             :     }
    1293             : 
    1294           0 :     path = talloc_asprintf(svc, CONFDB_DOMAIN_PATH_TMPL, name);
    1295           0 :     if (!path) {
    1296           0 :         talloc_free(svc);
    1297           0 :         return ENOMEM;
    1298             :     }
    1299             : 
    1300           0 :     ret = confdb_get_string(ctx->cdb, svc, path,
    1301             :                             CONFDB_DOMAIN_ID_PROVIDER,
    1302             :                             NULL, &svc->provider);
    1303           0 :     if (ret != EOK) {
    1304           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    1305             :               "Failed to find ID provider from [%s] configuration\n", name);
    1306           0 :         talloc_free(svc);
    1307           0 :         return ret;
    1308             :     }
    1309             : 
    1310           0 :     ret = confdb_get_string(ctx->cdb, svc, path,
    1311             :                             CONFDB_DOMAIN_COMMAND,
    1312             :                             NULL, &svc->command);
    1313           0 :     if (ret != EOK) {
    1314           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    1315             :               "Failed to find command from [%s] configuration\n", name);
    1316           0 :         talloc_free(svc);
    1317           0 :         return ret;
    1318             :     }
    1319             : 
    1320           0 :     ret = get_ping_config(ctx, path, svc);
    1321           0 :     if (ret != EOK) {
    1322           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1323             :               "Failed to get ping timeouts for %s\n", svc->name);
    1324           0 :         talloc_free(svc);
    1325           0 :         return ret;
    1326             :     }
    1327             : 
    1328           0 :     talloc_free(path);
    1329             : 
    1330             :     /* if no provider is present do not run the domain */
    1331           0 :     if (!svc->provider) {
    1332           0 :         talloc_free(svc);
    1333           0 :         return EIO;
    1334             :     }
    1335             : 
    1336             :     /* if there are no custom commands, build a default one */
    1337           0 :     if (!svc->command) {
    1338           0 :         svc->command = talloc_asprintf(
    1339             :             svc, "%s/sssd_be --domain %s", SSSD_LIBEXEC_PATH, svc->name
    1340             :         );
    1341           0 :         if (!svc->command) {
    1342           0 :             talloc_free(svc);
    1343           0 :             return ENOMEM;
    1344             :         }
    1345             : 
    1346           0 :         svc->command = talloc_asprintf_append(svc->command,
    1347             :                 " --uid %"SPRIuid" --gid %"SPRIgid,
    1348             :                 ctx->uid, ctx->gid);
    1349           0 :         if (!svc->command) {
    1350           0 :             talloc_free(svc);
    1351           0 :             return ENOMEM;
    1352             :         }
    1353             : 
    1354           0 :         if (cmdline_debug_level != SSSDBG_UNRESOLVED) {
    1355           0 :             svc->command = talloc_asprintf_append(
    1356             :                 svc->command, " -d %#.4x", cmdline_debug_level
    1357             :             );
    1358           0 :             if (!svc->command) {
    1359           0 :                 talloc_free(svc);
    1360           0 :                 return ENOMEM;
    1361             :             }
    1362             :         }
    1363             : 
    1364           0 :         if (cmdline_debug_timestamps != SSSDBG_TIMESTAMP_UNRESOLVED) {
    1365           0 :             svc->command = talloc_asprintf_append(
    1366             :                 svc->command, " --debug-timestamps=%d", cmdline_debug_timestamps
    1367             :             );
    1368           0 :             if (!svc->command) {
    1369           0 :                 talloc_free(svc);
    1370           0 :                 return ENOMEM;
    1371             :             }
    1372             :         }
    1373             : 
    1374           0 :         if (cmdline_debug_microseconds != SSSDBG_MICROSECONDS_UNRESOLVED) {
    1375           0 :             svc->command = talloc_asprintf_append(
    1376             :                 svc->command, " --debug-microseconds=%d",
    1377             :                 cmdline_debug_microseconds
    1378             :             );
    1379           0 :             if (!svc->command) {
    1380           0 :                 talloc_free(svc);
    1381           0 :                 return ENOMEM;
    1382             :             }
    1383             :         }
    1384             : 
    1385           0 :         if (debug_to_file) {
    1386           0 :             svc->command = talloc_strdup_append(
    1387             :                 svc->command, " --debug-to-files"
    1388             :             );
    1389           0 :             if (!svc->command) {
    1390           0 :                 talloc_free(svc);
    1391           0 :                 return ENOMEM;
    1392             :             }
    1393           0 :         } else if (ctx->is_daemon == false) {
    1394           0 :             svc->command = talloc_strdup_append(
    1395             :                 svc->command, " --debug-to-stderr"
    1396             :             );
    1397           0 :             if (!svc->command) {
    1398           0 :                 talloc_free(svc);
    1399           0 :                 return ENOMEM;
    1400             :             }
    1401             :         }
    1402             :     }
    1403             : 
    1404           0 :     svc->last_restart = now;
    1405             : 
    1406           0 :     *svc_cfg = svc;
    1407           0 :     return EOK;
    1408             : }
    1409             : 
    1410           0 : static int add_new_provider(struct mt_ctx *ctx,
    1411             :                             const char *name,
    1412             :                             int restarts)
    1413             : {
    1414             :     int ret;
    1415             :     struct mt_svc *svc;
    1416             : 
    1417           0 :     ret = get_provider_config(ctx, name, &svc);
    1418           0 :     if (ret != EOK) {
    1419           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    1420             :               "Could not get provider configuration for [%s]\n",
    1421             :                   name);
    1422           0 :         return ret;
    1423             :     }
    1424           0 :     svc->restarts = restarts;
    1425             : 
    1426           0 :     if (strcasecmp(svc->provider, "local") == 0) {
    1427             :         /* The LOCAL provider requires no back-end currently
    1428             :          * We'll add it to the service list, but we don't need
    1429             :          * to poll it.
    1430             :          */
    1431           0 :         svc->svc_started = true;
    1432           0 :         DLIST_ADD(ctx->svc_list, svc);
    1433           0 :         return ENOENT;
    1434             :     }
    1435             : 
    1436           0 :     ret = start_service(svc);
    1437           0 :     if (ret != EOK) {
    1438           0 :         DEBUG(SSSDBG_FATAL_FAILURE,"Failed to start service '%s'\n", svc->name);
    1439           0 :         talloc_free(svc);
    1440             :     }
    1441             : 
    1442           0 :     return ret;
    1443             : }
    1444             : 
    1445           0 : static void monitor_hup(struct tevent_context *ev,
    1446             :                         struct tevent_signal *se,
    1447             :                         int signum,
    1448             :                         int count,
    1449             :                         void *siginfo,
    1450             :                         void *private_data)
    1451             : {
    1452           0 :     struct mt_ctx *ctx = talloc_get_type(private_data, struct mt_ctx);
    1453             :     struct mt_svc *cur_svc;
    1454             : 
    1455           0 :     DEBUG(SSSDBG_CRIT_FAILURE, "Received SIGHUP.\n");
    1456             : 
    1457             :     /* Send D-Bus message to other services to rotate their logs.
    1458             :      * NSS service receives also message to clear memory caches. */
    1459           0 :     for(cur_svc = ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
    1460           0 :         service_signal_rotate(cur_svc);
    1461           0 :         if (!strcmp(NSS_SBUS_SERVICE_NAME, cur_svc->name)) {
    1462           0 :             service_signal_clear_memcache(cur_svc);
    1463           0 :             service_signal_clear_enum_cache(cur_svc);
    1464             :         }
    1465             : 
    1466           0 :         if (!strcmp(SSS_AUTOFS_SBUS_SERVICE_NAME, cur_svc->name)) {
    1467           0 :             service_signal_clear_enum_cache(cur_svc);
    1468             :         }
    1469             : 
    1470             :     }
    1471             : 
    1472           0 : }
    1473             : 
    1474           0 : static int monitor_cleanup(void)
    1475             : {
    1476             :     int ret;
    1477             : 
    1478           0 :     errno = 0;
    1479           0 :     ret = unlink(SSSD_PIDFILE_PATH);
    1480           0 :     if (ret == -1) {
    1481           0 :         ret = errno;
    1482           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    1483             :               "Error removing pidfile! (%d [%s])\n", ret, strerror(ret));
    1484           0 :         return ret;
    1485             :     }
    1486             : 
    1487           0 :     return EOK;
    1488             : }
    1489             : 
    1490           0 : static void monitor_quit(struct mt_ctx *mt_ctx, int ret)
    1491             : {
    1492             :     struct mt_svc *svc;
    1493             :     pid_t pid;
    1494             :     int status;
    1495             :     errno_t error;
    1496             :     int kret;
    1497             :     bool killed;
    1498             : 
    1499           0 :     DEBUG(SSSDBG_IMPORTANT_INFO, "Returned with: %d\n", ret);
    1500             : 
    1501             :     /* Kill all of our known children manually */
    1502           0 :     DLIST_FOR_EACH(svc, mt_ctx->svc_list) {
    1503           0 :         if (svc->pid == 0) {
    1504             :             /* The local provider has no PID */
    1505           0 :             continue;
    1506             :         }
    1507             : 
    1508           0 :         killed = false;
    1509           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1510             :               "Terminating [%s][%d]\n", svc->name, svc->pid);
    1511             :         do {
    1512           0 :             errno = 0;
    1513           0 :             kret = kill(svc->pid, SIGTERM);
    1514           0 :             if (kret < 0) {
    1515           0 :                 error = errno;
    1516           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't kill [%s][%d]: [%s]\n",
    1517             :                           svc->name, svc->pid, strerror(error));
    1518             :             }
    1519             : 
    1520           0 :             error = 0;
    1521             :             do {
    1522           0 :                 errno = 0;
    1523           0 :                 pid = waitpid(svc->pid, &status, WNOHANG);
    1524           0 :                 if (pid == -1) {
    1525             :                     /* An error occurred while waiting */
    1526           0 :                     error = errno;
    1527           0 :                     if (error == ECHILD) {
    1528           0 :                         killed = true;
    1529           0 :                     } else if (error != EINTR) {
    1530           0 :                         DEBUG(SSSDBG_FATAL_FAILURE,
    1531             :                               "[%d][%s] while waiting for [%s]\n",
    1532             :                                   error, strerror(error), svc->name);
    1533             :                         /* Forcibly kill this child */
    1534           0 :                         kill(svc->pid, SIGKILL);
    1535           0 :                         break;
    1536             :                     }
    1537           0 :                 } else if (pid != 0) {
    1538           0 :                     error = 0;
    1539           0 :                     if (WIFEXITED(status)) {
    1540           0 :                         DEBUG(SSSDBG_CRIT_FAILURE,
    1541             :                               "Child [%s] exited gracefully\n", svc->name);
    1542           0 :                     } else if (WIFSIGNALED(status)) {
    1543           0 :                         DEBUG(SSSDBG_CRIT_FAILURE,
    1544             :                               "Child [%s] terminated with a signal\n", svc->name);
    1545             :                     } else {
    1546           0 :                         DEBUG(SSSDBG_FATAL_FAILURE,
    1547             :                               "Child [%s] did not exit cleanly\n", svc->name);
    1548             :                         /* Forcibly kill this child */
    1549           0 :                         kill(svc->pid, SIGKILL);
    1550             :                     }
    1551           0 :                     killed = true;
    1552             :                 }
    1553           0 :             } while (error == EINTR);
    1554           0 :             if (!killed) {
    1555             :                 /* Sleep 10ms and try again */
    1556           0 :                 usleep(10000);
    1557             :             }
    1558           0 :         } while (!killed);
    1559             :     }
    1560             : 
    1561             : #if HAVE_GETPGRP
    1562             :     /* Kill any remaining children in our process group, just in case
    1563             :      * we have any leftover children we don't expect. For example, if
    1564             :      * a krb5_child or ldap_child is running at the same moment.
    1565             :      */
    1566           0 :     error = 0;
    1567           0 :     if (getpgrp() == getpid()) {
    1568           0 :         kill(-getpgrp(), SIGTERM);
    1569             :         do {
    1570           0 :             errno = 0;
    1571           0 :             pid = waitpid(0, &status, 0);
    1572           0 :             if (pid == -1) {
    1573           0 :                 error = errno;
    1574             :             }
    1575           0 :         } while (error == EINTR || pid > 0);
    1576             :     }
    1577             : #endif
    1578             : 
    1579           0 :     monitor_cleanup();
    1580             : 
    1581           0 :     exit(ret);
    1582             : }
    1583             : 
    1584           0 : static void monitor_quit_signal(struct tevent_context *ev,
    1585             :                                 struct tevent_signal *se,
    1586             :                                 int signum,
    1587             :                                 int count,
    1588             :                                 void *siginfo,
    1589             :                                 void *private_data)
    1590             : {
    1591           0 :     struct mt_ctx *mt_ctx = talloc_get_type(private_data, struct mt_ctx);
    1592             : 
    1593           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Received shutdown command\n");
    1594             : 
    1595           0 :     DEBUG(SSSDBG_IMPORTANT_INFO, "Monitor received %s: terminating "
    1596             :                                   "children\n", strsignal(signum));
    1597             : 
    1598           0 :     monitor_quit(mt_ctx, 0);
    1599           0 : }
    1600             : 
    1601           0 : static void signal_res_init(struct mt_ctx *monitor)
    1602             : {
    1603             :     struct mt_svc *cur_svc;
    1604             :     int ret;
    1605           0 :     DEBUG(SSSDBG_OP_FAILURE, "Reloading Resolv.conf.\n");
    1606             : 
    1607           0 :     ret = res_init();
    1608           0 :     if (ret == 0) {
    1609           0 :         for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
    1610           0 :             service_signal_dns_reload(cur_svc);
    1611             :         }
    1612             :     }
    1613           0 : }
    1614             : 
    1615           0 : static void signal_offline(struct tevent_context *ev,
    1616             :                            struct tevent_signal *se,
    1617             :                            int signum,
    1618             :                            int count,
    1619             :                            void *siginfo,
    1620             :                            void *private_data)
    1621             : {
    1622             :     struct mt_ctx *monitor;
    1623             :     struct mt_svc *cur_svc;
    1624             : 
    1625           0 :     monitor = talloc_get_type(private_data, struct mt_ctx);
    1626             : 
    1627           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
    1628             :          "Signaling providers to go offline immediately.\n");
    1629             : 
    1630             :     /* Signal all providers to immediately go offline */
    1631           0 :     for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
    1632             :         /* Don't signal services, only providers */
    1633           0 :         if (cur_svc->provider) {
    1634           0 :             service_signal_offline(cur_svc);
    1635             :         }
    1636             :     }
    1637           0 : }
    1638             : 
    1639           0 : static void signal_offline_reset(struct tevent_context *ev,
    1640             :                                  struct tevent_signal *se,
    1641             :                                  int signum,
    1642             :                                  int count,
    1643             :                                  void *siginfo,
    1644             :                                  void *private_data)
    1645             : {
    1646             :     struct mt_ctx *monitor;
    1647             :     struct mt_svc *cur_svc;
    1648             : 
    1649           0 :     monitor = talloc_get_type(private_data, struct mt_ctx);
    1650             : 
    1651           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
    1652             :          "Signaling providers to reset offline immediately.\n");
    1653             : 
    1654           0 :     for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
    1655           0 :         if (cur_svc->provider) {
    1656           0 :             service_signal_reset_offline(cur_svc);
    1657             :         }
    1658             : 
    1659           0 :         if (strcmp(SSS_IFP_SBUS_SERVICE_NAME, cur_svc->name) == 0) {
    1660           0 :             service_signal_sysbus_reconnect(cur_svc);
    1661             :         }
    1662             :     }
    1663           0 :     signal_res_init(monitor);
    1664           0 : }
    1665             : 
    1666           0 : static int monitor_ctx_destructor(void *mem)
    1667             : {
    1668           0 :     struct mt_ctx *mon = talloc_get_type(mem, struct mt_ctx);
    1669             :     struct mt_svc *svc;
    1670             : 
    1671             :     /* zero out references in svcs so that they don't try
    1672             :      * to access the monitor context on process shutdown */
    1673             : 
    1674           0 :     for (svc = mon->svc_list; svc; svc = svc->next) {
    1675           0 :         svc->mt_ctx = NULL;
    1676             :     }
    1677           0 :     return 0;
    1678             : }
    1679             : 
    1680             : /*
    1681             :  * This function should not be static otherwise gcc does some special kind of
    1682             :  * optimisations which should not happen according to code: chown (unlink)
    1683             :  * failed (return -1) but errno was zero.
    1684             :  * As a result of this  * warning is printed ‘monitor’ may be used
    1685             :  * uninitialized in this function. Instead of checking errno for 0
    1686             :  * it's better to disable optimisation(in-lining) of this function.
    1687             :  */
    1688           0 : errno_t load_configuration(TALLOC_CTX *mem_ctx,
    1689             :                            const char *config_file,
    1690             :                            struct mt_ctx **monitor)
    1691             : {
    1692             :     errno_t ret;
    1693             :     struct mt_ctx *ctx;
    1694           0 :     char *cdb_file = NULL;
    1695             : 
    1696           0 :     ctx = talloc_zero(mem_ctx, struct mt_ctx);
    1697           0 :     if(!ctx) {
    1698           0 :         return ENOMEM;
    1699             :     }
    1700             : 
    1701           0 :     talloc_set_destructor((TALLOC_CTX *)ctx, monitor_ctx_destructor);
    1702             : 
    1703           0 :     cdb_file = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
    1704           0 :     if (cdb_file == NULL) {
    1705           0 :         DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory, aborting!\n");
    1706           0 :         ret = ENOMEM;
    1707           0 :         goto done;
    1708             :     }
    1709             : 
    1710           0 :     ret = confdb_init(ctx, &ctx->cdb, cdb_file);
    1711           0 :     if (ret != EOK) {
    1712           0 :         DEBUG(SSSDBG_FATAL_FAILURE,"The confdb initialization failed\n");
    1713           0 :         goto done;
    1714             :     }
    1715             : 
    1716             :     /* Initialize the CDB from the configuration file */
    1717           0 :     ret = confdb_test(ctx->cdb);
    1718           0 :     if (ret == ENOENT) {
    1719             :         /* First-time setup */
    1720             : 
    1721             :         /* Purge any existing confdb in case an old
    1722             :          * misconfiguration gets in the way
    1723             :          */
    1724           0 :         talloc_zfree(ctx->cdb);
    1725           0 :         ret = unlink(cdb_file);
    1726           0 :         if (ret != EOK && errno != ENOENT) {
    1727           0 :             ret = errno;
    1728           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    1729             :                   "Purging existing confdb failed: %d [%s].\n",
    1730             :                   ret, sss_strerror(ret));
    1731           0 :             goto done;
    1732             :         }
    1733             : 
    1734           0 :         ret = confdb_init(ctx, &ctx->cdb, cdb_file);
    1735           0 :         if (ret != EOK) {
    1736           0 :             DEBUG(SSSDBG_FATAL_FAILURE,"The confdb initialization failed\n");
    1737           0 :             goto done;
    1738             :         }
    1739             : 
    1740             :         /* Load special entries */
    1741           0 :         ret = confdb_create_base(ctx->cdb);
    1742           0 :         if (ret != EOK) {
    1743           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    1744             :                   "Unable to load special entries into confdb\n");
    1745           0 :             goto done;
    1746             :         }
    1747           0 :     } else if (ret != EOK) {
    1748           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error initializing confdb\n");
    1749           0 :         goto done;
    1750             :     }
    1751             : 
    1752           0 :     ret = confdb_init_db(config_file, ctx->cdb);
    1753           0 :     if (ret != EOK) {
    1754           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "ConfDB initialization has failed [%s]\n",
    1755             :               sss_strerror(ret));
    1756           0 :         goto done;
    1757             :     }
    1758             : 
    1759             :     /* Validate the configuration in the database */
    1760             :     /* Read in the monitor's configuration */
    1761           0 :     ret = get_monitor_config(ctx);
    1762           0 :     if (ret != EOK) {
    1763           0 :         goto done;
    1764             :     }
    1765             : 
    1766             :     /* Allow configuration database to be accessible
    1767             :      * when SSSD runs as nonroot */
    1768           0 :     ret = chown(cdb_file, ctx->uid, ctx->gid);
    1769           0 :     if (ret != 0) {
    1770           0 :         ret = errno;
    1771           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    1772             :               "chown failed for [%s]: [%d][%s].\n",
    1773             :               cdb_file, ret, sss_strerror(ret));
    1774           0 :         goto done;
    1775             :     }
    1776             : 
    1777           0 :     *monitor = ctx;
    1778             : 
    1779           0 :     ret = EOK;
    1780             : 
    1781             : done:
    1782           0 :     talloc_free(cdb_file);
    1783           0 :     if (ret != EOK) {
    1784           0 :         talloc_free(ctx);
    1785             :     }
    1786           0 :     return ret;
    1787             : }
    1788             : 
    1789             : static errno_t monitor_config_file_fallback(TALLOC_CTX *mem_ctx,
    1790             :                                             struct mt_ctx *ctx,
    1791             :                                             const char *file,
    1792             :                                             monitor_reconf_fn fn,
    1793             :                                             bool ignore_missing);
    1794             : 
    1795             : #ifdef HAVE_INOTIFY
    1796             : static void process_config_file(struct tevent_context *ev,
    1797             :                                 struct tevent_timer *te,
    1798             :                                 struct timeval t, void *ptr);
    1799             : 
    1800           0 : static void config_file_changed(struct tevent_context *ev,
    1801             :                                 struct tevent_fd *fde,
    1802             :                                 uint16_t flags, void *data)
    1803             : {
    1804           0 :     struct tevent_timer *te = NULL;
    1805             :     struct timeval tv;
    1806             :     struct config_file_ctx *file_ctx;
    1807             : 
    1808           0 :     file_ctx = talloc_get_type(data, struct config_file_ctx);
    1809           0 :     if (file_ctx->needs_update) {
    1810             :         /* Skip updating. It's already queued for update.
    1811             :          */
    1812           0 :         return;
    1813             :     }
    1814             : 
    1815             :     /* We will queue the file for update in one second.
    1816             :      * This way, if there is a script writing to the file
    1817             :      * repeatedly, we won't be attempting to update multiple
    1818             :      * times.
    1819             :      */
    1820           0 :     gettimeofday(&tv, NULL);
    1821           0 :     tv.tv_sec += 1;
    1822             : 
    1823           0 :     te = tevent_add_timer(ev, ev, tv, process_config_file, file_ctx);
    1824           0 :     if (!te) {
    1825           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    1826             :               "Unable to queue config file update! Exiting.\n");
    1827           0 :         kill(getpid(), SIGTERM);
    1828           0 :         return;
    1829             :     }
    1830           0 :     file_ctx->needs_update = 1;
    1831             : }
    1832             : 
    1833             : struct rewatch_ctx {
    1834             :     struct config_file_callback *cb;
    1835             :     struct config_file_ctx *file_ctx;
    1836             : };
    1837             : static void rewatch_config_file(struct tevent_context *ev,
    1838             :                                 struct tevent_timer *te,
    1839             :                                 struct timeval t, void *ptr);
    1840           0 : static void process_config_file(struct tevent_context *ev,
    1841             :                                 struct tevent_timer *te,
    1842             :                                 struct timeval t, void *ptr)
    1843             : {
    1844             :     TALLOC_CTX *tmp_ctx;
    1845             :     struct inotify_event *in_event;
    1846             :     char *name;
    1847             :     ssize_t len;
    1848             :     struct config_file_ctx *file_ctx;
    1849             :     struct config_file_callback *cb;
    1850             :     struct rewatch_ctx *rw_ctx;
    1851             :     errno_t ret;
    1852             : 
    1853           0 :     file_ctx = talloc_get_type(ptr, struct config_file_ctx);
    1854             : 
    1855           0 :     DEBUG(SSSDBG_CRIT_FAILURE, "Processing config file changes\n");
    1856             : 
    1857           0 :     tmp_ctx = talloc_new(NULL);
    1858           0 :     if (!tmp_ctx) return;
    1859             : 
    1860           0 :     in_event = talloc(tmp_ctx, struct inotify_event);
    1861           0 :     if (!in_event) {
    1862           0 :         goto done;
    1863             :     }
    1864             : 
    1865           0 :     errno = 0;
    1866           0 :     len = sss_atomic_read_s(file_ctx->mt_ctx->inotify_fd, in_event,
    1867             :                             sizeof(struct inotify_event));
    1868           0 :     if (len == -1) {
    1869           0 :         ret = errno;
    1870           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1871             :               "Critical error reading inotify file descriptor [%d]: %s\n",
    1872             :                ret, strerror(ret));
    1873           0 :         goto done;
    1874             :     }
    1875             : 
    1876           0 :     if (in_event->len > 0) {
    1877             :         /* Read in the name, even though we don't use it,
    1878             :          * so that read ptr is in the right place
    1879             :          */
    1880           0 :         name = talloc_size(tmp_ctx, in_event->len);
    1881           0 :         if (!name) {
    1882           0 :             goto done;
    1883             :         }
    1884             : 
    1885           0 :         errno = 0;
    1886           0 :         len = sss_atomic_read_s(file_ctx->mt_ctx->inotify_fd, name, in_event->len);
    1887           0 :         if (len == -1) {
    1888           0 :             ret = errno;
    1889           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1890             :                 "Critical error reading inotify file descriptor [%d]: %s\n",
    1891             :                 ret, strerror(ret));
    1892           0 :             goto done;
    1893             :         }
    1894             :     }
    1895             : 
    1896           0 :     for (cb = file_ctx->callbacks; cb; cb = cb->next) {
    1897           0 :         if (cb->wd == in_event->wd) {
    1898           0 :             break;
    1899             :         }
    1900             :     }
    1901           0 :     if (!cb) {
    1902           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Unknown watch descriptor\n");
    1903           0 :         goto done;
    1904             :     }
    1905             : 
    1906           0 :     if (in_event->mask & IN_IGNORED) {
    1907             :         /* Some text editors will move a new file on top of the
    1908             :          * existing one instead of modifying it. In this case,
    1909             :          * the kernel will send us an IN_IGNORE signal.
    1910             :          * We will try to open a new watch descriptor on the
    1911             :          * new file.
    1912             :          */
    1913             :         struct timeval tv;
    1914             :         struct tevent_timer *tev;
    1915           0 :         tv.tv_sec = t.tv_sec+5;
    1916           0 :         tv.tv_usec = t.tv_usec;
    1917           0 :         DEBUG(SSSDBG_FUNC_DATA, "Restoring inotify watch.\n");
    1918             : 
    1919           0 :         cb->retries = 0;
    1920           0 :         rw_ctx = talloc(file_ctx, struct rewatch_ctx);
    1921           0 :         if(!rw_ctx) {
    1922           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    1923             :                   "Could not restore inotify watch. Quitting!\n");
    1924           0 :             close(file_ctx->mt_ctx->inotify_fd);
    1925           0 :             kill(getpid(), SIGTERM);
    1926           0 :             goto done;
    1927             :         }
    1928           0 :         rw_ctx->cb = cb;
    1929           0 :         rw_ctx->file_ctx = file_ctx;
    1930             : 
    1931           0 :         tev = tevent_add_timer(ev, rw_ctx, tv, rewatch_config_file, rw_ctx);
    1932           0 :         if (tev == NULL) {
    1933           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    1934             :                   "Could not restore inotify watch. Quitting!\n");
    1935           0 :             close(file_ctx->mt_ctx->inotify_fd);
    1936           0 :             kill(getpid(), SIGTERM);
    1937             :         }
    1938           0 :         goto done;
    1939             :     }
    1940             : 
    1941             :     /* Tell the monitor to signal the children */
    1942           0 :     cb->fn(file_ctx, cb->filename);
    1943           0 :     file_ctx->needs_update = 0;
    1944             : 
    1945             : done:
    1946           0 :     talloc_free(tmp_ctx);
    1947             : }
    1948             : 
    1949           0 : static void rewatch_config_file(struct tevent_context *ev,
    1950             :                                 struct tevent_timer *te,
    1951             :                                 struct timeval t, void *ptr)
    1952             : {
    1953             :     int err;
    1954           0 :     struct tevent_timer *tev = NULL;
    1955             :     struct timeval tv;
    1956             :     struct config_file_callback *cb;
    1957             : 
    1958             :     struct rewatch_ctx *rw_ctx;
    1959             :     struct config_file_ctx *file_ctx;
    1960             : 
    1961           0 :     rw_ctx = talloc_get_type(ptr, struct rewatch_ctx);
    1962             : 
    1963           0 :     cb = rw_ctx->cb;
    1964           0 :     file_ctx = rw_ctx->file_ctx;
    1965             : 
    1966             :     /* Retry six times at five-second intervals before giving up */
    1967           0 :     cb->retries++;
    1968           0 :     if (cb->retries > 6) {
    1969           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    1970             :              "Could not restore inotify watch. Switching to polling!\n");
    1971           0 :         close(file_ctx->mt_ctx->inotify_fd);
    1972           0 :         err = monitor_config_file_fallback(file_ctx->parent_ctx,
    1973             :                                            file_ctx->mt_ctx,
    1974           0 :                                            cb->filename,
    1975             :                                            cb->fn,true);
    1976           0 :         if (err != EOK)
    1977           0 :             kill(getpid(), SIGTERM);
    1978             : 
    1979           0 :         cb->fn(file_ctx, cb->filename);
    1980           0 :         talloc_free(rw_ctx);
    1981             : 
    1982             :         /* A new callback was created in monitor_config_file_fallback()*/
    1983           0 :         DLIST_REMOVE(file_ctx->callbacks, cb);
    1984           0 :         talloc_free(cb);
    1985             : 
    1986           0 :         return;
    1987             :     }
    1988             : 
    1989           0 :     cb->wd = inotify_add_watch(file_ctx->mt_ctx->inotify_fd,
    1990           0 :                                cb->filename, IN_MODIFY);
    1991           0 :     if (cb->wd < 0) {
    1992           0 :         err = errno;
    1993             : 
    1994           0 :         tv.tv_sec = t.tv_sec+5;
    1995           0 :         tv.tv_usec = t.tv_usec;
    1996             : 
    1997           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1998             :              "Could not add inotify watch for file [%s]. Error [%d:%s]\n",
    1999             :              cb->filename, err, strerror(err));
    2000             : 
    2001           0 :         tev = tevent_add_timer(ev, ev, tv, rewatch_config_file, rw_ctx);
    2002           0 :         if (tev == NULL) {
    2003           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    2004             :                  "Could not restore inotify watch. Quitting!\n");
    2005           0 :             close(file_ctx->mt_ctx->inotify_fd);
    2006           0 :             kill(getpid(), SIGTERM);
    2007             :         }
    2008             : 
    2009           0 :         return;
    2010             :     }
    2011           0 :     cb->retries = 0;
    2012             : 
    2013             :     /* Tell the monitor to signal the children */
    2014           0 :     cb->fn(file_ctx, cb->filename);
    2015             : 
    2016           0 :     talloc_free(rw_ctx);
    2017           0 :     file_ctx->needs_update = 0;
    2018             : }
    2019             : #endif /* HAVE_INOTIFY */
    2020             : 
    2021           0 : static void poll_config_file(struct tevent_context *ev,
    2022             :                                     struct tevent_timer *te,
    2023             :                                     struct timeval t, void *ptr)
    2024             : {
    2025             :     int ret, err;
    2026             :     struct stat file_stat;
    2027             :     struct timeval tv;
    2028             :     struct config_file_ctx *file_ctx;
    2029             :     struct config_file_callback *cb;
    2030             : 
    2031           0 :     file_ctx = talloc_get_type(ptr,struct config_file_ctx);
    2032             : 
    2033           0 :     for (cb = file_ctx->callbacks; cb; cb = cb->next) {
    2034           0 :         ret = stat(cb->filename, &file_stat);
    2035           0 :         if (ret < 0) {
    2036           0 :             err = errno;
    2037           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    2038             :                   "Could not stat file [%s]. Error [%d:%s]\n",
    2039             :                       cb->filename, err, strerror(err));
    2040             :             /* TODO: If the config file is missing, should we shut down? */
    2041           0 :             return;
    2042             :         }
    2043             : 
    2044           0 :         if (file_stat.st_mtime != cb->modified) {
    2045             :             /* Parse the configuration file and signal the children */
    2046             :             /* Note: this will fire if the modification time changes into the past
    2047             :              * as well as the future.
    2048             :              */
    2049           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Config file changed\n");
    2050           0 :             cb->modified = file_stat.st_mtime;
    2051             : 
    2052             :             /* Tell the monitor to signal the children */
    2053           0 :             cb->fn(file_ctx, cb->filename);
    2054             :         }
    2055             :     }
    2056             : 
    2057           0 :     gettimeofday(&tv, NULL);
    2058           0 :     tv.tv_sec += CONFIG_FILE_POLL_INTERVAL;
    2059           0 :     tv.tv_usec = 0;
    2060           0 :     file_ctx->timer = tevent_add_timer(ev, file_ctx->parent_ctx, tv,
    2061             :                              poll_config_file, file_ctx);
    2062           0 :     if (!file_ctx->timer) {
    2063           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2064             :               "Error: Config file no longer monitored for changes!\n");
    2065             :     }
    2066             : }
    2067             : 
    2068           0 : static int try_inotify(struct config_file_ctx *file_ctx, const char *filename,
    2069             :                        monitor_reconf_fn fn)
    2070             : {
    2071             : #ifdef HAVE_INOTIFY
    2072             :     int err, fd_args, ret;
    2073             :     struct tevent_fd *tfd;
    2074             :     struct config_file_callback *cb;
    2075             : 
    2076             :     /* Monitoring the file descriptor should be global */
    2077           0 :     if (!file_ctx->mt_ctx->inotify_fd) {
    2078             :         /* Set up inotify to monitor the config file for changes */
    2079           0 :         file_ctx->mt_ctx->inotify_fd = inotify_init();
    2080           0 :         if (file_ctx->mt_ctx->inotify_fd < 0) {
    2081           0 :             err = errno;
    2082           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    2083             :                   "Could not initialize inotify, error [%d:%s]\n",
    2084             :                       err, strerror(err));
    2085           0 :             return err;
    2086             :         }
    2087             : 
    2088           0 :         fd_args = fcntl(file_ctx->mt_ctx->inotify_fd, F_GETFL, NULL);
    2089           0 :         if (fd_args < 0) {
    2090             :             /* Could not set nonblocking */
    2091           0 :             close(file_ctx->mt_ctx->inotify_fd);
    2092           0 :             return EINVAL;
    2093             :         }
    2094             : 
    2095           0 :         fd_args |= O_NONBLOCK;
    2096           0 :         ret = fcntl(file_ctx->mt_ctx->inotify_fd, F_SETFL, fd_args);
    2097           0 :         if (ret < 0) {
    2098             :             /* Could not set nonblocking */
    2099           0 :             close(file_ctx->mt_ctx->inotify_fd);
    2100           0 :             return EINVAL;
    2101             :         }
    2102             : 
    2103             :         /* Add the inotify file descriptor to the TEvent context */
    2104           0 :         tfd = tevent_add_fd(file_ctx->mt_ctx->ev, file_ctx,
    2105             :                             file_ctx->mt_ctx->inotify_fd,
    2106             :                             TEVENT_FD_READ, config_file_changed,
    2107             :                             file_ctx);
    2108           0 :         if (!tfd) {
    2109           0 :             close(file_ctx->mt_ctx->inotify_fd);
    2110           0 :             return EIO;
    2111             :         }
    2112             :     }
    2113             : 
    2114           0 :     cb = talloc_zero(file_ctx, struct config_file_callback);
    2115           0 :     if(!cb) {
    2116           0 :         close(file_ctx->mt_ctx->inotify_fd);
    2117           0 :         return ENOMEM;
    2118             :     }
    2119             : 
    2120           0 :     cb->filename = talloc_strdup(cb, filename);
    2121           0 :     if (!cb->filename) {
    2122           0 :         close(file_ctx->mt_ctx->inotify_fd);
    2123           0 :         return ENOMEM;
    2124             :     }
    2125           0 :     cb->wd = inotify_add_watch(file_ctx->mt_ctx->inotify_fd,
    2126           0 :                                cb->filename, IN_MODIFY);
    2127           0 :     if (cb->wd < 0) {
    2128           0 :         err = errno;
    2129           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2130             :               "Could not add inotify watch for file [%s]. Error [%d:%s]\n",
    2131             :                   cb->filename, err, strerror(err));
    2132           0 :         close(file_ctx->mt_ctx->inotify_fd);
    2133           0 :         return err;
    2134             :     }
    2135           0 :     cb->fn = fn;
    2136             : 
    2137           0 :     DLIST_ADD(file_ctx->callbacks, cb);
    2138             : 
    2139           0 :     return EOK;
    2140             : #else
    2141             :     return EINVAL;
    2142             : #endif /* HAVE_INOTIFY */
    2143             : }
    2144             : 
    2145           0 : static int monitor_config_file(TALLOC_CTX *mem_ctx,
    2146             :                                struct mt_ctx *ctx,
    2147             :                                const char *file,
    2148             :                                monitor_reconf_fn fn,
    2149             :                                bool ignore_missing)
    2150             : {
    2151             :     int ret, err;
    2152             :     bool use_inotify;
    2153             :     struct stat file_stat;
    2154             : 
    2155           0 :     ret = stat(file, &file_stat);
    2156           0 :     if (ret < 0) {
    2157           0 :         err = errno;
    2158           0 :         if (err == ENOENT && ignore_missing) {
    2159           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    2160             :                   "file [%s] is missing. Will not update online status "
    2161             :                   "based on watching the file\n", file);
    2162           0 :             return EOK;
    2163             :         } else {
    2164           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    2165             :                   "Could not stat file [%s]. Error [%d:%s]\n",
    2166             :                   file, err, strerror(err));
    2167             : 
    2168           0 :             return err;
    2169             :         }
    2170             :     }
    2171           0 :     if (!ctx->file_ctx) {
    2172           0 :         ctx->file_ctx = talloc_zero(mem_ctx, struct config_file_ctx);
    2173           0 :         if (!ctx->file_ctx) return ENOMEM;
    2174             : 
    2175           0 :         ctx->file_ctx->parent_ctx = mem_ctx;
    2176           0 :         ctx->file_ctx->mt_ctx = ctx;
    2177             :     }
    2178             : 
    2179           0 :     ret = confdb_get_bool(ctx->cdb,
    2180             :                           CONFDB_MONITOR_CONF_ENTRY,
    2181             :                           CONFDB_MONITOR_TRY_INOTIFY,
    2182             :                           true, &use_inotify);
    2183           0 :     if (ret != EOK) {
    2184           0 :         talloc_free(ctx->file_ctx);
    2185           0 :         return ret;
    2186             :     }
    2187             : 
    2188           0 :     if (use_inotify) {
    2189           0 :         ret = try_inotify(ctx->file_ctx, file, fn);
    2190           0 :         if (ret != EOK) {
    2191           0 :             use_inotify = false;
    2192             :         }
    2193             :     }
    2194             : 
    2195           0 :     if (!use_inotify) {
    2196             :         /* Could not monitor file with inotify, fall back to polling */
    2197           0 :         ret = monitor_config_file_fallback(mem_ctx, ctx, file, fn, true);
    2198             :     }
    2199             : 
    2200           0 :     return ret;
    2201             : }
    2202             : 
    2203           0 : static errno_t monitor_config_file_fallback(TALLOC_CTX *mem_ctx,
    2204             :                                             struct mt_ctx *ctx,
    2205             :                                             const char *file,
    2206             :                                             monitor_reconf_fn fn,
    2207             :                                             bool ignore_missing)
    2208             : {
    2209           0 :     struct config_file_callback *cb = NULL;
    2210             :     struct stat file_stat;
    2211             :     int ret, err;
    2212             :     struct timeval tv;
    2213             : 
    2214           0 :     ret = stat(file, &file_stat);
    2215           0 :     if (ret < 0) {
    2216           0 :         err = errno;
    2217           0 :         if (err == ENOENT && ignore_missing) {
    2218           0 :              DEBUG(SSSDBG_MINOR_FAILURE,
    2219             :                      "file [%s] is missing. Will not update online status "
    2220             :                       "based on watching the file\n", file);
    2221           0 :              return EOK;
    2222             : 
    2223             :         } else {
    2224           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    2225             :                  "Could not stat file [%s]. Error [%d:%s]\n",
    2226             :                  file, err, strerror(err));
    2227             : 
    2228           0 :             return err;
    2229             :         }
    2230             :     }
    2231             : 
    2232           0 :     cb = talloc_zero(ctx->file_ctx, struct config_file_callback);
    2233           0 :     if (!cb) {
    2234           0 :         talloc_free(ctx->file_ctx);
    2235           0 :         return ENOMEM;
    2236             :     }
    2237           0 :     cb->filename = talloc_strdup(cb, file);
    2238           0 :     if (!cb->filename) {
    2239           0 :         talloc_free(ctx->file_ctx);
    2240           0 :         return ENOMEM;
    2241             :     }
    2242           0 :     cb->fn = fn;
    2243           0 :     cb->modified = file_stat.st_mtime;
    2244             : 
    2245           0 :     DLIST_ADD(ctx->file_ctx->callbacks, cb);
    2246             : 
    2247           0 :     if(!ctx->file_ctx->timer) {
    2248           0 :         gettimeofday(&tv, NULL);
    2249           0 :         tv.tv_sec += CONFIG_FILE_POLL_INTERVAL;
    2250           0 :         tv.tv_usec = 0;
    2251           0 :         ctx->file_ctx->timer = tevent_add_timer(ctx->ev, mem_ctx, tv,
    2252             :                 poll_config_file, ctx->file_ctx);
    2253           0 :         if (!ctx->file_ctx->timer) {
    2254           0 :             talloc_free(ctx->file_ctx);
    2255           0 :             return EIO;
    2256             :         }
    2257             :     }
    2258             : 
    2259           0 :     return EOK;
    2260             : }
    2261             : 
    2262             : #define MISSING_RESOLV_CONF_POLL_TIME 10
    2263             : 
    2264           0 : static void missing_resolv_conf(struct tevent_context *ev,
    2265             :                                 struct tevent_timer *te,
    2266             :                                 struct timeval tv, void *data)
    2267             : {
    2268             :     int ret;
    2269           0 :     struct mt_ctx *ctx = talloc_get_type(data, struct mt_ctx);
    2270             : 
    2271           0 :     ret = monitor_config_file(ctx, ctx, RESOLV_CONF_PATH,
    2272             :                               monitor_update_resolv, false);
    2273           0 :     if (ret == EOK) {
    2274           0 :         signal_res_init(ctx);
    2275           0 :     } else if (ret == ENOENT) {
    2276           0 :         tv = tevent_timeval_current_ofs(MISSING_RESOLV_CONF_POLL_TIME, 0);
    2277           0 :         te = tevent_add_timer(ctx->ev, ctx, tv, missing_resolv_conf, ctx);
    2278           0 :         if (te == NULL) {
    2279           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    2280             :                   "tevent_add_timer failed. resolv.conf will be ignored.\n");
    2281             :         }
    2282             :     } else {
    2283           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2284             :               "Monitor_config_file failed. resolv.conf will be ignored.\n");
    2285             :     }
    2286           0 : }
    2287             : 
    2288           0 : static int monitor_process_init(struct mt_ctx *ctx,
    2289             :                                 const char *config_file)
    2290             : {
    2291             :     TALLOC_CTX *tmp_ctx;
    2292             :     struct tevent_signal *tes;
    2293             :     struct timeval tv;
    2294             :     struct tevent_timer *te;
    2295             :     struct sss_domain_info *dom;
    2296             :     char *rcachedir;
    2297             :     int num_providers;
    2298             :     int ret;
    2299             :     int error;
    2300             : 
    2301             :     /* Set up the environment variable for the Kerberos Replay Cache */
    2302           0 :     ret = confdb_get_string(ctx->cdb, ctx,
    2303             :                             CONFDB_MONITOR_CONF_ENTRY,
    2304             :                             CONFDB_MONITOR_KRB5_RCACHEDIR,
    2305             :                             KRB5_RCACHE_DIR,
    2306             :                             &rcachedir);
    2307           0 :     if (ret != EOK) {
    2308           0 :         return ret;
    2309             :     }
    2310             : 
    2311           0 :     if (strcmp(rcachedir, KRB5_RCACHE_DIR_DISABLE) != 0)
    2312             :     {
    2313           0 :         errno = 0;
    2314           0 :         ret = setenv("KRB5RCACHEDIR", rcachedir, 1);
    2315           0 :         if (ret < 0) {
    2316           0 :             error = errno;
    2317           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    2318             :                   "Unable to set KRB5RCACHEDIR: %s."
    2319             :                    "Will attempt to use libkrb5 defaults\n",
    2320             :                    strerror(error));
    2321             :         }
    2322           0 :         talloc_zfree(rcachedir);
    2323             :     }
    2324             : 
    2325             :     /* Set up an event handler for a SIGHUP */
    2326           0 :     tes = tevent_add_signal(ctx->ev, ctx, SIGHUP, 0,
    2327             :                             monitor_hup, ctx);
    2328           0 :     if (tes == NULL) {
    2329           0 :         return EIO;
    2330             :     }
    2331             : 
    2332             :     /* Set up an event handler for a SIGINT */
    2333           0 :     BlockSignals(false, SIGINT);
    2334           0 :     tes = tevent_add_signal(ctx->ev, ctx, SIGINT, 0,
    2335             :                             monitor_quit_signal, ctx);
    2336           0 :     if (tes == NULL) {
    2337           0 :         return EIO;
    2338             :     }
    2339             : 
    2340             :     /* Set up an event handler for a SIGTERM */
    2341           0 :     tes = tevent_add_signal(ctx->ev, ctx, SIGTERM, 0,
    2342             :                             monitor_quit_signal, ctx);
    2343           0 :     if (tes == NULL) {
    2344           0 :         return EIO;
    2345             :     }
    2346             : 
    2347             :     /* Handle SIGUSR1 (tell all providers to go offline) */
    2348           0 :     BlockSignals(false, SIGUSR1);
    2349           0 :     tes = tevent_add_signal(ctx->ev, ctx, SIGUSR1, 0,
    2350             :                             signal_offline, ctx);
    2351           0 :     if (tes == NULL) {
    2352           0 :         return EIO;
    2353             :     }
    2354             : 
    2355             :     /* Handle SIGUSR2 (tell all providers to go reset offline) */
    2356           0 :     BlockSignals(false, SIGUSR2);
    2357           0 :     tes = tevent_add_signal(ctx->ev, ctx, SIGUSR2, 0,
    2358             :                             signal_offline_reset, ctx);
    2359           0 :     if (tes == NULL) {
    2360           0 :         return EIO;
    2361             :     }
    2362             : 
    2363             :     /* Set up the SIGCHLD handler */
    2364           0 :     ret = sss_sigchld_init(ctx, ctx->ev, &ctx->sigchld_ctx);
    2365           0 :     if (ret != EOK) return ret;
    2366             : 
    2367             : #if 0
    2368             :     This feature is incomplete and can leave the SSSD in a bad state if the
    2369             :     config file is changed while the SSSD is running.
    2370             : 
    2371             :     Uncomment this once the backends are honoring reloadConfig()
    2372             : 
    2373             :     /* Watch for changes to the confdb config file */
    2374             :     ret = monitor_config_file(ctx, ctx, config_file, monitor_signal_reconf,
    2375             :                               true);
    2376             :     if (ret != EOK) {
    2377             :         return ret;
    2378             :     }
    2379             : #endif
    2380             :     /* Watch for changes to the DNS resolv.conf */
    2381           0 :     ret = monitor_config_file(ctx, ctx, RESOLV_CONF_PATH,
    2382             :                               monitor_update_resolv, false);
    2383           0 :     if (ret == ENOENT) {
    2384           0 :         tv = tevent_timeval_current_ofs(MISSING_RESOLV_CONF_POLL_TIME, 0);
    2385           0 :         te = tevent_add_timer(ctx->ev, ctx, tv, missing_resolv_conf, ctx);
    2386           0 :         if (te == NULL) {
    2387           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "resolv.conf will be ignored\n");
    2388             :         }
    2389           0 :     } else if (ret != EOK) {
    2390           0 :         return ret;
    2391             :     }
    2392             : 
    2393             :     /* Avoid a startup race condition between process.
    2394             :      * We need to handle DB upgrades or DB creation only
    2395             :      * in one process before all other start.
    2396             :      */
    2397           0 :     tmp_ctx = talloc_new(NULL);
    2398           0 :     if (!tmp_ctx) {
    2399           0 :         return ENOMEM;
    2400             :     }
    2401           0 :     ret = sysdb_init_ext(tmp_ctx, ctx->domains, true,
    2402             :                          true, ctx->uid, ctx->gid);
    2403           0 :     if (ret != EOK) {
    2404           0 :         SYSDB_VERSION_ERROR_DAEMON(ret);
    2405           0 :         return ret;
    2406             :     }
    2407           0 :     talloc_zfree(tmp_ctx);
    2408             : 
    2409             :     /* Initialize D-BUS Server
    2410             :      * The monitor will act as a D-BUS server for all
    2411             :      * SSSD processes */
    2412           0 :     ret = monitor_dbus_init(ctx);
    2413           0 :     if (ret != EOK) {
    2414           0 :         return ret;
    2415             :     }
    2416             : 
    2417           0 :     ret = setup_netlink(ctx, ctx->ev, network_status_change_cb,
    2418             :                         ctx, &ctx->nlctx);
    2419           0 :     if (ret != EOK) {
    2420           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2421             :               "Cannot set up listening for network notifications\n");
    2422           0 :         return ret;
    2423             :     }
    2424             : 
    2425             :     /* start providers */
    2426           0 :     num_providers = 0;
    2427           0 :     for (dom = ctx->domains; dom; dom = get_next_domain(dom, false)) {
    2428           0 :         ret = add_new_provider(ctx, dom->name, 0);
    2429           0 :         if (ret != EOK && ret != ENOENT) {
    2430           0 :             return ret;
    2431             :         }
    2432           0 :         if (ret != ENOENT) {
    2433           0 :             num_providers++;
    2434             :         }
    2435             :     }
    2436             : 
    2437           0 :     if (num_providers > 0) {
    2438             :         /* now set the services stratup timeout *
    2439             :          * (responders will be started automatically when all
    2440             :          *  providers are up and running or when the tomeout
    2441             :          *  expires) */
    2442           0 :         ret = add_services_startup_timeout(ctx);
    2443           0 :         if (ret != EOK) {
    2444           0 :             return ret;
    2445             :         }
    2446             :     } else {
    2447             :         int i;
    2448             : 
    2449           0 :         ctx->services_started = true;
    2450             : 
    2451             :         /* No providers start services immediately
    2452             :          * Normally this means only LOCAL is configured */
    2453           0 :         for (i = 0; ctx->services[i]; i++) {
    2454           0 :             add_new_service(ctx, ctx->services[i], 0);
    2455             :         }
    2456             :     }
    2457             : 
    2458           0 :     return EOK;
    2459             : }
    2460             : 
    2461           0 : static void init_timeout(struct tevent_context *ev,
    2462             :                          struct tevent_timer *te,
    2463             :                          struct timeval t, void *ptr)
    2464             : {
    2465             :     struct mon_init_conn *mini;
    2466             : 
    2467           0 :     DEBUG(SSSDBG_OP_FAILURE, "Client timed out before Identification!\n");
    2468             : 
    2469           0 :     mini = talloc_get_type(ptr, struct mon_init_conn);
    2470             : 
    2471           0 :     sbus_disconnect(mini->conn);
    2472           0 :     talloc_zfree(mini);
    2473           0 : }
    2474             : 
    2475             : /*
    2476             :  * monitor_service_init
    2477             :  * Set up a timeout function and temporary connection structure.
    2478             :  * If the client does not identify before the timeout kicks in,
    2479             :  * the client is forcibly disconnected.
    2480             :  */
    2481           0 : static int monitor_service_init(struct sbus_connection *conn, void *data)
    2482             : {
    2483             :     struct mt_ctx *ctx;
    2484             :     struct mon_init_conn *mini;
    2485             :     struct timeval tv;
    2486             : 
    2487           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Initializing D-BUS Service\n");
    2488             : 
    2489           0 :     ctx = talloc_get_type(data, struct mt_ctx);
    2490             : 
    2491           0 :     mini = talloc(conn, struct mon_init_conn);
    2492           0 :     if (!mini) {
    2493           0 :         DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
    2494           0 :         talloc_zfree(conn);
    2495           0 :         return ENOMEM;
    2496             :     }
    2497           0 :     mini->ctx = ctx;
    2498           0 :     mini->conn = conn;
    2499             : 
    2500             :     /* Allow access from the SSSD user */
    2501           0 :     sbus_allow_uid(conn, &ctx->uid);
    2502             : 
    2503             :     /* 10 seconds should be plenty */
    2504           0 :     tv = tevent_timeval_current_ofs(10, 0);
    2505             : 
    2506           0 :     mini->timeout = tevent_add_timer(ctx->ev, mini, tv, init_timeout, mini);
    2507           0 :     if (!mini->timeout) {
    2508           0 :         DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
    2509           0 :         talloc_zfree(conn);
    2510           0 :         return ENOMEM;
    2511             :     }
    2512             : 
    2513           0 :     return sbus_conn_register_iface(conn, &monitor_methods.vtable,
    2514             :                                     MON_SRV_PATH, mini);
    2515             : }
    2516             : 
    2517             : /* service_send_ping
    2518             :  * this function send a dbus ping to a service.
    2519             :  * It returns EOK if all is fine or ENXIO if the connection is
    2520             :  * not available (either not yet set up or teared down).
    2521             :  * Returns e generic error in other cases.
    2522             :  */
    2523           0 : static int service_send_ping(struct mt_svc *svc)
    2524             : {
    2525             :     DBusMessage *msg;
    2526             :     int ret;
    2527             : 
    2528           0 :     if (!svc->conn) {
    2529           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Service not yet initialized\n");
    2530           0 :         return ENXIO;
    2531             :     }
    2532             : 
    2533           0 :     DEBUG(SSSDBG_CONF_SETTINGS,"Pinging %s\n", svc->name);
    2534             : 
    2535             :     /*
    2536             :      * Set up identity request
    2537             :      * This should be a well-known path and method
    2538             :      * for all services
    2539             :      */
    2540           0 :     msg = dbus_message_new_method_call(NULL,
    2541             :                                        MONITOR_PATH,
    2542             :                                        MON_CLI_IFACE,
    2543             :                                        MON_CLI_IFACE_PING);
    2544           0 :     if (!msg) {
    2545           0 :         DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
    2546           0 :         talloc_zfree(svc->conn);
    2547           0 :         return ENOMEM;
    2548             :     }
    2549             : 
    2550           0 :     ret = sbus_conn_send(svc->conn, msg,
    2551           0 :                          svc->ping_time * 1000, /* milliseconds */
    2552             :                          ping_check, svc, &svc->pending);
    2553           0 :     dbus_message_unref(msg);
    2554           0 :     return ret;
    2555             : }
    2556             : 
    2557           0 : static void ping_check(DBusPendingCall *pending, void *data)
    2558             : {
    2559             :     struct mt_svc *svc;
    2560             :     DBusMessage *reply;
    2561             :     const char *dbus_error_name;
    2562             :     size_t len;
    2563             :     int type;
    2564             : 
    2565           0 :     svc = talloc_get_type(data, struct mt_svc);
    2566           0 :     if (!svc) {
    2567             :         /* The connection probably went down before the callback fired.
    2568             :          * Not much we can do. */
    2569           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid service pointer.\n");
    2570           0 :         return;
    2571             :     }
    2572           0 :     svc->pending = NULL;
    2573             : 
    2574           0 :     reply = dbus_pending_call_steal_reply(pending);
    2575           0 :     if (!reply) {
    2576             :         /* reply should never be null. This function shouldn't be called
    2577             :          * until reply is valid or timeout has occurred. If reply is NULL
    2578             :          * here, something is seriously wrong and we should bail out.
    2579             :          */
    2580           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2581             :               "A reply callback was called but no reply was received"
    2582             :                   " and no timeout occurred\n");
    2583             : 
    2584             :         /* Destroy this connection */
    2585           0 :         sbus_disconnect(svc->conn);
    2586           0 :         goto done;
    2587             :     }
    2588             : 
    2589           0 :     type = dbus_message_get_type(reply);
    2590           0 :     switch (type) {
    2591             :     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
    2592             :         /* ok peer replied,
    2593             :          * make sure we reset the failure counter in the service structure */
    2594             : 
    2595           0 :         DEBUG(SSSDBG_CONF_SETTINGS,"Service %s replied to ping\n", svc->name);
    2596             : 
    2597           0 :         svc->failed_pongs = 0;
    2598           0 :         break;
    2599             : 
    2600             :     case DBUS_MESSAGE_TYPE_ERROR:
    2601             : 
    2602           0 :         dbus_error_name = dbus_message_get_error_name(reply);
    2603           0 :         if (!dbus_error_name) {
    2604           0 :             dbus_error_name = "<UNKNOWN>";
    2605             :         }
    2606             : 
    2607           0 :         len = strlen(DBUS_ERROR_NO_REPLY);
    2608             : 
    2609             :         /* Increase failed pong count */
    2610           0 :         if (strnlen(dbus_error_name, len + 1) == len
    2611           0 :                 && strncmp(dbus_error_name, DBUS_ERROR_NO_REPLY, len) == 0) {
    2612           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    2613             :                   "A service PING timed out on [%s]. "
    2614             :                    "Attempt [%d]\n",
    2615             :                    svc->name, svc->failed_pongs);
    2616           0 :             svc->failed_pongs++;
    2617           0 :             break;
    2618             :         }
    2619             : 
    2620           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2621             :               "A service PING returned an error [%s], closing connection.\n",
    2622             :                dbus_error_name);
    2623             :         /* Falling through to default intentionally*/
    2624             :     default:
    2625             :         /*
    2626             :          * Timeout or other error occurred or something
    2627             :          * unexpected happened.
    2628             :          * It doesn't matter which, because either way we
    2629             :          * know that this connection isn't trustworthy.
    2630             :          * We'll destroy it now.
    2631             :          */
    2632           0 :         sbus_disconnect(svc->conn);
    2633             :     }
    2634             : 
    2635             : done:
    2636           0 :     dbus_pending_call_unref(pending);
    2637           0 :     dbus_message_unref(reply);
    2638             : }
    2639             : 
    2640             : static void service_startup_handler(struct tevent_context *ev,
    2641             :                                     struct tevent_timer *te,
    2642             :                                     struct timeval t, void *ptr);
    2643             : 
    2644           0 : static int start_service(struct mt_svc *svc)
    2645             : {
    2646             :     struct tevent_timer *te;
    2647             :     struct timeval tv;
    2648             : 
    2649           0 :     DEBUG(SSSDBG_CONF_SETTINGS,"Queueing service %s for startup\n", svc->name);
    2650             : 
    2651           0 :     tv = tevent_timeval_current();
    2652             : 
    2653             :     /* Add a timed event to start up the service.
    2654             :      * We have to do this in order to avoid a race
    2655             :      * condition where the service being started forks
    2656             :      * and attempts to connect to the SBUS before
    2657             :      * the monitor is serving it.
    2658             :      */
    2659           0 :     te = tevent_add_timer(svc->mt_ctx->ev, svc, tv,
    2660             :                           service_startup_handler, svc);
    2661           0 :     if (te == NULL) {
    2662           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2663             :               "Unable to queue service %s for startup\n", svc->name);
    2664           0 :         return ENOMEM;
    2665             :     }
    2666           0 :     return EOK;
    2667             : }
    2668             : 
    2669             : static void mt_svc_exit_handler(int pid, int wait_status, void *pvt);
    2670           0 : static void service_startup_handler(struct tevent_context *ev,
    2671             :                                     struct tevent_timer *te,
    2672             :                                     struct timeval t, void *ptr)
    2673             : {
    2674             :     errno_t ret;
    2675             :     struct mt_svc *mt_svc;
    2676             :     char **args;
    2677             : 
    2678           0 :     mt_svc = talloc_get_type(ptr, struct mt_svc);
    2679           0 :     if (mt_svc == NULL) {
    2680           0 :         return;
    2681             :     }
    2682             : 
    2683           0 :     mt_svc->pid = fork();
    2684           0 :     if (mt_svc->pid != 0) {
    2685           0 :         if (mt_svc->pid == -1) {
    2686           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    2687             :                   "Could not fork child to start service [%s]. "
    2688             :                       "Continuing.\n", mt_svc->name);
    2689           0 :             return;
    2690             :         }
    2691             : 
    2692             :         /* Parent */
    2693           0 :         mt_svc->mt_ctx->check_children = true;
    2694           0 :         mt_svc->failed_pongs = 0;
    2695             : 
    2696             :         /* Handle process exit */
    2697           0 :         ret = sss_child_register(mt_svc,
    2698           0 :                                  mt_svc->mt_ctx->sigchld_ctx,
    2699             :                                  mt_svc->pid,
    2700             :                                  mt_svc_exit_handler,
    2701             :                                  mt_svc,
    2702             :                                  &mt_svc->child_ctx);
    2703           0 :         if (ret != EOK) {
    2704           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    2705             :                   "Could not register sigchld handler.\n");
    2706             :             /* Should we exit here? For now, we'll hope this
    2707             :              * child never dies, because we can't restart it.
    2708             :              */
    2709             :         }
    2710             : 
    2711           0 :         DLIST_ADD(mt_svc->mt_ctx->svc_list, mt_svc);
    2712           0 :         set_tasks_checker(mt_svc);
    2713             : 
    2714           0 :         return;
    2715             :     }
    2716             : 
    2717             :     /* child */
    2718             : 
    2719           0 :     args = parse_args(mt_svc->command);
    2720           0 :     execvp(args[0], args);
    2721             : 
    2722             :     /* If we are here, exec() has failed
    2723             :      * Print errno and abort quickly */
    2724           0 :     DEBUG(SSSDBG_FATAL_FAILURE,
    2725             :           "Could not exec %s, reason: %s\n", mt_svc->command, strerror(errno));
    2726             : 
    2727             :     /* We have to call _exit() instead of exit() here
    2728             :      * because a bug in D-BUS will cause the server to
    2729             :      * close its socket at exit() */
    2730           0 :     _exit(1);
    2731             : }
    2732             : 
    2733           0 : static void mt_svc_restart(struct tevent_context *ev,
    2734             :                            struct tevent_timer *te,
    2735             :                            struct timeval t, void *ptr)
    2736             : {
    2737             :     struct mt_svc *svc;
    2738             : 
    2739           0 :     svc = talloc_get_type(ptr, struct mt_svc);
    2740           0 :     if (svc == NULL) {
    2741           0 :         return;
    2742             :     }
    2743             : 
    2744           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Scheduling service %s for restart %d\n",
    2745             :                               svc->name, svc->restarts+1);
    2746             : 
    2747           0 :     if (svc->type == MT_SVC_SERVICE) {
    2748           0 :         add_new_service(svc->mt_ctx, svc->name, svc->restarts + 1);
    2749           0 :     } else if (svc->type == MT_SVC_PROVIDER) {
    2750           0 :         add_new_provider(svc->mt_ctx, svc->name, svc->restarts + 1);
    2751             :     } else {
    2752             :         /* Invalid type? */
    2753           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    2754             :               "BUG: Invalid child process type [%d]\n", svc->type);
    2755             :     }
    2756             : 
    2757             :     /* Free the old service (which will also remove it
    2758             :      * from the child list)
    2759             :      */
    2760           0 :     talloc_free(svc);
    2761             : }
    2762             : 
    2763           0 : static void mt_svc_exit_handler(int pid, int wait_status, void *pvt)
    2764             : {
    2765           0 :     struct mt_svc *svc = talloc_get_type(pvt, struct mt_svc);
    2766             : 
    2767             : 
    2768           0 :     if (WIFEXITED(wait_status)) {
    2769           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2770             :               "Child [%s] exited with code [%d]\n",
    2771             :                svc->name, WEXITSTATUS(wait_status));
    2772           0 :     } else if (WIFSIGNALED(wait_status)) {
    2773           0 :         DEBUG(SSSDBG_OP_FAILURE,
    2774             :               "Child [%s] terminated with signal [%d]\n",
    2775             :                svc->name, WTERMSIG(wait_status));
    2776             :     } else {
    2777           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2778             :               "Child [%s] did not exit cleanly\n", svc->name);
    2779             :         /* Forcibly kill this child, just in case */
    2780           0 :         kill(svc->pid, SIGKILL);
    2781             : 
    2782             :         /* Return and let us get caught by another
    2783             :          * call to the SIGCHLD handler
    2784             :          */
    2785           0 :         return;
    2786             :     }
    2787             : 
    2788             :     /* Clear the kill_timer so we don't try to SIGKILL it after it's
    2789             :      * already gone.
    2790             :      */
    2791           0 :     talloc_zfree(svc->kill_timer);
    2792             : 
    2793             :     /* Check the number of restart tries and relaunch the service */
    2794           0 :     monitor_restart_service(svc);
    2795             : 
    2796           0 :     return;
    2797             : }
    2798             : 
    2799           0 : static void monitor_restart_service(struct mt_svc *svc)
    2800             : {
    2801           0 :     struct mt_ctx *mt_ctx = svc->mt_ctx;
    2802             :     int restart_delay;
    2803           0 :     time_t now = time(NULL);
    2804             :     struct tevent_timer *te;
    2805             :     struct timeval tv;
    2806             : 
    2807             :     /* Handle the actual checks for how many times to restart this
    2808             :      * service before giving up.
    2809             :      */
    2810           0 :     if ((now - svc->last_restart) > MONITOR_RESTART_CNT_INTERVAL_RESET) {
    2811           0 :         svc->restarts = 0;
    2812             :     }
    2813             : 
    2814             :     /* Restart the service */
    2815           0 :     if (svc->restarts > MONITOR_MAX_SVC_RESTARTS) {
    2816           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2817             :               "Process [%s], definitely stopped!\n", svc->name);
    2818             : 
    2819           0 :         sss_log(SSS_LOG_ERR,
    2820             :                 "Exiting the SSSD. Could not restart critical service [%s].",
    2821             :                 svc->name);
    2822             : 
    2823           0 :         talloc_free(svc);
    2824             : 
    2825             :         /* exit the SSSD with an error, shutting down all
    2826             :          * services and domains.
    2827             :          * We do this because if one of the responders is down
    2828             :          * and can't come back up, this is the only way to
    2829             :          * guarantee admin intervention.
    2830             :          */
    2831           0 :         monitor_quit(mt_ctx, 1);
    2832           0 :         return;
    2833             :     }
    2834             : 
    2835             :     /* restarts are schedule after 0, 2, 4 seconds */
    2836           0 :     restart_delay = svc->restarts << 1;
    2837           0 :     if (restart_delay > MONITOR_MAX_RESTART_DELAY) {
    2838           0 :         restart_delay = MONITOR_MAX_RESTART_DELAY;
    2839             :     }
    2840             : 
    2841           0 :     tv = tevent_timeval_current_ofs(restart_delay, 0);
    2842           0 :     te = tevent_add_timer(svc->mt_ctx->ev, svc, tv, mt_svc_restart, svc);
    2843           0 :     if (te == NULL) {
    2844             :         /* Nothing much we can do */
    2845           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    2846             :               "Failed to allocate timed event: mt_svc_restart.\n");
    2847           0 :         talloc_free(svc);
    2848           0 :         return;
    2849             :     }
    2850             : }
    2851             : 
    2852           0 : int main(int argc, const char *argv[])
    2853             : {
    2854             :     int opt;
    2855             :     poptContext pc;
    2856           0 :     int opt_daemon = 0;
    2857           0 :     int opt_interactive = 0;
    2858           0 :     int opt_version = 0;
    2859           0 :     char *opt_config_file = NULL;
    2860           0 :     char *config_file = NULL;
    2861           0 :     int flags = 0;
    2862             :     struct main_context *main_ctx;
    2863             :     TALLOC_CTX *tmp_ctx;
    2864             :     struct mt_ctx *monitor;
    2865             :     int ret;
    2866             :     uid_t uid;
    2867             : 
    2868           0 :     struct poptOption long_options[] = {
    2869             :         POPT_AUTOHELP
    2870           0 :         SSSD_MAIN_OPTS
    2871             :         {"daemon", 'D', POPT_ARG_NONE, &opt_daemon, 0, \
    2872           0 :          _("Become a daemon (default)"), NULL }, \
    2873             :         {"interactive", 'i', POPT_ARG_NONE, &opt_interactive, 0, \
    2874           0 :          _("Run interactive (not a daemon)"), NULL}, \
    2875             :         {"config", 'c', POPT_ARG_STRING, &opt_config_file, 0, \
    2876           0 :          _("Specify a non-default config file"), NULL}, \
    2877             :          {"version", '\0', POPT_ARG_NONE, &opt_version, 0, \
    2878           0 :           _("Print version number and exit"), NULL }, \
    2879             :         POPT_TABLEEND
    2880             :     };
    2881             : 
    2882             :     /* Set debug level to invalid value so we can deside if -d 0 was used. */
    2883           0 :     debug_level = SSSDBG_INVALID;
    2884             : 
    2885           0 :     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
    2886           0 :     while((opt = poptGetNextOpt(pc)) != -1) {
    2887             :         switch(opt) {
    2888             :         default:
    2889           0 :             fprintf(stderr, "\nInvalid option %s: %s\n\n",
    2890             :                     poptBadOption(pc, 0), poptStrerror(opt));
    2891           0 :             poptPrintUsage(pc, stderr, 0);
    2892           0 :             return 1;
    2893             :         }
    2894             :     }
    2895             : 
    2896           0 :     DEBUG_INIT(debug_level);
    2897             : 
    2898           0 :     if (opt_version) {
    2899           0 :         puts(VERSION""PRERELEASE_VERSION);
    2900           0 :         return EXIT_SUCCESS;
    2901             :     }
    2902             : 
    2903             :     /* If the level or timestamps was passed at the command-line, we want
    2904             :      * to save it and pass it to the children later.
    2905             :      */
    2906           0 :     cmdline_debug_level = debug_level;
    2907           0 :     cmdline_debug_timestamps = debug_timestamps;
    2908           0 :     cmdline_debug_microseconds = debug_microseconds;
    2909             : 
    2910           0 :     if (opt_daemon && opt_interactive) {
    2911           0 :         fprintf(stderr, "Option -i|--interactive is not allowed together with -D|--daemon\n");
    2912           0 :         poptPrintUsage(pc, stderr, 0);
    2913           0 :         return 1;
    2914             :     }
    2915             : 
    2916           0 :     if (!opt_daemon && !opt_interactive) {
    2917           0 :         opt_daemon = 1;
    2918             :     }
    2919             : 
    2920           0 :     poptFreeContext(pc);
    2921             : 
    2922           0 :     uid = getuid();
    2923           0 :     if (uid != 0) {
    2924           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
    2925             :               "Running under %"SPRIuid", must be root\n", uid);
    2926           0 :         sss_log(SSS_LOG_ALERT, "sssd must be run as root");
    2927           0 :         return 8;
    2928             :     }
    2929             : 
    2930           0 :     tmp_ctx = talloc_new(NULL);
    2931           0 :     if (!tmp_ctx) {
    2932           0 :         return 7;
    2933             :     }
    2934             : 
    2935           0 :     if (opt_daemon) flags |= FLAGS_DAEMON;
    2936           0 :     if (opt_interactive) {
    2937           0 :         flags |= FLAGS_INTERACTIVE;
    2938           0 :         debug_to_stderr = 1;
    2939             :     }
    2940             : 
    2941           0 :     if (opt_config_file) {
    2942           0 :         config_file = talloc_strdup(tmp_ctx, opt_config_file);
    2943             :     } else {
    2944           0 :         config_file = talloc_strdup(tmp_ctx, CONFDB_DEFAULT_CONFIG_FILE);
    2945             :     }
    2946             : 
    2947           0 :     if (!config_file) {
    2948           0 :         return 6;
    2949             :     }
    2950             : 
    2951             :     /* we want a pid file check */
    2952           0 :     flags |= FLAGS_PID_FILE;
    2953             : 
    2954             :     /* Open before server_setup() does to have logging
    2955             :      * during configuration checking */
    2956           0 :     if (debug_to_file) {
    2957           0 :         ret = open_debug_file();
    2958           0 :         if (ret) {
    2959           0 :             return 7;
    2960             :         }
    2961             :     }
    2962             : 
    2963             : #ifdef USE_KEYRING
    2964             :     /* Do this before all the forks, it sets the session key ring so all
    2965             :      * keys are private to the daemon and cannot be read by any other process
    2966             :      * tree */
    2967             : 
    2968             :     /* make a new session */
    2969           0 :     ret = keyctl_join_session_keyring(NULL);
    2970           0 :     if (ret == -1) {
    2971           0 :         sss_log(SSS_LOG_ALERT,
    2972             :                 "Could not create private keyring session. "
    2973             :                 "If you store password there they may be easily accessible "
    2974           0 :                 "to the root user. (%d, %s)", errno, strerror(errno));
    2975             :     }
    2976             : 
    2977           0 :     ret = keyctl_setperm(KEY_SPEC_SESSION_KEYRING, KEY_POS_ALL);
    2978           0 :     if (ret == -1) {
    2979           0 :         sss_log(SSS_LOG_ALERT,
    2980             :                 "Could not set permissions on private keyring. "
    2981             :                 "If you store password there they may be easily accessible "
    2982           0 :                 "to the root user. (%d, %s)", errno, strerror(errno));
    2983             :     }
    2984             : #endif
    2985             : 
    2986             :     /* Warn if nscd seems to be running */
    2987           0 :     ret = check_file(NSCD_SOCKET_PATH,
    2988             :                      -1, -1, S_IFSOCK, S_IFMT, NULL, false);
    2989           0 :     if (ret == EOK) {
    2990           0 :         ret = sss_nscd_parse_conf(NSCD_CONF_PATH);
    2991             : 
    2992           0 :         switch (ret) {
    2993             :             case ENOENT:
    2994           0 :                 sss_log(SSS_LOG_NOTICE,
    2995             :                         "NSCD socket was detected. NSCD caching capabilities "
    2996             :                         "may conflict with SSSD for users and groups. It is "
    2997             :                         "recommended not to run NSCD in parallel with SSSD, "
    2998             :                         "unless NSCD is configured not to cache the passwd, "
    2999             :                         "group, netgroup and services nsswitch maps.");
    3000           0 :                 break;
    3001             : 
    3002             :             case EEXIST:
    3003           0 :                 sss_log(SSS_LOG_NOTICE,
    3004             :                         "NSCD socket was detected and seems to be configured "
    3005             :                         "to cache some of the databases controlled by "
    3006             :                         "SSSD [passwd,group,netgroup,services]. It is "
    3007             :                         "recommended not to run NSCD in parallel with SSSD, "
    3008             :                         "unless NSCD is configured not to cache these.");
    3009           0 :                 break;
    3010             : 
    3011             :             case EOK:
    3012           0 :                 DEBUG(SSSDBG_TRACE_FUNC, "NSCD socket was detected and it "
    3013             :                             "seems to be configured not to interfere with "
    3014             :                             "SSSD's caching capabilities\n");
    3015             :         }
    3016             :     }
    3017             : 
    3018             :     /* Parse config file, fail if cannot be done */
    3019           0 :     ret = load_configuration(tmp_ctx, config_file, &monitor);
    3020           0 :     if (ret != EOK) {
    3021           0 :         switch (ret) {
    3022             :         case ERR_MISSING_CONF:
    3023           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    3024             :                   "Configuration file: %s does not exist.\n", config_file);
    3025           0 :             sss_log(SSS_LOG_ALERT,
    3026             :                     "Configuration file: %s does not exist.\n", config_file);
    3027           0 :             break;
    3028             :         case EPERM:
    3029             :         case EACCES:
    3030           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    3031             :                   CONF_FILE_PERM_ERROR_MSG, config_file);
    3032           0 :             sss_log(SSS_LOG_ALERT, CONF_FILE_PERM_ERROR_MSG, config_file);
    3033           0 :             break;
    3034             :         default:
    3035           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    3036             :                  "SSSD couldn't load the configuration database.\n");
    3037           0 :             sss_log(SSS_LOG_ALERT,
    3038             :                    "SSSD couldn't load the configuration database [%d]: %s.\n",
    3039             :                     ret, strerror(ret));
    3040           0 :             break;
    3041             :         }
    3042           0 :         return 4;
    3043             :     }
    3044             : 
    3045             :     /* set up things like debug , signals, daemonization, etc... */
    3046           0 :     monitor->conf_path = CONFDB_MONITOR_CONF_ENTRY;
    3047           0 :     ret = close(STDIN_FILENO);
    3048           0 :     if (ret != EOK) return 6;
    3049             : 
    3050           0 :     ret = server_setup(MONITOR_NAME, flags, 0, 0,
    3051           0 :                        monitor->conf_path, &main_ctx);
    3052           0 :     if (ret != EOK) return 2;
    3053             : 
    3054           0 :     monitor->is_daemon = !opt_interactive;
    3055           0 :     monitor->parent_pid = main_ctx->parent_pid;
    3056           0 :     monitor->ev = main_ctx->event_ctx;
    3057           0 :     talloc_steal(main_ctx, monitor);
    3058             : 
    3059           0 :     ret = monitor_process_init(monitor,
    3060             :                                config_file);
    3061           0 :     if (ret != EOK) return 3;
    3062           0 :     talloc_free(tmp_ctx);
    3063             : 
    3064             :     /* loop on main */
    3065           0 :     server_loop(main_ctx);
    3066             : 
    3067           0 :     ret = monitor_cleanup();
    3068           0 :     if (ret != EOK) return 5;
    3069             : 
    3070           0 :     return 0;
    3071             : }

Generated by: LCOV version 1.10