monitor.c revision 0887c35bdb85adf0a4376dc8963294ea5a9d6da6
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/*
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher SSSD
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher Service monitor
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher Copyright (C) Simo Sorce 2008
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher This program is free software; you can redistribute it and/or modify
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher it under the terms of the GNU General Public License as published by
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher the Free Software Foundation; either version 3 of the License, or
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher (at your option) any later version.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher This program is distributed in the hope that it will be useful,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher but WITHOUT ANY WARRANTY; without even the implied warranty of
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher GNU General Public License for more details.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher You should have received a copy of the GNU General Public License
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher along with this program. If not, see <http://www.gnu.org/licenses/>.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher*/
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "util/util.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "util/child_common.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <sys/types.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <sys/wait.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <sys/time.h>
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce#include <sys/param.h>
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce#include <time.h>
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce#include <string.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#ifdef HAVE_SYS_INOTIFY_H
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <sys/inotify.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#endif
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <sys/types.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <sys/stat.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <unistd.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <fcntl.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <popt.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <tevent.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <dbus/dbus.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* Needed for res_init() */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <netinet/in.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <arpa/nameser.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <resolv.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "confdb/confdb.h"
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce#include "confdb/confdb_setup.h"
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce#include "db/sysdb.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "monitor/monitor.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "sbus/sssd_dbus.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "monitor/monitor_interfaces.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "responder/common/responder_sbus.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce#ifdef USE_KEYRING
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <keyutils.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#endif
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* ping time cannot be less then once every few seconds or the
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * monitor will get crazy hammering children with messages */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define MONITOR_DEF_PING_TIME 10
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* terminate the child after this interval by default if it
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * doesn't shutdown on receiving SIGTERM */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define MONITOR_DEF_FORCE_TIME 60
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* TODO: get the restart related values from config */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define MONITOR_RESTART_CNT_INTERVAL_RESET 30
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* maximum allowed number of service restarts if the restarts
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * were less than MONITOR_RESTART_CNT_INTERVAL_RESET apart, which would
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * indicate a crash after startup or after every request */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define MONITOR_MAX_SVC_RESTARTS 2
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* The services are restarted with a delay in case the restart was
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * hitting a race condition where the DP is not ready yet either.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * The MONITOR_MAX_RESTART_DELAY defines the maximum delay between
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * restarts.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define MONITOR_MAX_RESTART_DELAY 4
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* name of the monitor server instance */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define MONITOR_NAME "sssd"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define SSSD_PIDFILE_PATH PID_PATH"/"MONITOR_NAME".pid"
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce/* Special value to leave the Kerberos Replay Cache set to use
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * the libkrb5 defaults
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define KRB5_RCACHE_DIR_DISABLE "__LIBKRB5_DEFAULTS__"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* Warning messages */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define CONF_FILE_PERM_ERROR_MSG "Cannot read config file %s. Please check "\
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "that the file is accessible only by the "\
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "owner and owned by root.root.\n"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherint cmdline_debug_level;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherint cmdline_debug_timestamps;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherint cmdline_debug_microseconds;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct svc_spy;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherenum mt_svc_type {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher MT_SVC_SERVICE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher MT_SVC_PROVIDER
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher};
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct mt_svc {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc *prev;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc *next;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher enum mt_svc_type type;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sbus_connection *conn;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct svc_spy *conn_spy;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_ctx *mt_ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char *provider;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char *command;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce char *name;
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek char *identity;
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek pid_t pid;
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek int ping_time;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int kill_time;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool svc_started;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce int restarts;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher time_t last_restart;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int failed_pongs;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DBusPendingCall *pending;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int debug_level;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_timer *ping_ev;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce struct sss_child_ctx *child_ctx;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce};
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct config_file_callback {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int wd;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int retries;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher monitor_reconf_fn fn;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char *filename;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher time_t modified;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce struct config_file_callback *next;
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek struct config_file_callback *prev;
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek};
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek
21d485184df986e1a123f70c689517386e51a5ceMichal Zidekstruct config_file_ctx {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher TALLOC_CTX *parent_ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_timer *timer;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool needs_update;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_ctx *mt_ctx;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce struct config_file_callback *callbacks;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher};
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct mt_ctx {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_context *ev;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct confdb_ctx *cdb;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sss_domain_info *domains;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **services;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int num_services;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int started_services;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc *svc_list;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sbus_connection *sbus_srv;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct config_file_ctx *file_ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int inotify_fd;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int service_id_timeout;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool check_children;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool services_started;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct netlink_ctx *nlctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *conf_path;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sss_sigchild_ctx *sigchld_ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool is_daemon;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher pid_t parent_pid;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* For running unprivileged services */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher uid_t uid;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher gid_t gid;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher};
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int start_service(struct mt_svc *mt_svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int monitor_service_init(struct sbus_connection *conn, void *data);
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozekstatic int service_send_ping(struct mt_svc *svc);
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozekstatic int service_signal_reset_offline(struct mt_svc *svc);
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozekstatic void ping_check(DBusPendingCall *pending, void *data);
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozekstatic void set_tasks_checker(struct mt_svc *srv);
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozekstatic int monitor_kill_service (struct mt_svc *svc);
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozekstatic int get_service_config(struct mt_ctx *ctx, const char *name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc **svc_cfg);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int get_provider_config(struct mt_ctx *ctx, const char *name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc **svc_cfg);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int add_new_service(struct mt_ctx *ctx,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int restarts);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int add_new_provider(struct mt_ctx *ctx,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int restarts);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int mark_service_as_started(struct mt_svc *svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int monitor_cleanup(void);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic void network_status_change_cb(void *cb_data)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc *iter;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_ctx *ctx = (struct mt_ctx *) cb_data;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_TRACE_INTERNAL, "A networking status change detected "
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "signaling providers to reset offline status\n");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (iter = ctx->svc_list; iter; iter = iter->next) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Don't signal services, only providers */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (iter->provider) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher service_signal_reset_offline(iter);
9f37bb2012faa136ef7c1f9fe93689ce2be85637Ondrej Kos }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* dbus_get_monitor_version
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * Return the monitor version over D-BUS */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int get_monitor_version(struct sbus_request *dbus_req, void *data)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher dbus_uint16_t version = MONITOR_VERSION;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return sbus_request_return_and_finish(dbus_req,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DBUS_TYPE_UINT16, &version,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DBUS_TYPE_INVALID);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct mon_init_conn {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_ctx *ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sbus_connection *conn;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_timer *timeout;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher};
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int add_svc_conn_spy(struct mt_svc *svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
4a6a5421113ab662a665c62ed6a24b61a5a36950Jakub Hrozek/* registers a new client.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * if operation is successful also sends back the Monitor version */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int client_registration(struct sbus_request *dbus_req, void *data)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher dbus_uint16_t version = MONITOR_VERSION;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mon_init_conn *mini;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc *svc;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DBusError dbus_error;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher dbus_uint16_t svc_ver;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char *svc_name;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher dbus_bool_t dbret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher mini = talloc_get_type(data, struct mon_init_conn);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!mini) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return EINVAL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* First thing, cancel the timeout */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_zfree(mini->timeout);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher dbus_error_init(&dbus_error);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher dbret = dbus_message_get_args(dbus_req->message, &dbus_error,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DBUS_TYPE_STRING, &svc_name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DBUS_TYPE_UINT16, &svc_ver,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DBUS_TYPE_INVALID);
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce if (!dbret) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Failed to parse message, killing connection\n");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher sbus_disconnect(dbus_req->conn);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher sbus_request_finish(dbus_req, NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* FIXME: should we just talloc_zfree(conn) ? */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CONF_SETTINGS,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Received ID registration: (%s,%d)\n", svc_name, svc_ver);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* search this service in the list */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc = mini->ctx->svc_list;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher while (svc) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = strcasecmp(svc->identity, svc_name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret == 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher break;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc = svc->next;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!svc) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_FATAL_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Unable to find peer [%s] in list of services,"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher " killing connection!\n", svc_name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher sbus_disconnect(dbus_req->conn);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher sbus_request_finish(dbus_req, NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* FIXME: should we just talloc_zfree(conn) ? */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Fill in svc structure with connection data */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc->conn = mini->conn;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = mark_service_as_started(svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE, "Failed to mark service [%s]!\n", svc_name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* reply that all is ok */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher sbus_request_return_and_finish(dbus_req,
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce DBUS_TYPE_UINT16, &version,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DBUS_TYPE_INVALID);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherdone:
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* init complete, get rid of temp init context */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_zfree(mini);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct svc_spy {
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce struct mt_svc *svc;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher};
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int svc_destructor(void *mem)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc *svc = talloc_get_type(mem, struct mt_svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!svc) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* ?!?!? */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce /* try to delist service */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (svc->mt_ctx) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DLIST_REMOVE(svc->mt_ctx->svc_list, svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Cancel any pending pings */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (svc->pending) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher dbus_pending_call_cancel(svc->pending);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* svc is beeing freed, neutralize the spy */
6fb75e297bf7fc83e3db1f5ae8560624656ef319Jan Zeleny if (svc->conn_spy) {
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce talloc_set_destructor((TALLOC_CTX *)svc->conn_spy, NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_zfree(svc->conn_spy);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
6fb75e297bf7fc83e3db1f5ae8560624656ef319Jan Zeleny
6fb75e297bf7fc83e3db1f5ae8560624656ef319Jan Zeleny if (svc->type == MT_SVC_SERVICE && svc->svc_started
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher && svc->mt_ctx != NULL && svc->mt_ctx->started_services > 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc->mt_ctx->started_services--;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int svc_spy_destructor(void *mem)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct svc_spy *spy = talloc_get_type(mem, struct svc_spy);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!spy) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* ?!?!? */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* svc->conn has been freed, NULL the pointer in svc */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher spy->svc->conn_spy = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher spy->svc->conn = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int add_svc_conn_spy(struct mt_svc *svc)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct svc_spy *spy;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher spy = talloc(svc->conn, struct svc_spy);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!spy) return ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher spy->svc = svc;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_set_destructor((TALLOC_CTX *)spy, svc_spy_destructor);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc->conn_spy = spy;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int mark_service_as_started(struct mt_svc *svc)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_ctx *ctx = svc->mt_ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc *iter;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int i;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_FUNC_DATA, "Marking %s as started.\n", svc->name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc->svc_started = true;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* we need to attach a spy to the connection structure so that if some code
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * frees it we can zero it out in the service structure. Otherwise we may
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * try to access or even free, freed memory. */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = add_svc_conn_spy(svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_FATAL_FAILURE, "Failed to attch spy\n");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!ctx->services_started) {
2ce00e0d3896bb42db169d1e79553a81ca837a22Simo Sorce
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* check if all providers are up */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (iter = ctx->svc_list; iter; iter = iter->next) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (iter->provider && !iter->svc_started) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_FUNC_DATA,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Still waiting on %s provider.\n", iter->name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher break;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (iter) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* there are still unstarted providers */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ctx->services_started = true;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CONF_SETTINGS, "Now starting services!\n");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* then start all services */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (i = 0; ctx->services[i]; i++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher add_new_service(ctx, ctx->services[i], 0);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (svc->type == MT_SVC_SERVICE) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ctx->started_services++;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce if (ctx->started_services == ctx->num_services) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Initialization is complete, terminate parent process if in daemon
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * mode. Make sure we send the signal to the right process */
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose if (ctx->is_daemon) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ctx->parent_pid <= 1 || ctx->parent_pid != getppid()) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* the parent process was already terminated */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_MINOR_FAILURE, "Invalid parent pid: %d\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ctx->parent_pid);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
1ea2e8bd370e0dc2f2c3fa09232cf67082ef748dStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_TRACE_FUNC, "SSSD is initialized, "
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "terminating parent process\n");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher errno = 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = kill(ctx->parent_pid, SIGTERM);
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose if (ret != 0) {
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose ret = errno;
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose DEBUG(SSSDBG_FATAL_FAILURE, "Unable to terminate parent "
b8d703cf3aba81800cf1b8ccca64bb00ef0b30f7Sumit Bose "process [%d]: %s\n", ret, strerror(ret));
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose }
b8d703cf3aba81800cf1b8ccca64bb00ef0b30f7Sumit Bose }
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose }
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bosedone:
2ce00e0d3896bb42db169d1e79553a81ca837a22Simo Sorce return ret;
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose}
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose
b860f8b6b6b03982c80268e9f6fd35f6455b6b37Simo Sorcestatic void services_startup_timeout(struct tevent_context *ev,
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose struct tevent_timer *te,
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose struct timeval t, void *ptr)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_ctx *ctx = talloc_get_type(ptr, struct mt_ctx);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int i;
b860f8b6b6b03982c80268e9f6fd35f6455b6b37Simo Sorce
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_TRACE_FUNC, "Handling timeout\n");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!ctx->services_started) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE, "Providers did not start in time, "
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher "forcing services startup!\n");
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher ctx->services_started = true;
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CONF_SETTINGS, "Now starting services!\n");
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher /* then start all services */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (i = 0; ctx->services[i]; i++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher add_new_service(ctx, ctx->services[i], 0);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
b860f8b6b6b03982c80268e9f6fd35f6455b6b37Simo Sorce}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int add_services_startup_timeout(struct mt_ctx *ctx)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_timer *to;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct timeval tv;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* 5 seconds should be plenty */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tv = tevent_timeval_current_ofs(5, 0);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher to = tevent_add_timer(ctx->ev, ctx, tv, services_startup_timeout, ctx);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!to) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
b860f8b6b6b03982c80268e9f6fd35f6455b6b37Simo Sorce return ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct mon_srv_iface monitor_methods = {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher { &mon_srv_iface_meta, 0 },
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher .getVersion = get_monitor_version,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher .RegisterService = client_registration,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher};
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* monitor_dbus_init
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * Set up the monitor service as a D-BUS Server */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int monitor_dbus_init(struct mt_ctx *ctx)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
2ce00e0d3896bb42db169d1e79553a81ca837a22Simo Sorce char *monitor_address;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = monitor_get_sbus_address(ctx, &monitor_address);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* If a service is running as unprivileged user, we need to make sure this
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * user can access the monitor sbus server. root is still king, so we don't
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * lose any access.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sbus_new_server(ctx, ctx->ev, monitor_address, ctx->uid, ctx->gid,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher false, &ctx->sbus_srv, monitor_service_init, ctx);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_free(monitor_address);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic void tasks_check_handler(struct tevent_context *ev,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_timer *te,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct timeval t, void *ptr)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc *svc = talloc_get_type(ptr, struct mt_svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = service_send_ping(svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher switch (ret) {
4c08db0fb0dda3d27b1184248ca5c800d7ce23f0Michal Zidek case EOK:
4c08db0fb0dda3d27b1184248ca5c800d7ce23f0Michal Zidek /* all fine */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher break;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher case ENXIO:
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Child (%s) not responding! (yet)\n", svc->name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher break;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher default:
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* TODO: should we tear it down ? */
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Sending a message to service (%s) failed!!\n", svc->name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher break;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (svc->failed_pongs >= 3) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* too long since we last heard of this process */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Killing service [%s], not responding to pings!\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc->name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher sss_log(SSS_LOG_ERR,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Killing service [%s], not responding to pings!\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc->name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Kill the service. The SIGCHLD handler will restart it */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher monitor_kill_service(svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* all fine, set up the task checker again */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher set_tasks_checker(svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic void set_tasks_checker(struct mt_svc *svc)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_timer *te = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct timeval tv;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher gettimeofday(&tv, NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tv.tv_sec += svc->ping_time;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tv.tv_usec = 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher te = tevent_add_timer(svc->mt_ctx->ev, svc, tv, tasks_check_handler, svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (te == NULL) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_FATAL_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "failed to add event, monitor offline for [%s]!\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc->name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* FIXME: shutdown ? */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc->ping_ev = te;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic void mt_svc_sigkill(struct tevent_context *ev,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_timer *te,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct timeval t, void *ptr);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int monitor_kill_service (struct mt_svc *svc)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct timeval tv;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_timer *te;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = kill(svc->pid, SIGTERM);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret == -1) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = errno;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher DEBUG(SSSDBG_FATAL_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Sending signal to child (%s:%d) failed: [%d]: %s! "
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Ignore and pretend child is dead.\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc->name, svc->pid, ret, strerror(ret));
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Set up a timer to send SIGKILL if this process
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher * doesn't exit within sixty seconds
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher tv = tevent_timeval_current_ofs(svc->kill_time, 0);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher te = tevent_add_timer(svc->mt_ctx->ev, svc, tv, mt_svc_sigkill, svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (te == NULL) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Nothing much we can do */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Failed to allocate timed event: mt_svc_sigkill.\n");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagherdone:
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
de526c8425886ca3bed8f07a0f092ba5ac325654Simo Sorce talloc_free(svc);
de526c8425886ca3bed8f07a0f092ba5ac325654Simo Sorce }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic void mt_svc_sigkill(struct tevent_context *ev,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_timer *te,
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct timeval t, void *ptr)
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher{
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher int ret;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct mt_svc *svc = talloc_get_type(ptr, struct mt_svc);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher DEBUG(SSSDBG_FATAL_FAILURE,
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher "[%s][%d] is not responding to SIGTERM. Sending SIGKILL.\n",
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher svc->name, svc->pid);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher sss_log(SSS_LOG_ERR,
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher "[%s][%d] is not responding to SIGTERM. Sending SIGKILL.\n",
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek svc->name, svc->pid);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher ret = kill(svc->pid, SIGKILL);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher if (ret != EOK) {
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher DEBUG(SSSDBG_FATAL_FAILURE,
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher "Sending signal to child (%s:%d) failed! "
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher "Ignore and pretend child is dead.\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher svc->name, svc->pid);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_free(svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher}
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagherstatic void reload_reply(DBusPendingCall *pending, void *data)
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher{
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher DBusMessage *reply;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct mt_svc *svc = talloc_get_type(data, struct mt_svc);
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek
c3d09c0095a45de1973f320ce2045ac74d4e4f83Jakub Hrozek reply = dbus_pending_call_steal_reply(pending);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher if (!reply) {
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher /* reply should never be null. This function shouldn't be called
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher * until reply is valid or timeout has occurred. If reply is NULL
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher * here, something is seriously wrong and we should bail out.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_FATAL_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "A reply callback was called but no reply was received"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher " and no timeout occurred\n");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Destroy this connection */
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher sbus_disconnect(svc->conn);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher dbus_pending_call_unref(pending);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher return;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher }
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher /* TODO: Handle cases where the call has timed out or returned
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher * with an error.
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher */
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher dbus_pending_call_unref(pending);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher dbus_message_unref(reply);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher}
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagherstatic int service_signal_dns_reload(struct mt_svc *svc);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagherstatic int monitor_update_resolv(struct config_file_ctx *file_ctx,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *filename)
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct mt_svc *cur_svc;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_OP_FAILURE, "Resolv.conf has been updated. Reloading.\n");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher ret = res_init();
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher if(ret != 0) {
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher return EIO;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Signal all services to reload their DNS configuration */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for(cur_svc = file_ctx->mt_ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher service_signal_dns_reload(cur_svc);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int service_signal(struct mt_svc *svc, const char *svc_signal)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DBusMessage *msg;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher int ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (svc->provider && strcasecmp(svc->provider, "local") == 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* The local provider requires no signaling */
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher return EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher if (!svc->conn) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Avoid a race condition where we are trying to
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * order a service to reload that hasn't started
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * yet.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Could not signal service [%s].\n", svc->name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return EIO;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher msg = dbus_message_new_method_call(NULL,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher MONITOR_PATH,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher MON_CLI_IFACE,
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher svc_signal);
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher if (msg == NULL) {
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher DEBUG(SSSDBG_FATAL_FAILURE,
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher "Out of memory trying to allocate memory to invoke: %s\n",
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek svc_signal);
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher monitor_kill_service(svc);
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher return ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
de526c8425886ca3bed8f07a0f092ba5ac325654Simo Sorce
de526c8425886ca3bed8f07a0f092ba5ac325654Simo Sorce ret = sbus_conn_send(svc->conn, msg,
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher svc->mt_ctx->service_id_timeout,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher reload_reply, svc, NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher dbus_message_unref(msg);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ret;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher}
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagherstatic int service_signal_dns_reload(struct mt_svc *svc)
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher{
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher return service_signal(svc, MON_CLI_IFACE_RESINIT);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher}
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagherstatic int service_signal_offline(struct mt_svc *svc)
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher{
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher return service_signal(svc, MON_CLI_IFACE_GOOFFLINE);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher}
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozekstatic int service_signal_reset_offline(struct mt_svc *svc)
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher{
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher return service_signal(svc, MON_CLI_IFACE_RESETOFFLINE);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher}
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagherstatic int service_signal_rotate(struct mt_svc *svc)
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher{
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher return service_signal(svc, MON_CLI_IFACE_ROTATELOGS);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int service_signal_clear_memcache(struct mt_svc *svc)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher return service_signal(svc, MON_CLI_IFACE_CLEARMEMCACHE);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher}
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagherstatic int service_signal_clear_enum_cache(struct mt_svc *svc)
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher{
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher return service_signal(svc, MON_CLI_IFACE_CLEARENUMCACHE);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher}
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozekstatic int service_signal_sysbus_reconnect(struct mt_svc *svc)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return service_signal(svc, MON_CLI_IFACE_SYSBUSRECONNECT);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagherstatic int check_domain_ranges(struct sss_domain_info *domains)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sss_domain_info *dom = domains, *other = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher uint32_t id_min, id_max;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher while (dom) {
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher other = get_next_domain(dom, false);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher if (dom->id_max && dom->id_min > dom->id_max) {
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE,
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher "Domain '%s' does not have a valid ID range\n", dom->name);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher return EINVAL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher while (other) {
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher id_min = MAX(dom->id_min, other->id_min);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher id_max = MIN((dom->id_max ? dom->id_max : UINT32_MAX),
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher (other->id_max ? other->id_max : UINT32_MAX));
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher if (id_min <= id_max) {
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher DEBUG(SSSDBG_MINOR_FAILURE,
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher "Domains '%s' and '%s' overlap in range %u - %u\n",
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher dom->name, other->name, id_min, id_max);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher other = get_next_domain(other, false);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher dom = get_next_domain(dom, false);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher return EOK;
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher}
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int check_local_domain_unique(struct sss_domain_info *domains)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher uint8_t count = 0;
struct sss_domain_info *dom = domains;
while (dom) {
if (strcasecmp(dom->provider, "local") == 0) {
count++;
}
if (count > 1) {
break;
}
dom = get_next_domain(dom, false);
}
if (count > 1) {
return EINVAL;
}
return EOK;
}
static errno_t add_implicit_services(struct confdb_ctx *cdb, TALLOC_CTX *mem_ctx,
char ***_services)
{
int ret;
char **domain_names;
TALLOC_CTX *tmp_ctx;
size_t c;
char *conf_path;
char *id_provider;
bool add_pac = false;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
return ENOMEM;
}
ret = confdb_get_string_as_list(cdb, tmp_ctx,
CONFDB_MONITOR_CONF_ENTRY,
CONFDB_MONITOR_ACTIVE_DOMAINS,
&domain_names);
if (ret == ENOENT) {
DEBUG(SSSDBG_OP_FAILURE, "No domains configured!\n");
goto done;
}
for (c = 0; domain_names[c] != NULL; c++) {
conf_path = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL,
domain_names[c]);
if (conf_path == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
ret = ENOMEM;
goto done;
}
ret = confdb_get_string(cdb, tmp_ctx, conf_path,
CONFDB_DOMAIN_ID_PROVIDER, NULL, &id_provider);
if (ret == EOK) {
if (id_provider == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "id_provider is not set for "
"domain [%s], trying next domain.\n", domain_names[c]);
continue;
}
if (strcasecmp(id_provider, "IPA") == 0) {
add_pac = true;
}
} else {
DEBUG(SSSDBG_OP_FAILURE, "Failed to get id_provider for " \
"domain [%s], trying next domain.\n",
domain_names[c]);
}
}
if (BUILD_WITH_PAC_RESPONDER && add_pac &&
!string_in_list("pac", *_services, false)) {
ret = add_string_to_list(mem_ctx, "pac", _services);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "add_string_to_list failed.\n");
goto done;
}
}
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
static char *check_services(char **services)
{
const char * const *known_services = get_known_services();
int i;
int ii;
/* Check if services we are about to start are in the list if known */
for (i = 0; services[i]; i++) {
for (ii=0; known_services[ii]; ii++) {
if (strcasecmp(services[i], known_services[ii]) == 0) {
break;
}
}
if (known_services[ii] == NULL) {
return services[i];
}
}
return NULL;
}
static int get_service_user(struct mt_ctx *ctx)
{
errno_t ret;
char *user_str;
ret = confdb_get_string(ctx->cdb, ctx, CONFDB_MONITOR_CONF_ENTRY,
CONFDB_MONITOR_USER_RUNAS,
SSSD_USER, &user_str);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get the user to run as\n");
return ret;
}
ret = sss_user_by_name_or_uid(user_str, &ctx->uid, &ctx->gid);
talloc_free(user_str);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "Failed to set allowed UIDs.\n");
return ret;
}
return EOK;
}
static int get_monitor_config(struct mt_ctx *ctx)
{
int ret;
int timeout_seconds;
char *badsrv = NULL;
int i;
ret = confdb_get_int(ctx->cdb,
CONFDB_MONITOR_CONF_ENTRY,
CONFDB_MONITOR_SBUS_TIMEOUT,
10, &timeout_seconds);
if (ret != EOK) {
return ret;
}
ctx->service_id_timeout = timeout_seconds * 1000; /* service_id_timeout is in ms */
ret = confdb_get_string_as_list(ctx->cdb, ctx,
CONFDB_MONITOR_CONF_ENTRY,
CONFDB_MONITOR_ACTIVE_SERVICES,
&ctx->services);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "No services configured!\n");
return EINVAL;
}
ret = add_implicit_services(ctx->cdb, ctx, &ctx->services);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Failed to add implicit configured " \
"services. Some functionality might " \
"be missing");
}
badsrv = check_services(ctx->services);
if (badsrv != NULL) {
DEBUG(SSSDBG_FATAL_FAILURE, "Invalid service %s\n", badsrv);
return EINVAL;
}
ctx->started_services = 0;
ctx->num_services = 0;
for (i = 0; ctx->services[i] != NULL; i++) {
ctx->num_services++;
}
ret = get_service_user(ctx);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to get the unprivileged user\n");
return ret;
}
ret = confdb_get_domains(ctx->cdb, &ctx->domains);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured.\n");
return ret;
}
ret = check_local_domain_unique(ctx->domains);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "More than one local domain configured.\n");
return ret;
}
/* Check UID/GID overlaps */
ret = check_domain_ranges(ctx->domains);
if (ret != EOK) {
return ret;
}
return EOK;
}
static errno_t get_ping_config(struct mt_ctx *ctx, const char *path,
struct mt_svc *svc)
{
errno_t ret;
ret = confdb_get_int(ctx->cdb, path,
CONFDB_DOMAIN_TIMEOUT,
MONITOR_DEF_PING_TIME, &svc->ping_time);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to get ping timeout for '%s'\n", svc->name);
return ret;
}
/* 'timeout = 0' should be translated to the default */
if (svc->ping_time == 0) {
svc->ping_time = MONITOR_DEF_PING_TIME;
}
DEBUG(SSSDBG_CONF_SETTINGS,
"Time between service pings for [%s]: [%d]\n",
svc->name, svc->ping_time);
ret = confdb_get_int(ctx->cdb, path,
CONFDB_SERVICE_FORCE_TIMEOUT,
MONITOR_DEF_FORCE_TIME, &svc->kill_time);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to get kill timeout for %s\n", svc->name);
return ret;
}
/* 'force_timeout = 0' should be translated to the default */
if (svc->kill_time == 0) {
svc->kill_time = MONITOR_DEF_FORCE_TIME;
}
DEBUG(SSSDBG_CONF_SETTINGS,
"Time between SIGTERM and SIGKILL for [%s]: [%d]\n",
svc->name, svc->kill_time);
return EOK;
}
/* This is a temporary function that returns false if the service
* being started was only tested when running as root.
*/
static bool svc_supported_as_nonroot(const char *svc_name)
{
return false;
}
static int get_service_config(struct mt_ctx *ctx, const char *name,
struct mt_svc **svc_cfg)
{
int ret;
char *path;
struct mt_svc *svc;
time_t now = time(NULL);
uid_t uid = 0;
gid_t gid = 0;
*svc_cfg = NULL;
svc = talloc_zero(ctx, struct mt_svc);
if (!svc) {
return ENOMEM;
}
svc->mt_ctx = ctx;
svc->type = MT_SVC_SERVICE;
talloc_set_destructor((TALLOC_CTX *)svc, svc_destructor);
svc->name = talloc_strdup(svc, name);
if (!svc->name) {
talloc_free(svc);
return ENOMEM;
}
svc->identity = talloc_strdup(svc, name);
if (!svc->identity) {
talloc_free(svc);
return ENOMEM;
}
path = talloc_asprintf(svc, CONFDB_SERVICE_PATH_TMPL, svc->name);
if (!path) {
talloc_free(svc);
return ENOMEM;
}
ret = confdb_get_string(ctx->cdb, svc, path,
CONFDB_SERVICE_COMMAND,
NULL, &svc->command);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,"Failed to start service '%s'\n", svc->name);
talloc_free(svc);
return ret;
}
if (svc_supported_as_nonroot(svc->name)) {
uid = ctx->uid;
gid = ctx->gid;
}
if (!svc->command) {
svc->command = talloc_asprintf(
svc, "%s/sssd_%s", SSSD_LIBEXEC_PATH, svc->name
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
svc->command = talloc_asprintf_append(svc->command,
" --uid %"SPRIuid" --gid %"SPRIgid,
uid, gid);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
if (cmdline_debug_level != SSSDBG_UNRESOLVED) {
svc->command = talloc_asprintf_append(
svc->command, " -d %#.4x", cmdline_debug_level
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
}
if (cmdline_debug_timestamps != SSSDBG_TIMESTAMP_UNRESOLVED) {
svc->command = talloc_asprintf_append(
svc->command, " --debug-timestamps=%d", cmdline_debug_timestamps
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
}
if (cmdline_debug_microseconds != SSSDBG_MICROSECONDS_UNRESOLVED) {
svc->command = talloc_asprintf_append(
svc->command, " --debug-microseconds=%d",
cmdline_debug_microseconds
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
}
if (debug_to_file) {
svc->command = talloc_strdup_append(
svc->command, " --debug-to-files"
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
} else if (ctx->is_daemon == false) {
svc->command = talloc_strdup_append(
svc->command, " --debug-to-stderr"
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
}
}
ret = get_ping_config(ctx, path, svc);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to get ping timeouts for %s\n", svc->name);
talloc_free(svc);
return ret;
}
svc->last_restart = now;
*svc_cfg = svc;
talloc_free(path);
return EOK;
}
static int add_new_service(struct mt_ctx *ctx,
const char *name,
int restarts)
{
int ret;
struct mt_svc *svc;
ret = get_service_config(ctx, name, &svc);
if (ret != EOK) {
return ret;
}
svc->restarts = restarts;
ret = start_service(svc);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,"Failed to start service '%s'\n", svc->name);
talloc_free(svc);
}
return ret;
}
static int get_provider_config(struct mt_ctx *ctx, const char *name,
struct mt_svc **svc_cfg)
{
int ret;
char *path;
struct mt_svc *svc;
time_t now = time(NULL);
*svc_cfg = NULL;
svc = talloc_zero(ctx, struct mt_svc);
if (!svc) {
return ENOMEM;
}
svc->mt_ctx = ctx;
svc->type = MT_SVC_PROVIDER;
talloc_set_destructor((TALLOC_CTX *)svc, svc_destructor);
svc->name = talloc_strdup(svc, name);
if (!svc->name) {
talloc_free(svc);
return ENOMEM;
}
svc->identity = talloc_asprintf(svc, "%%BE_%s", svc->name);
if (!svc->identity) {
talloc_free(svc);
return ENOMEM;
}
path = talloc_asprintf(svc, CONFDB_DOMAIN_PATH_TMPL, name);
if (!path) {
talloc_free(svc);
return ENOMEM;
}
ret = confdb_get_string(ctx->cdb, svc, path,
CONFDB_DOMAIN_ID_PROVIDER,
NULL, &svc->provider);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Failed to find ID provider from [%s] configuration\n", name);
talloc_free(svc);
return ret;
}
ret = confdb_get_string(ctx->cdb, svc, path,
CONFDB_DOMAIN_COMMAND,
NULL, &svc->command);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Failed to find command from [%s] configuration\n", name);
talloc_free(svc);
return ret;
}
ret = get_ping_config(ctx, path, svc);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to get ping timeouts for %s\n", svc->name);
talloc_free(svc);
return ret;
}
talloc_free(path);
/* if no provider is present do not run the domain */
if (!svc->provider) {
talloc_free(svc);
return EIO;
}
/* if there are no custom commands, build a default one */
if (!svc->command) {
svc->command = talloc_asprintf(
svc, "%s/sssd_be --domain %s", SSSD_LIBEXEC_PATH, svc->name
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
svc->command = talloc_asprintf_append(svc->command,
" --uid %"SPRIuid" --gid %"SPRIgid,
ctx->uid, ctx->gid);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
if (cmdline_debug_level != SSSDBG_UNRESOLVED) {
svc->command = talloc_asprintf_append(
svc->command, " -d %#.4x", cmdline_debug_level
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
}
if (cmdline_debug_timestamps != SSSDBG_TIMESTAMP_UNRESOLVED) {
svc->command = talloc_asprintf_append(
svc->command, " --debug-timestamps=%d", cmdline_debug_timestamps
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
}
if (cmdline_debug_microseconds != SSSDBG_MICROSECONDS_UNRESOLVED) {
svc->command = talloc_asprintf_append(
svc->command, " --debug-microseconds=%d",
cmdline_debug_microseconds
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
}
if (debug_to_file) {
svc->command = talloc_strdup_append(
svc->command, " --debug-to-files"
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
} else if (ctx->is_daemon == false) {
svc->command = talloc_strdup_append(
svc->command, " --debug-to-stderr"
);
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
}
}
svc->last_restart = now;
*svc_cfg = svc;
return EOK;
}
static int add_new_provider(struct mt_ctx *ctx,
const char *name,
int restarts)
{
int ret;
struct mt_svc *svc;
ret = get_provider_config(ctx, name, &svc);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not get provider configuration for [%s]\n",
name);
return ret;
}
svc->restarts = restarts;
if (strcasecmp(svc->provider, "local") == 0) {
/* The LOCAL provider requires no back-end currently
* We'll add it to the service list, but we don't need
* to poll it.
*/
svc->svc_started = true;
DLIST_ADD(ctx->svc_list, svc);
return ENOENT;
}
ret = start_service(svc);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,"Failed to start service '%s'\n", svc->name);
talloc_free(svc);
}
return ret;
}
static void monitor_hup(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
struct mt_ctx *ctx = talloc_get_type(private_data, struct mt_ctx);
struct mt_svc *cur_svc;
DEBUG(SSSDBG_CRIT_FAILURE, "Received SIGHUP.\n");
/* Send D-Bus message to other services to rotate their logs.
* NSS service receives also message to clear memory caches. */
for(cur_svc = ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
service_signal_rotate(cur_svc);
if (!strcmp(NSS_SBUS_SERVICE_NAME, cur_svc->name)) {
service_signal_clear_memcache(cur_svc);
service_signal_clear_enum_cache(cur_svc);
}
if (!strcmp(SSS_AUTOFS_SBUS_SERVICE_NAME, cur_svc->name)) {
service_signal_clear_enum_cache(cur_svc);
}
}
}
static int monitor_cleanup(void)
{
int ret;
errno = 0;
ret = unlink(SSSD_PIDFILE_PATH);
if (ret == -1) {
ret = errno;
DEBUG(SSSDBG_FATAL_FAILURE,
"Error removing pidfile! (%d [%s])\n", ret, strerror(ret));
return ret;
}
return EOK;
}
static void monitor_quit(struct mt_ctx *mt_ctx, int ret)
{
struct mt_svc *svc;
pid_t pid;
int status;
errno_t error;
int kret;
bool killed;
DEBUG(SSSDBG_IMPORTANT_INFO, "Returned with: %d\n", ret);
/* Kill all of our known children manually */
DLIST_FOR_EACH(svc, mt_ctx->svc_list) {
if (svc->pid == 0) {
/* The local provider has no PID */
continue;
}
killed = false;
DEBUG(SSSDBG_CRIT_FAILURE,
"Terminating [%s][%d]\n", svc->name, svc->pid);
do {
errno = 0;
kret = kill(svc->pid, SIGTERM);
if (kret < 0) {
error = errno;
DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't kill [%s][%d]: [%s]\n",
svc->name, svc->pid, strerror(error));
}
error = 0;
do {
errno = 0;
pid = waitpid(svc->pid, &status, WNOHANG);
if (pid == -1) {
/* An error occurred while waiting */
error = errno;
if (error == ECHILD) {
killed = true;
} else if (error != EINTR) {
DEBUG(SSSDBG_FATAL_FAILURE,
"[%d][%s] while waiting for [%s]\n",
error, strerror(error), svc->name);
/* Forcibly kill this child */
kill(svc->pid, SIGKILL);
break;
}
} else if (pid != 0) {
error = 0;
if (WIFEXITED(status)) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Child [%s] exited gracefully\n", svc->name);
} else if (WIFSIGNALED(status)) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Child [%s] terminated with a signal\n", svc->name);
} else {
DEBUG(SSSDBG_FATAL_FAILURE,
"Child [%s] did not exit cleanly\n", svc->name);
/* Forcibly kill this child */
kill(svc->pid, SIGKILL);
}
killed = true;
}
} while (error == EINTR);
if (!killed) {
/* Sleep 10ms and try again */
usleep(10000);
}
} while (!killed);
}
#if HAVE_GETPGRP
/* Kill any remaining children in our process group, just in case
* we have any leftover children we don't expect. For example, if
* a krb5_child or ldap_child is running at the same moment.
*/
error = 0;
if (getpgrp() == getpid()) {
kill(-getpgrp(), SIGTERM);
do {
errno = 0;
pid = waitpid(0, &status, 0);
if (pid == -1) {
error = errno;
}
} while (error == EINTR || pid > 0);
}
#endif
monitor_cleanup();
exit(ret);
}
static void monitor_quit_signal(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
struct mt_ctx *mt_ctx = talloc_get_type(private_data, struct mt_ctx);
DEBUG(SSSDBG_TRACE_INTERNAL, "Received shutdown command\n");
DEBUG(SSSDBG_IMPORTANT_INFO, "Monitor received %s: terminating "
"children\n", strsignal(signum));
monitor_quit(mt_ctx, 0);
}
static void signal_res_init(struct mt_ctx *monitor)
{
struct mt_svc *cur_svc;
int ret;
DEBUG(SSSDBG_OP_FAILURE, "Reloading Resolv.conf.\n");
ret = res_init();
if (ret == 0) {
for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
service_signal_dns_reload(cur_svc);
}
}
}
static void signal_offline(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
struct mt_ctx *monitor;
struct mt_svc *cur_svc;
monitor = talloc_get_type(private_data, struct mt_ctx);
DEBUG(SSSDBG_TRACE_INTERNAL,
"Signaling providers to go offline immediately.\n");
/* Signal all providers to immediately go offline */
for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
/* Don't signal services, only providers */
if (cur_svc->provider) {
service_signal_offline(cur_svc);
}
}
}
static void signal_offline_reset(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
struct mt_ctx *monitor;
struct mt_svc *cur_svc;
monitor = talloc_get_type(private_data, struct mt_ctx);
DEBUG(SSSDBG_TRACE_INTERNAL,
"Signaling providers to reset offline immediately.\n");
for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
if (cur_svc->provider) {
service_signal_reset_offline(cur_svc);
}
if (strcmp(SSS_IFP_SBUS_SERVICE_NAME, cur_svc->name) == 0) {
service_signal_sysbus_reconnect(cur_svc);
}
}
signal_res_init(monitor);
}
static int monitor_ctx_destructor(void *mem)
{
struct mt_ctx *mon = talloc_get_type(mem, struct mt_ctx);
struct mt_svc *svc;
/* zero out references in svcs so that they don't try
* to access the monitor context on process shutdown */
for (svc = mon->svc_list; svc; svc = svc->next) {
svc->mt_ctx = NULL;
}
return 0;
}
static errno_t load_configuration(TALLOC_CTX *mem_ctx,
const char *config_file,
struct mt_ctx **monitor)
{
errno_t ret;
struct mt_ctx *ctx;
char *cdb_file = NULL;
ctx = talloc_zero(mem_ctx, struct mt_ctx);
if(!ctx) {
return ENOMEM;
}
talloc_set_destructor((TALLOC_CTX *)ctx, monitor_ctx_destructor);
cdb_file = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
if (cdb_file == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory, aborting!\n");
ret = ENOMEM;
goto done;
}
ret = confdb_init(ctx, &ctx->cdb, cdb_file);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,"The confdb initialization failed\n");
goto done;
}
/* Initialize the CDB from the configuration file */
ret = confdb_test(ctx->cdb);
if (ret == ENOENT) {
/* First-time setup */
/* Purge any existing confdb in case an old
* misconfiguration gets in the way
*/
talloc_zfree(ctx->cdb);
unlink(cdb_file);
ret = confdb_init(ctx, &ctx->cdb, cdb_file);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,"The confdb initialization failed\n");
goto done;
}
/* Load special entries */
ret = confdb_create_base(ctx->cdb);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Unable to load special entries into confdb\n");
goto done;
}
} else if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error initializing confdb\n");
goto done;
}
ret = confdb_init_db(config_file, ctx->cdb);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "ConfDB initialization has failed [%s]\n",
sss_strerror(ret));
goto done;
}
/* Validate the configuration in the database */
/* Read in the monitor's configuration */
ret = get_monitor_config(ctx);
if (ret != EOK) {
goto done;
}
/* Allow configuration database to be accessible
* when SSSD runs as nonroot */
ret = chown(cdb_file, ctx->uid, ctx->gid);
if (ret != 0) {
ret = errno;
DEBUG(SSSDBG_FATAL_FAILURE,
"chown failed for [%s]: [%d][%s].\n",
cdb_file, ret, sss_strerror(ret));
goto done;
}
*monitor = ctx;
ret = EOK;
done:
talloc_free(cdb_file);
if (ret != EOK) {
talloc_free(ctx);
}
return ret;
}
static errno_t monitor_config_file_fallback(TALLOC_CTX *mem_ctx,
struct mt_ctx *ctx,
const char *file,
monitor_reconf_fn fn,
bool ignore_missing);
#ifdef HAVE_INOTIFY
static void process_config_file(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr);
static void config_file_changed(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *data)
{
struct tevent_timer *te = NULL;
struct timeval tv;
struct config_file_ctx *file_ctx;
file_ctx = talloc_get_type(data, struct config_file_ctx);
if (file_ctx->needs_update) {
/* Skip updating. It's already queued for update.
*/
return;
}
/* We will queue the file for update in one second.
* This way, if there is a script writing to the file
* repeatedly, we won't be attempting to update multiple
* times.
*/
gettimeofday(&tv, NULL);
tv.tv_sec += 1;
te = tevent_add_timer(ev, ev, tv, process_config_file, file_ctx);
if (!te) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Unable to queue config file update! Exiting.\n");
kill(getpid(), SIGTERM);
return;
}
file_ctx->needs_update = 1;
}
struct rewatch_ctx {
struct config_file_callback *cb;
struct config_file_ctx *file_ctx;
};
static void rewatch_config_file(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr);
static void process_config_file(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
TALLOC_CTX *tmp_ctx;
struct inotify_event *in_event;
char *name;
ssize_t len;
struct config_file_ctx *file_ctx;
struct config_file_callback *cb;
struct rewatch_ctx *rw_ctx;
errno_t ret;
file_ctx = talloc_get_type(ptr, struct config_file_ctx);
DEBUG(SSSDBG_CRIT_FAILURE, "Processing config file changes\n");
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return;
in_event = talloc(tmp_ctx, struct inotify_event);
if (!in_event) {
goto done;
}
errno = 0;
len = sss_atomic_read_s(file_ctx->mt_ctx->inotify_fd, in_event,
sizeof(struct inotify_event));
if (len == -1) {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"Critical error reading inotify file descriptor [%d]: %s\n",
ret, strerror(ret));
goto done;
}
if (in_event->len > 0) {
/* Read in the name, even though we don't use it,
* so that read ptr is in the right place
*/
name = talloc_size(tmp_ctx, in_event->len);
if (!name) {
goto done;
}
errno = 0;
len = sss_atomic_read_s(file_ctx->mt_ctx->inotify_fd, name, in_event->len);
if (len == -1) {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"Critical error reading inotify file descriptor [%d]: %s\n",
ret, strerror(ret));
goto done;
}
}
for (cb = file_ctx->callbacks; cb; cb = cb->next) {
if (cb->wd == in_event->wd) {
break;
}
}
if (!cb) {
DEBUG(SSSDBG_FATAL_FAILURE, "Unknown watch descriptor\n");
goto done;
}
if (in_event->mask & IN_IGNORED) {
/* Some text editors will move a new file on top of the
* existing one instead of modifying it. In this case,
* the kernel will send us an IN_IGNORE signal.
* We will try to open a new watch descriptor on the
* new file.
*/
struct timeval tv;
struct tevent_timer *tev;
tv.tv_sec = t.tv_sec+5;
tv.tv_usec = t.tv_usec;
DEBUG(SSSDBG_FUNC_DATA, "Restoring inotify watch.\n");
cb->retries = 0;
rw_ctx = talloc(file_ctx, struct rewatch_ctx);
if(!rw_ctx) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not restore inotify watch. Quitting!\n");
close(file_ctx->mt_ctx->inotify_fd);
kill(getpid(), SIGTERM);
goto done;
}
rw_ctx->cb = cb;
rw_ctx->file_ctx = file_ctx;
tev = tevent_add_timer(ev, rw_ctx, tv, rewatch_config_file, rw_ctx);
if (tev == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not restore inotify watch. Quitting!\n");
close(file_ctx->mt_ctx->inotify_fd);
kill(getpid(), SIGTERM);
}
goto done;
}
/* Tell the monitor to signal the children */
cb->fn(file_ctx, cb->filename);
file_ctx->needs_update = 0;
done:
talloc_free(tmp_ctx);
}
static void rewatch_config_file(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
int err;
struct tevent_timer *tev = NULL;
struct timeval tv;
struct config_file_callback *cb;
struct rewatch_ctx *rw_ctx;
struct config_file_ctx *file_ctx;
rw_ctx = talloc_get_type(ptr, struct rewatch_ctx);
cb = rw_ctx->cb;
file_ctx = rw_ctx->file_ctx;
/* Retry six times at five-second intervals before giving up */
cb->retries++;
if (cb->retries > 6) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not restore inotify watch. Switching to polling!\n");
close(file_ctx->mt_ctx->inotify_fd);
err = monitor_config_file_fallback(file_ctx->parent_ctx,
file_ctx->mt_ctx,
cb->filename,
cb->fn,true);
if (err != EOK)
kill(getpid(), SIGTERM);
cb->fn(file_ctx, cb->filename);
talloc_free(rw_ctx);
/* A new callback was created in monitor_config_file_fallback()*/
DLIST_REMOVE(file_ctx->callbacks, cb);
talloc_free(cb);
return;
}
cb->wd = inotify_add_watch(file_ctx->mt_ctx->inotify_fd,
cb->filename, IN_MODIFY);
if (cb->wd < 0) {
err = errno;
tv.tv_sec = t.tv_sec+5;
tv.tv_usec = t.tv_usec;
DEBUG(SSSDBG_CRIT_FAILURE,
"Could not add inotify watch for file [%s]. Error [%d:%s]\n",
cb->filename, err, strerror(err));
tev = tevent_add_timer(ev, ev, tv, rewatch_config_file, rw_ctx);
if (tev == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not restore inotify watch. Quitting!\n");
close(file_ctx->mt_ctx->inotify_fd);
kill(getpid(), SIGTERM);
}
return;
}
cb->retries = 0;
/* Tell the monitor to signal the children */
cb->fn(file_ctx, cb->filename);
talloc_free(rw_ctx);
file_ctx->needs_update = 0;
}
#endif /* HAVE_INOTIFY */
static void poll_config_file(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
int ret, err;
struct stat file_stat;
struct timeval tv;
struct config_file_ctx *file_ctx;
struct config_file_callback *cb;
file_ctx = talloc_get_type(ptr,struct config_file_ctx);
for (cb = file_ctx->callbacks; cb; cb = cb->next) {
ret = stat(cb->filename, &file_stat);
if (ret < 0) {
err = errno;
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not stat file [%s]. Error [%d:%s]\n",
cb->filename, err, strerror(err));
/* TODO: If the config file is missing, should we shut down? */
return;
}
if (file_stat.st_mtime != cb->modified) {
/* Parse the configuration file and signal the children */
/* Note: this will fire if the modification time changes into the past
* as well as the future.
*/
DEBUG(SSSDBG_CRIT_FAILURE, "Config file changed\n");
cb->modified = file_stat.st_mtime;
/* Tell the monitor to signal the children */
cb->fn(file_ctx, cb->filename);
}
}
gettimeofday(&tv, NULL);
tv.tv_sec += CONFIG_FILE_POLL_INTERVAL;
tv.tv_usec = 0;
file_ctx->timer = tevent_add_timer(ev, file_ctx->parent_ctx, tv,
poll_config_file, file_ctx);
if (!file_ctx->timer) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Error: Config file no longer monitored for changes!\n");
}
}
static int try_inotify(struct config_file_ctx *file_ctx, const char *filename,
monitor_reconf_fn fn)
{
#ifdef HAVE_INOTIFY
int err, fd_args, ret;
struct tevent_fd *tfd;
struct config_file_callback *cb;
/* Monitoring the file descriptor should be global */
if (!file_ctx->mt_ctx->inotify_fd) {
/* Set up inotify to monitor the config file for changes */
file_ctx->mt_ctx->inotify_fd = inotify_init();
if (file_ctx->mt_ctx->inotify_fd < 0) {
err = errno;
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not initialize inotify, error [%d:%s]\n",
err, strerror(err));
return err;
}
fd_args = fcntl(file_ctx->mt_ctx->inotify_fd, F_GETFL, NULL);
if (fd_args < 0) {
/* Could not set nonblocking */
close(file_ctx->mt_ctx->inotify_fd);
return EINVAL;
}
fd_args |= O_NONBLOCK;
ret = fcntl(file_ctx->mt_ctx->inotify_fd, F_SETFL, fd_args);
if (ret < 0) {
/* Could not set nonblocking */
close(file_ctx->mt_ctx->inotify_fd);
return EINVAL;
}
/* Add the inotify file descriptor to the TEvent context */
tfd = tevent_add_fd(file_ctx->mt_ctx->ev, file_ctx,
file_ctx->mt_ctx->inotify_fd,
TEVENT_FD_READ, config_file_changed,
file_ctx);
if (!tfd) {
close(file_ctx->mt_ctx->inotify_fd);
return EIO;
}
}
cb = talloc_zero(file_ctx, struct config_file_callback);
if(!cb) {
close(file_ctx->mt_ctx->inotify_fd);
return ENOMEM;
}
cb->filename = talloc_strdup(cb, filename);
if (!cb->filename) {
close(file_ctx->mt_ctx->inotify_fd);
return ENOMEM;
}
cb->wd = inotify_add_watch(file_ctx->mt_ctx->inotify_fd,
cb->filename, IN_MODIFY);
if (cb->wd < 0) {
err = errno;
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not add inotify watch for file [%s]. Error [%d:%s]\n",
cb->filename, err, strerror(err));
close(file_ctx->mt_ctx->inotify_fd);
return err;
}
cb->fn = fn;
DLIST_ADD(file_ctx->callbacks, cb);
return EOK;
#else
return EINVAL;
#endif /* HAVE_INOTIFY */
}
static int monitor_config_file(TALLOC_CTX *mem_ctx,
struct mt_ctx *ctx,
const char *file,
monitor_reconf_fn fn,
bool ignore_missing)
{
int ret, err;
bool use_inotify;
struct stat file_stat;
ret = stat(file, &file_stat);
if (ret < 0) {
err = errno;
if (err == ENOENT && ignore_missing) {
DEBUG(SSSDBG_MINOR_FAILURE,
"file [%s] is missing. Will not update online status "
"based on watching the file\n", file);
return EOK;
} else {
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not stat file [%s]. Error [%d:%s]\n",
file, err, strerror(err));
return err;
}
}
if (!ctx->file_ctx) {
ctx->file_ctx = talloc_zero(mem_ctx, struct config_file_ctx);
if (!ctx->file_ctx) return ENOMEM;
ctx->file_ctx->parent_ctx = mem_ctx;
ctx->file_ctx->mt_ctx = ctx;
}
ret = confdb_get_bool(ctx->cdb,
CONFDB_MONITOR_CONF_ENTRY,
CONFDB_MONITOR_TRY_INOTIFY,
true, &use_inotify);
if (ret != EOK) {
talloc_free(ctx->file_ctx);
return ret;
}
if (use_inotify) {
ret = try_inotify(ctx->file_ctx, file, fn);
if (ret != EOK) {
use_inotify = false;
}
}
if (!use_inotify) {
/* Could not monitor file with inotify, fall back to polling */
ret = monitor_config_file_fallback(mem_ctx, ctx, file, fn, true);
}
return ret;
}
static errno_t monitor_config_file_fallback(TALLOC_CTX *mem_ctx,
struct mt_ctx *ctx,
const char *file,
monitor_reconf_fn fn,
bool ignore_missing)
{
struct config_file_callback *cb = NULL;
struct stat file_stat;
int ret, err;
struct timeval tv;
ret = stat(file, &file_stat);
if (ret < 0) {
err = errno;
if (err == ENOENT && ignore_missing) {
DEBUG(SSSDBG_MINOR_FAILURE,
"file [%s] is missing. Will not update online status "
"based on watching the file\n", file);
return EOK;
} else {
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not stat file [%s]. Error [%d:%s]\n",
file, err, strerror(err));
return err;
}
}
cb = talloc_zero(ctx->file_ctx, struct config_file_callback);
if (!cb) {
talloc_free(ctx->file_ctx);
return ENOMEM;
}
cb->filename = talloc_strdup(cb, file);
if (!cb->filename) {
talloc_free(ctx->file_ctx);
return ENOMEM;
}
cb->fn = fn;
cb->modified = file_stat.st_mtime;
DLIST_ADD(ctx->file_ctx->callbacks, cb);
if(!ctx->file_ctx->timer) {
gettimeofday(&tv, NULL);
tv.tv_sec += CONFIG_FILE_POLL_INTERVAL;
tv.tv_usec = 0;
ctx->file_ctx->timer = tevent_add_timer(ctx->ev, mem_ctx, tv,
poll_config_file, ctx->file_ctx);
if (!ctx->file_ctx->timer) {
talloc_free(ctx->file_ctx);
return EIO;
}
}
return EOK;
}
static int monitor_process_init(struct mt_ctx *ctx,
const char *config_file)
{
TALLOC_CTX *tmp_ctx;
struct tevent_signal *tes;
struct sss_domain_info *dom;
char *rcachedir;
int num_providers;
int ret;
int error;
/* Set up the environment variable for the Kerberos Replay Cache */
ret = confdb_get_string(ctx->cdb, ctx,
CONFDB_MONITOR_CONF_ENTRY,
CONFDB_MONITOR_KRB5_RCACHEDIR,
KRB5_RCACHE_DIR,
&rcachedir);
if (ret != EOK) {
return ret;
}
if (strcmp(rcachedir, KRB5_RCACHE_DIR_DISABLE) != 0)
{
errno = 0;
ret = setenv("KRB5RCACHEDIR", rcachedir, 1);
if (ret < 0) {
error = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"Unable to set KRB5RCACHEDIR: %s."
"Will attempt to use libkrb5 defaults\n",
strerror(error));
}
talloc_zfree(rcachedir);
}
/* Set up an event handler for a SIGHUP */
tes = tevent_add_signal(ctx->ev, ctx, SIGHUP, 0,
monitor_hup, ctx);
if (tes == NULL) {
return EIO;
}
/* Set up an event handler for a SIGINT */
BlockSignals(false, SIGINT);
tes = tevent_add_signal(ctx->ev, ctx, SIGINT, 0,
monitor_quit_signal, ctx);
if (tes == NULL) {
return EIO;
}
/* Set up an event handler for a SIGTERM */
tes = tevent_add_signal(ctx->ev, ctx, SIGTERM, 0,
monitor_quit_signal, ctx);
if (tes == NULL) {
return EIO;
}
/* Handle SIGUSR1 (tell all providers to go offline) */
BlockSignals(false, SIGUSR1);
tes = tevent_add_signal(ctx->ev, ctx, SIGUSR1, 0,
signal_offline, ctx);
if (tes == NULL) {
return EIO;
}
/* Handle SIGUSR2 (tell all providers to go reset offline) */
BlockSignals(false, SIGUSR2);
tes = tevent_add_signal(ctx->ev, ctx, SIGUSR2, 0,
signal_offline_reset, ctx);
if (tes == NULL) {
return EIO;
}
/* Set up the SIGCHLD handler */
ret = sss_sigchld_init(ctx, ctx->ev, &ctx->sigchld_ctx);
if (ret != EOK) return ret;
#if 0
This feature is incomplete and can leave the SSSD in a bad state if the
config file is changed while the SSSD is running.
Uncomment this once the backends are honoring reloadConfig()
/* Watch for changes to the confdb config file */
ret = monitor_config_file(ctx, ctx, config_file, monitor_signal_reconf,
true);
if (ret != EOK) {
return ret;
}
#endif
/* Watch for changes to the DNS resolv.conf */
ret = monitor_config_file(ctx, ctx, RESOLV_CONF_PATH,
monitor_update_resolv,true);
if (ret != EOK) {
return ret;
}
/* Avoid a startup race condition between process.
* We need to handle DB upgrades or DB creation only
* in one process before all other start.
*/
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
return ENOMEM;
}
ret = sysdb_init_ext(tmp_ctx, ctx->domains, true,
true, ctx->uid, ctx->gid);
if (ret != EOK) {
SYSDB_VERSION_ERROR_DAEMON(ret);
return ret;
}
talloc_zfree(tmp_ctx);
/* Initialize D-BUS Server
* The monitor will act as a D-BUS server for all
* SSSD processes */
ret = monitor_dbus_init(ctx);
if (ret != EOK) {
return ret;
}
ret = setup_netlink(ctx, ctx->ev, network_status_change_cb,
ctx, &ctx->nlctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot set up listening for network notifications\n");
return ret;
}
/* start providers */
num_providers = 0;
for (dom = ctx->domains; dom; dom = get_next_domain(dom, false)) {
ret = add_new_provider(ctx, dom->name, 0);
if (ret != EOK && ret != ENOENT) {
return ret;
}
if (ret != ENOENT) {
num_providers++;
}
}
if (num_providers > 0) {
/* now set the services stratup timeout *
* (responders will be started automatically when all
* providers are up and running or when the tomeout
* expires) */
ret = add_services_startup_timeout(ctx);
if (ret != EOK) {
return ret;
}
} else {
int i;
ctx->services_started = true;
/* No providers start services immediately
* Normally this means only LOCAL is configured */
for (i = 0; ctx->services[i]; i++) {
add_new_service(ctx, ctx->services[i], 0);
}
}
return EOK;
}
static void init_timeout(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
struct mon_init_conn *mini;
DEBUG(SSSDBG_OP_FAILURE, "Client timed out before Identification!\n");
mini = talloc_get_type(ptr, struct mon_init_conn);
sbus_disconnect(mini->conn);
talloc_zfree(mini);
}
/*
* monitor_service_init
* Set up a timeout function and temporary connection structure.
* If the client does not identify before the timeout kicks in,
* the client is forcibly disconnected.
*/
static int monitor_service_init(struct sbus_connection *conn, void *data)
{
struct sbus_interface *intf;
struct mt_ctx *ctx;
struct mon_init_conn *mini;
struct timeval tv;
DEBUG(SSSDBG_TRACE_FUNC, "Initializing D-BUS Service\n");
ctx = talloc_get_type(data, struct mt_ctx);
mini = talloc(conn, struct mon_init_conn);
if (!mini) {
DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
talloc_zfree(conn);
return ENOMEM;
}
mini->ctx = ctx;
mini->conn = conn;
/* Allow access from the SSSD user */
sbus_allow_uid(conn, &ctx->uid);
/* 10 seconds should be plenty */
tv = tevent_timeval_current_ofs(10, 0);
mini->timeout = tevent_add_timer(ctx->ev, mini, tv, init_timeout, mini);
if (!mini->timeout) {
DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
talloc_zfree(conn);
return ENOMEM;
}
intf = sbus_new_interface(conn, MON_SRV_PATH, &monitor_methods.vtable, mini);
if (!intf) {
return ENOMEM;
}
return sbus_conn_add_interface(conn, intf);
}
/* service_send_ping
* this function send a dbus ping to a service.
* It returns EOK if all is fine or ENXIO if the connection is
* not available (either not yet set up or teared down).
* Returns e generic error in other cases.
*/
static int service_send_ping(struct mt_svc *svc)
{
DBusMessage *msg;
int ret;
if (!svc->conn) {
DEBUG(SSSDBG_TRACE_INTERNAL, "Service not yet initialized\n");
return ENXIO;
}
DEBUG(SSSDBG_CONF_SETTINGS,"Pinging %s\n", svc->name);
/*
* Set up identity request
* This should be a well-known path and method
* for all services
*/
msg = dbus_message_new_method_call(NULL,
MONITOR_PATH,
MON_CLI_IFACE,
MON_CLI_IFACE_PING);
if (!msg) {
DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
talloc_zfree(svc->conn);
return ENOMEM;
}
ret = sbus_conn_send(svc->conn, msg,
svc->ping_time * 1000, /* milliseconds */
ping_check, svc, &svc->pending);
dbus_message_unref(msg);
return ret;
}
static void ping_check(DBusPendingCall *pending, void *data)
{
struct mt_svc *svc;
DBusMessage *reply;
const char *dbus_error_name;
size_t len;
int type;
svc = talloc_get_type(data, struct mt_svc);
if (!svc) {
/* The connection probably went down before the callback fired.
* Not much we can do. */
DEBUG(SSSDBG_CRIT_FAILURE, "Invalid service pointer.\n");
return;
}
svc->pending = NULL;
reply = dbus_pending_call_steal_reply(pending);
if (!reply) {
/* reply should never be null. This function shouldn't be called
* until reply is valid or timeout has occurred. If reply is NULL
* here, something is seriously wrong and we should bail out.
*/
DEBUG(SSSDBG_FATAL_FAILURE,
"A reply callback was called but no reply was received"
" and no timeout occurred\n");
/* Destroy this connection */
sbus_disconnect(svc->conn);
goto done;
}
type = dbus_message_get_type(reply);
switch (type) {
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
/* ok peer replied,
* make sure we reset the failure counter in the service structure */
DEBUG(SSSDBG_CONF_SETTINGS,"Service %s replied to ping\n", svc->name);
svc->failed_pongs = 0;
break;
case DBUS_MESSAGE_TYPE_ERROR:
dbus_error_name = dbus_message_get_error_name(reply);
if (!dbus_error_name) {
dbus_error_name = "<UNKNOWN>";
}
len = strlen(DBUS_ERROR_NO_REPLY);
/* Increase failed pong count */
if (strnlen(dbus_error_name, len + 1) == len
&& strncmp(dbus_error_name, DBUS_ERROR_NO_REPLY, len) == 0) {
DEBUG(SSSDBG_CRIT_FAILURE,
"A service PING timed out on [%s]. "
"Attempt [%d]\n",
svc->name, svc->failed_pongs);
svc->failed_pongs++;
break;
}
DEBUG(SSSDBG_FATAL_FAILURE,
"A service PING returned an error [%s], closing connection.\n",
dbus_error_name);
/* Falling through to default intentionally*/
default:
/*
* Timeout or other error occurred or something
* unexpected happened.
* It doesn't matter which, because either way we
* know that this connection isn't trustworthy.
* We'll destroy it now.
*/
sbus_disconnect(svc->conn);
}
done:
dbus_pending_call_unref(pending);
dbus_message_unref(reply);
}
static void service_startup_handler(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr);
static int start_service(struct mt_svc *svc)
{
struct tevent_timer *te;
struct timeval tv;
DEBUG(SSSDBG_CONF_SETTINGS,"Queueing service %s for startup\n", svc->name);
tv = tevent_timeval_current();
/* Add a timed event to start up the service.
* We have to do this in order to avoid a race
* condition where the service being started forks
* and attempts to connect to the SBUS before
* the monitor is serving it.
*/
te = tevent_add_timer(svc->mt_ctx->ev, svc, tv,
service_startup_handler, svc);
if (te == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Unable to queue service %s for startup\n", svc->name);
return ENOMEM;
}
return EOK;
}
static void mt_svc_exit_handler(int pid, int wait_status, void *pvt);
static void service_startup_handler(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
errno_t ret;
struct mt_svc *mt_svc;
char **args;
mt_svc = talloc_get_type(ptr, struct mt_svc);
if (mt_svc == NULL) {
return;
}
mt_svc->pid = fork();
if (mt_svc->pid != 0) {
if (mt_svc->pid == -1) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not fork child to start service [%s]. "
"Continuing.\n", mt_svc->name);
return;
}
/* Parent */
mt_svc->mt_ctx->check_children = true;
mt_svc->failed_pongs = 0;
/* Handle process exit */
ret = sss_child_register(mt_svc,
mt_svc->mt_ctx->sigchld_ctx,
mt_svc->pid,
mt_svc_exit_handler,
mt_svc,
&mt_svc->child_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not register sigchld handler.\n");
/* Should we exit here? For now, we'll hope this
* child never dies, because we can't restart it.
*/
}
DLIST_ADD(mt_svc->mt_ctx->svc_list, mt_svc);
set_tasks_checker(mt_svc);
return;
}
/* child */
args = parse_args(mt_svc->command);
execvp(args[0], args);
/* If we are here, exec() has failed
* Print errno and abort quickly */
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not exec %s, reason: %s\n", mt_svc->command, strerror(errno));
/* We have to call _exit() instead of exit() here
* because a bug in D-BUS will cause the server to
* close its socket at exit() */
_exit(1);
}
static void mt_svc_restart(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
struct mt_svc *svc;
svc = talloc_get_type(ptr, struct mt_svc);
if (svc == NULL) {
return;
}
DEBUG(SSSDBG_TRACE_FUNC, "Scheduling service %s for restart %d\n",
svc->name, svc->restarts+1);
if (svc->type == MT_SVC_SERVICE) {
add_new_service(svc->mt_ctx, svc->name, svc->restarts + 1);
} else if (svc->type == MT_SVC_PROVIDER) {
add_new_provider(svc->mt_ctx, svc->name, svc->restarts + 1);
} else {
/* Invalid type? */
DEBUG(SSSDBG_CRIT_FAILURE,
"BUG: Invalid child process type [%d]\n", svc->type);
}
/* Free the old service (which will also remove it
* from the child list)
*/
talloc_free(svc);
}
static void mt_svc_exit_handler(int pid, int wait_status, void *pvt)
{
struct mt_svc *svc = talloc_get_type(pvt, struct mt_svc);
struct mt_ctx *mt_ctx = svc->mt_ctx;
time_t now = time(NULL);
struct tevent_timer *te;
struct timeval tv;
int restart_delay;
if (WIFEXITED(wait_status)) {
DEBUG(SSSDBG_OP_FAILURE,
"Child [%s] exited with code [%d]\n",
svc->name, WEXITSTATUS(wait_status));
} else if (WIFSIGNALED(wait_status)) {
DEBUG(SSSDBG_OP_FAILURE,
"Child [%s] terminated with signal [%d]\n",
svc->name, WTERMSIG(wait_status));
} else {
DEBUG(SSSDBG_FATAL_FAILURE,
"Child [%s] did not exit cleanly\n", svc->name);
/* Forcibly kill this child, just in case */
kill(svc->pid, SIGKILL);
/* Return and let us get caught by another
* call to the SIGCHLD handler
*/
return;
}
if ((now - svc->last_restart) > MONITOR_RESTART_CNT_INTERVAL_RESET) {
svc->restarts = 0;
}
/* Restart the service */
if (svc->restarts > MONITOR_MAX_SVC_RESTARTS) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Process [%s], definitely stopped!\n", svc->name);
talloc_free(svc);
/* exit with error */
monitor_quit(mt_ctx, 1);
return;
}
/* restarts are schedule after 0, 2, 4 seconds */
restart_delay = svc->restarts << 1;
if (restart_delay > MONITOR_MAX_RESTART_DELAY) {
restart_delay = MONITOR_MAX_RESTART_DELAY;
}
tv = tevent_timeval_current_ofs(restart_delay, 0);
te = tevent_add_timer(svc->mt_ctx->ev, svc, tv, mt_svc_restart, svc);
if (te == NULL) {
/* Nothing much we can do */
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to allocate timed event: mt_svc_restart.\n");
talloc_free(svc);
return;
}
}
int main(int argc, const char *argv[])
{
int opt;
poptContext pc;
int opt_daemon = 0;
int opt_interactive = 0;
int opt_version = 0;
char *opt_config_file = NULL;
char *config_file = NULL;
int flags = 0;
struct main_context *main_ctx;
TALLOC_CTX *tmp_ctx;
struct mt_ctx *monitor;
int ret;
uid_t uid;
struct poptOption long_options[] = {
POPT_AUTOHELP
SSSD_MAIN_OPTS
{"daemon", 'D', POPT_ARG_NONE, &opt_daemon, 0, \
_("Become a daemon (default)"), NULL }, \
{"interactive", 'i', POPT_ARG_NONE, &opt_interactive, 0, \
_("Run interactive (not a daemon)"), NULL}, \
{"config", 'c', POPT_ARG_STRING, &opt_config_file, 0, \
_("Specify a non-default config file"), NULL}, \
{"version", '\0', POPT_ARG_NONE, &opt_version, 0, \
_("Print version number and exit"), NULL }, \
POPT_TABLEEND
};
/* Set debug level to invalid value so we can deside if -d 0 was used. */
debug_level = SSSDBG_INVALID;
pc = poptGetContext(argv[0], argc, argv, long_options, 0);
while((opt = poptGetNextOpt(pc)) != -1) {
switch(opt) {
default:
fprintf(stderr, "\nInvalid option %s: %s\n\n",
poptBadOption(pc, 0), poptStrerror(opt));
poptPrintUsage(pc, stderr, 0);
return 1;
}
}
DEBUG_INIT(debug_level);
if (opt_version) {
puts(VERSION""PRERELEASE_VERSION);
return EXIT_SUCCESS;
}
/* If the level or timestamps was passed at the command-line, we want
* to save it and pass it to the children later.
*/
cmdline_debug_level = debug_level;
cmdline_debug_timestamps = debug_timestamps;
cmdline_debug_microseconds = debug_microseconds;
if (opt_daemon && opt_interactive) {
fprintf(stderr, "Option -i|--interactive is not allowed together with -D|--daemon\n");
poptPrintUsage(pc, stderr, 0);
return 1;
}
if (!opt_daemon && !opt_interactive) {
opt_daemon = 1;
}
poptFreeContext(pc);
uid = getuid();
if (uid != 0) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Running under %"SPRIuid", must be root\n", uid);
sss_log(SSS_LOG_ALERT, "sssd must be run as root");
return 8;
}
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
return 7;
}
if (opt_daemon) flags |= FLAGS_DAEMON;
if (opt_interactive) {
flags |= FLAGS_INTERACTIVE;
debug_to_stderr = 1;
}
if (opt_config_file) {
config_file = talloc_strdup(tmp_ctx, opt_config_file);
} else {
config_file = talloc_strdup(tmp_ctx, CONFDB_DEFAULT_CONFIG_FILE);
}
if (!config_file) {
return 6;
}
/* we want a pid file check */
flags |= FLAGS_PID_FILE;
/* Open before server_setup() does to have logging
* during configuration checking */
if (debug_to_file) {
ret = open_debug_file();
if (ret) {
return 7;
}
}
#ifdef USE_KEYRING
/* Do this before all the forks, it sets the session key ring so all
* keys are private to the daemon and cannot be read by any other process
* tree */
/* make a new session */
ret = keyctl_join_session_keyring(NULL);
if (ret == -1) {
sss_log(SSS_LOG_ALERT,
"Could not create private keyring session. "
"If you store password there they may be easily accessible "
"to the root user. (%d, %s)", errno, strerror(errno));
}
ret = keyctl_setperm(KEY_SPEC_SESSION_KEYRING, KEY_POS_ALL);
if (ret == -1) {
sss_log(SSS_LOG_ALERT,
"Could not set permissions on private keyring. "
"If you store password there they may be easily accessible "
"to the root user. (%d, %s)", errno, strerror(errno));
}
#endif
/* Warn if nscd seems to be running */
ret = check_file(NSCD_SOCKET_PATH,
-1, -1, S_IFSOCK, S_IFMT, NULL, false);
if (ret == EOK) {
ret = sss_nscd_parse_conf(NSCD_CONF_PATH);
switch (ret) {
case ENOENT:
sss_log(SSS_LOG_NOTICE,
"NSCD socket was detected. NSCD caching capabilities "
"may conflict with SSSD for users and groups. It is "
"recommended not to run NSCD in parallel with SSSD, "
"unless NSCD is configured not to cache the passwd, "
"group, netgroup and services nsswitch maps.");
break;
case EEXIST:
sss_log(SSS_LOG_NOTICE,
"NSCD socket was detected and seems to be configured "
"to cache some of the databases controlled by "
"SSSD [passwd,group,netgroup,services]. It is "
"recommended not to run NSCD in parallel with SSSD, "
"unless NSCD is configured not to cache these.");
break;
case EOK:
DEBUG(SSSDBG_TRACE_FUNC, "NSCD socket was detected and it "
"seems to be configured not to interfere with "
"SSSD's caching capabilities\n");
}
}
/* Parse config file, fail if cannot be done */
ret = load_configuration(tmp_ctx, config_file, &monitor);
if (ret != EOK) {
switch (ret) {
case ERR_MISSING_CONF:
DEBUG(SSSDBG_CRIT_FAILURE,
"Configuration file: %s does not exist.\n", config_file);
sss_log(SSS_LOG_ALERT,
"Configuration file: %s does not exist.\n", config_file);
break;
case EPERM:
case EACCES:
DEBUG(SSSDBG_CRIT_FAILURE,
CONF_FILE_PERM_ERROR_MSG, config_file);
sss_log(SSS_LOG_ALERT, CONF_FILE_PERM_ERROR_MSG, config_file);
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE,
"SSSD couldn't load the configuration database.\n");
sss_log(SSS_LOG_ALERT,
"SSSD couldn't load the configuration database [%d]: %s.\n",
ret, strerror(ret));
break;
}
return 4;
}
/* set up things like debug , signals, daemonization, etc... */
monitor->conf_path = CONFDB_MONITOR_CONF_ENTRY;
ret = close(STDIN_FILENO);
if (ret != EOK) return 6;
ret = server_setup(MONITOR_NAME, flags, 0, 0,
monitor->conf_path, &main_ctx);
if (ret != EOK) return 2;
monitor->is_daemon = !opt_interactive;
monitor->parent_pid = main_ctx->parent_pid;
monitor->ev = main_ctx->event_ctx;
talloc_steal(main_ctx, monitor);
ret = monitor_process_init(monitor,
config_file);
if (ret != EOK) return 3;
talloc_free(tmp_ctx);
/* loop on main */
server_loop(main_ctx);
ret = monitor_cleanup();
if (ret != EOK) return 5;
return 0;
}