URL: https://github.com/SSSD/sssd/pull/274 Author: justin-stephenson Title: #274: Merge sss_cache and sss_debuglevel into sssctl Action: opened
PR body: """ Move `sss_cache` into a new command **sssctl expire-cache** and `sss_debuglevel` into new command **sssctl debug-level** for ticket https://pagure.io/SSSD/sssd/issue/3057 Shell redirect wrappers replace the `sss_{debuglevel,cache}` binaries and man pages updated to point admins towards the new **sssctl** commands. """ To pull the PR as Git branch: git remote add ghsssd https://github.com/SSSD/sssd git fetch ghsssd pull/274/head:pr274 git checkout pr274
From 31af2027a76cc02fa50f4852924007decafe4b83 Mon Sep 17 00:00:00 2001 From: Justin Stephenson <[email protected]> Date: Fri, 12 May 2017 14:08:37 -0400 Subject: [PATCH 1/4] SSSCTL: Add sss_cache shell wrapper The added sss_cache shell wrapper will be used to replace /usr/sbin/sss_cache binary to merge sss_cache into sssctl. The wrapper will redirect sss_cache to the sssctl expire-cache command performing the same task. The sss_cache(8) man page is updated to indicate that sss_cache is deprecated and functionality exists now in sssctl. Resolves: https://pagure.io/SSSD/sssd/issue/3057 --- Makefile.am | 2 + configure.ac | 1 + contrib/tools/sss_cache.in | 4 + src/man/sss_cache.8.xml | 194 +-------------------------------------------- 4 files changed, 11 insertions(+), 190 deletions(-) create mode 100644 contrib/tools/sss_cache.in diff --git a/Makefile.am b/Makefile.am index c947e31..491bfe3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -456,6 +456,8 @@ dist_noinst_SCRIPTS = \ src/tests/krb5_proxy_check_test_data.conf \ $(NULL) +dist_sbin_SCRIPTS = contrib/tools/sss_cache + dist_noinst_DATA = \ src/config/testconfigs/sssd-valid.conf \ src/config/testconfigs/noparse.api.conf \ diff --git a/configure.ac b/configure.ac index 80d8ea9..1dfa2d2 100644 --- a/configure.ac +++ b/configure.ac @@ -504,5 +504,6 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config src/lib/sifp/sss_simpleifp.doxy src/config/setup.py src/systemtap/sssd.stp + contrib/tools/sss_cache src/config/SSSDConfig/__init__.py]) AC_OUTPUT diff --git a/contrib/tools/sss_cache.in b/contrib/tools/sss_cache.in new file mode 100644 index 0000000..a576e85 --- /dev/null +++ b/contrib/tools/sss_cache.in @@ -0,0 +1,4 @@ +#!/bin/sh +sbindir=@sbindir@ +echo "Redirecting to $sbindir/sssctl expire-cache" +$sbindir/sssctl expire-cache $@ diff --git a/src/man/sss_cache.8.xml b/src/man/sss_cache.8.xml index 221c0a8..6d918ac 100644 --- a/src/man/sss_cache.8.xml +++ b/src/man/sss_cache.8.xml @@ -13,7 +13,7 @@ <refnamediv id='name'> <refname>sss_cache</refname> - <refpurpose>perform cache cleanup</refpurpose> + <refpurpose>[DEPRECATED] perform cache cleanup</refpurpose> </refnamediv> <refsynopsisdiv id='synopsis'> @@ -28,198 +28,12 @@ <refsect1 id='description'> <title>DESCRIPTION</title> <para> - <command>sss_cache</command> invalidates records in SSSD cache. - Invalidated records are forced to be reloaded from server as soon - as related SSSD backend is online. Options that invalidate a single - object only accept a single provided argument. + <command>sss_cache</command> is deprecated and replaced by + the sssctl expire-cache command. Please refer to the + <command>sssctl(8)</command> man page for more information on sssctl usage. </para> </refsect1> - <refsect1 id='options'> - <title>OPTIONS</title> - <variablelist remap='IP'> - <varlistentry> - <term> - <option>-E</option>,<option>--everything</option> - </term> - <listitem> - <para> - Invalidate all cached entries. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <option>-u</option>,<option>--user</option> - <replaceable>login</replaceable> - </term> - <listitem> - <para> - Invalidate specific user. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <option>-U</option>,<option>--users</option> - </term> - <listitem> - <para> - Invalidate all user records. This option overrides - invalidation of specific user if it was also set. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <option>-g</option>,<option>--group</option> - <replaceable>group</replaceable> - </term> - <listitem> - <para> - Invalidate specific group. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <option>-G</option>,<option>--groups</option> - </term> - <listitem> - <para> - Invalidate all group records. This option overrides - invalidation of specific group if it was also set. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <option>-n</option>,<option>--netgroup</option> - <replaceable>netgroup</replaceable> - </term> - <listitem> - <para> - Invalidate specific netgroup. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <option>-N</option>,<option>--netgroups</option> - </term> - <listitem> - <para> - Invalidate all netgroup records. This option overrides - invalidation of specific netgroup if it was also set. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <option>-s</option>,<option>--service</option> - <replaceable>service</replaceable> - </term> - <listitem> - <para> - Invalidate specific service. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <option>-S</option>,<option>--services</option> - </term> - <listitem> - <para> - Invalidate all service records. This option overrides - invalidation of specific service if it was also set. - </para> - </listitem> - </varlistentry> - <varlistentry condition="with_autofs"> - <term> - <option>-a</option>,<option>--autofs-map</option> - <replaceable>autofs-map</replaceable> - </term> - <listitem> - <para> - Invalidate specific autofs maps. - </para> - </listitem> - </varlistentry> - <varlistentry condition="with_autofs"> - <term> - <option>-A</option>,<option>--autofs-maps</option> - </term> - <listitem> - <para> - Invalidate all autofs maps. This option overrides - invalidation of specific map if it was also set. - </para> - </listitem> - </varlistentry> - <varlistentry condition="with_ssh"> - <term> - <option>-h</option>,<option>--ssh-host</option> - <replaceable>hostname</replaceable> - </term> - <listitem> - <para> - Invalidate SSH public keys of a specific host. - </para> - </listitem> - </varlistentry> - <varlistentry condition="with_ssh"> - <term> - <option>-H</option>,<option>--ssh-hosts</option> - </term> - <listitem> - <para> - Invalidate SSH public keys of all hosts. This option - overrides invalidation of SSH public keys of specific - host if it was also set. - </para> - </listitem> - </varlistentry> - <varlistentry condition="with_sudo"> - <term> - <option>-r</option>,<option>--sudo-rule</option> - <replaceable>rule</replaceable> - </term> - <listitem> - <para> - Invalidate particular sudo rule. - </para> - </listitem> - </varlistentry> - <varlistentry condition="with_sudo"> - <term> - <option>-R</option>,<option>--sudo-rules</option> - </term> - <listitem> - <para> - Invalidate all cached sudo rules. This option - overrides invalidation of specific sudo rule - if it was also set. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <option>-d</option>,<option>--domain</option> - <replaceable>domain</replaceable> - </term> - <listitem> - <para> - Restrict invalidation process only to a particular - domain. - </para> - </listitem> - </varlistentry> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/param_help.xml" /> - </variablelist> - </refsect1> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/seealso.xml" /> </refentry> From 6ad70639aa884fabde1dcf966d40b5530c8bd5c3 Mon Sep 17 00:00:00 2001 From: Justin Stephenson <[email protected]> Date: Fri, 12 May 2017 17:08:08 -0400 Subject: [PATCH 2/4] SSSCTL: Move sss_cache into sssctl expire-cache Move code from sss_cache to sssctl_cache and add new expire-cache sssctl command to perform the same invalidation of cache objects. POPT_CONTEXT_KEEP_FIRST Flag added to poptGetContext call in init_context() to fix argument parsing. Resolves: https://pagure.io/SSSD/sssd/issue/3057 --- Makefile.am | 13 +- po/POTFILES.in | 1 - src/tools/common/sss_tools.c | 6 - src/tools/common/sss_tools.h | 7 +- src/tools/sss_cache.c | 962 ---------------------------------------- src/tools/sssctl/sssctl.c | 3 +- src/tools/sssctl/sssctl.h | 4 + src/tools/sssctl/sssctl_cache.c | 916 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 930 insertions(+), 982 deletions(-) delete mode 100644 src/tools/sss_cache.c diff --git a/Makefile.am b/Makefile.am index 491bfe3..73b3153 100644 --- a/Makefile.am +++ b/Makefile.am @@ -141,7 +141,6 @@ sbin_PROGRAMS = \ sss_usermod \ sss_groupmod \ sss_groupshow \ - sss_cache \ sss_debuglevel \ sss_override \ sss_seed \ @@ -1672,15 +1671,6 @@ sss_groupshow_LDADD = \ $(TOOLS_LIBS) \ $(SSSD_INTERNAL_LTLIBS) -sss_cache_SOURCES = \ - src/tools/sss_cache.c \ - $(SSSD_LCL_TOOLS_OBJ) -sss_cache_LDADD = \ - $(TOOLS_LIBS) \ - $(SSSD_INTERNAL_LTLIBS) \ - $(CLIENT_LIBS) -sss_cache_CFLAGS = $(AM_CFLAGS) - sss_debuglevel_SOURCES = \ src/tools/sss_debuglevel.c \ $(SSSD_TOOLS_OBJ) @@ -1727,7 +1717,7 @@ sssctl_SOURCES = \ src/tools/sssctl/sssctl_sifp.c \ src/tools/sssctl/sssctl_config.c \ src/tools/sssctl/sssctl_user_checks.c \ - $(SSSD_TOOLS_OBJ) \ + $(SSSD_LCL_TOOLS_OBJ) \ $(NULL) sssctl_LDADD = \ $(TOOLS_LIBS) \ @@ -1735,6 +1725,7 @@ sssctl_LDADD = \ $(PAM_LIBS) \ $(PAM_MISC_LIBS) \ $(LIBADD_DL) \ + $(CLIENTS_LIBS) \ libsss_simpleifp.la \ $(NULL) sssctl_CFLAGS = \ diff --git a/po/POTFILES.in b/po/POTFILES.in index 33e7ed7..b928473 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -19,7 +19,6 @@ src/tools/sss_groupshow.c src/tools/sss_useradd.c src/tools/sss_userdel.c src/tools/sss_usermod.c -src/tools/sss_cache.c src/tools/sss_debuglevel.c src/tools/tools_util.c src/tools/tools_util.h diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c index 97a3caa..d6ae726 100644 --- a/src/tools/common/sss_tools.c +++ b/src/tools/common/sss_tools.c @@ -30,12 +30,6 @@ #include "db/sysdb.h" #include "tools/common/sss_tools.h" -struct sss_cmdline { - const char *exec; /* argv[0] */ - const char *command; /* command name */ - int argc; /* rest of arguments */ - const char **argv; -}; static void sss_tool_print_common_opts(int min_len) { diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h index 49da7d6..8480093 100644 --- a/src/tools/common/sss_tools.h +++ b/src/tools/common/sss_tools.h @@ -38,7 +38,12 @@ errno_t sss_tool_init(TALLOC_CTX *mem_ctx, int *argc, const char **argv, struct sss_tool_ctx **_tool_ctx); -struct sss_cmdline; +struct sss_cmdline { + const char *exec; /* argv[0] */ + const char *command; /* command name */ + int argc; /* rest of arguments */ + const char **argv; +}; typedef errno_t (*sss_route_fn)(struct sss_cmdline *cmdline, diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c deleted file mode 100644 index 8a40b38..0000000 --- a/src/tools/sss_cache.c +++ /dev/null @@ -1,962 +0,0 @@ -/* - SSSD - - sss_cache - - Copyright (C) Jan Zeleny <[email protected]> 2011 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <talloc.h> -#include <popt.h> -#include <sys/types.h> - -#include "util/util.h" -#include "tools/sss_sync_ops.h" -#include "db/sysdb.h" -#include "db/sysdb_services.h" -#include "db/sysdb_autofs.h" -#include "db/sysdb_ssh.h" -#include "db/sysdb_sudo.h" - -#define INVALIDATE_NONE 0 -#define INVALIDATE_USERS 1 -#define INVALIDATE_GROUPS 2 -#define INVALIDATE_NETGROUPS 4 -#define INVALIDATE_SERVICES 8 -#define INVALIDATE_AUTOFSMAPS 16 -#define INVALIDATE_SSH_HOSTS 32 -#define INVALIDATE_SUDO_RULES 64 - -#ifdef BUILD_AUTOFS -#ifdef BUILD_SSH -#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \ - INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \ - INVALIDATE_AUTOFSMAPS | INVALIDATE_SSH_HOSTS ) -#else /* BUILD_SSH */ -#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \ - INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \ - INVALIDATE_AUTOFSMAPS ) -#endif /* BUILD_SSH */ -#else /* BUILD_AUTOFS */ -#ifdef BUILD_SSH -#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \ - INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \ - INVALIDATE_SSH_HOSTS ) -#else /* BUILD_SSH */ -#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \ - INVALIDATE_NETGROUPS | INVALIDATE_SERVICES ) -#endif /* BUILD_SSH */ -#endif /* BUILD_AUTOFS */ - -enum sss_cache_entry { - TYPE_USER=0, - TYPE_GROUP, - TYPE_NETGROUP, - TYPE_SERVICE, - TYPE_AUTOFSMAP, - TYPE_SSH_HOST, - TYPE_SUDO_RULE -}; - -static errno_t search_autofsmaps(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - const char *sub_filter, const char **attrs, - size_t *msgs_count, struct ldb_message ***msgs); - -struct input_values { - char *domain; - char *group; - char *map; - char *netgroup; - char *service; - char *ssh_host; - char *sudo_rule; - char *user; -}; - -struct cache_tool_ctx { - struct confdb_ctx *confdb; - struct sss_domain_info *domains; - - char *user_filter; - char *group_filter; - char *netgroup_filter; - char *service_filter; - char *autofs_filter; - char *ssh_host_filter; - char *sudo_rule_filter; - - char *user_name; - char *group_name; - char *netgroup_name; - char *service_name; - char *autofs_name; - char *ssh_host_name; - char *sudo_rule_name; - - bool update_user_filter; - bool update_group_filter; - bool update_netgroup_filter; - bool update_service_filter; - bool update_autofs_filter; - bool update_ssh_host_filter; - bool update_sudo_rule_filter; -}; - -static void free_input_values(struct input_values *values); -static bool is_filter_valid(struct cache_tool_ctx *ctx, - struct input_values *values, int idb); -static errno_t init_domains(struct cache_tool_ctx *ctx, - const char *domain); -static errno_t init_context(int argc, const char *argv[], - struct cache_tool_ctx **tctx); -static errno_t invalidate_entry(TALLOC_CTX *ctx, - struct sss_domain_info *domain, - const char *name, int entry_type); -static bool invalidate_entries(TALLOC_CTX *ctx, - struct sss_domain_info *dinfo, - enum sss_cache_entry entry_type, - const char *filter, const char *name); -static errno_t update_all_filters(struct cache_tool_ctx *tctx, - struct sss_domain_info *dinfo); -static int sysdb_invalidate_user_cache_entry(struct sss_domain_info *domain, - const char *name); -static int sysdb_invalidate_group_cache_entry(struct sss_domain_info *domain, - const char *name); - -int main(int argc, const char *argv[]) -{ - errno_t ret; - struct cache_tool_ctx *tctx = NULL; - struct sysdb_ctx *sysdb; - bool skipped = true; - struct sss_domain_info *dinfo; - - ret = init_context(argc, argv, &tctx); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Error initializing context for the application\n"); - goto done; - } - - for (dinfo = tctx->domains; dinfo; - dinfo = get_next_domain(dinfo, SSS_GND_DESCEND)) { - if (!IS_SUBDOMAIN(dinfo)) { - /* Update list of subdomains for this domain */ - ret = sysdb_update_subdomains(dinfo, tctx->confdb); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Failed to update subdomains for domain %s.\n", dinfo->name); - } - } - - sysdb = dinfo->sysdb; - /* Update filters for each domain */ - ret = update_all_filters(tctx, dinfo); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to update filters.\n"); - goto done; - } - - ret = sysdb_transaction_start(sysdb); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not start the transaction!\n"); - goto done; - } - - skipped &= !invalidate_entries(tctx, dinfo, TYPE_USER, - tctx->user_filter, - tctx->user_name); - skipped &= !invalidate_entries(tctx, dinfo, TYPE_GROUP, - tctx->group_filter, - tctx->group_name); - skipped &= !invalidate_entries(tctx, dinfo, TYPE_NETGROUP, - tctx->netgroup_filter, - tctx->netgroup_name); - skipped &= !invalidate_entries(tctx, dinfo, TYPE_SERVICE, - tctx->service_filter, - tctx->service_name); - skipped &= !invalidate_entries(tctx, dinfo, TYPE_AUTOFSMAP, - tctx->autofs_filter, - tctx->autofs_name); - skipped &= !invalidate_entries(tctx, dinfo, TYPE_SSH_HOST, - tctx->ssh_host_filter, - tctx->ssh_host_name); - skipped &= !invalidate_entries(tctx, dinfo, TYPE_SUDO_RULE, - tctx->sudo_rule_filter, - tctx->sudo_rule_name); - - ret = sysdb_transaction_commit(sysdb); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not commit the transaction!\n"); - ret = sysdb_transaction_cancel(sysdb); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Failed to cancel transaction\n"); - } - } - } - - if (skipped == true) { - ERROR("No cache object matched the specified search\n"); - ret = ENOENT; - goto done; - } else { - ret = sss_memcache_clear_all(); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to clear memory cache.\n"); - goto done; - } - } - - ret = EOK; -done: - if (tctx) talloc_free(tctx); - return ret; -} - -static void free_input_values(struct input_values *values) -{ - free(values->domain); - free(values->group); - free(values->map); - free(values->netgroup); - free(values->service); - free(values->ssh_host); - free(values->sudo_rule); - free(values->user); -} - -static errno_t update_filter(struct cache_tool_ctx *tctx, - struct sss_domain_info *dinfo, - char *name, bool update, const char *fmt, - enum sss_cache_entry entry_type, - bool force_case_sensitivity, - char **_filter) -{ - errno_t ret; - char *parsed_domain = NULL; - char *parsed_name = NULL; - TALLOC_CTX *tmp_ctx = NULL; - char *use_name = NULL; - char *filter; - char *sanitized; - char *lc_sanitized; - - if (!name || !update) { - /* Nothing to do */ - return EOK; - } - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n"); - return ENOMEM; - } - - ret = sss_parse_name(tmp_ctx, dinfo->names, name, - &parsed_domain, &parsed_name); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_name failed\n"); - goto done; - } - - if (parsed_domain != NULL && strcasecmp(dinfo->name, parsed_domain) != 0) { - /* We were able to parse the domain from given fqdn, but it - * does not match with currently processed domain. */ - filter = NULL; - ret = EOK; - goto done; - } - - if (!dinfo->case_sensitive && !force_case_sensitivity) { - use_name = sss_tc_utf8_str_tolower(tmp_ctx, parsed_name); - if (!use_name) { - DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n"); - ret = ENOMEM; - goto done; - } - } else { - use_name = parsed_name; - } - - switch (entry_type) { - case TYPE_USER: - case TYPE_GROUP: - use_name = sss_create_internal_fqname(tmp_ctx, use_name, dinfo->name); - default: - break; - } - if (!use_name) { - ret = ENOMEM; - goto done; - } - - ret = sss_filter_sanitize_for_dom(tmp_ctx, use_name, dinfo, - &sanitized, &lc_sanitized); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to sanitize the given name.\n"); - goto done; - } - - if (fmt) { - if (!dinfo->case_sensitive && !force_case_sensitivity) { - filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)(%s=%s))", - SYSDB_NAME_ALIAS, lc_sanitized, - SYSDB_NAME_ALIAS, sanitized); - } else { - filter = talloc_asprintf(tmp_ctx, fmt, SYSDB_NAME, sanitized); - } - } else { - filter = talloc_strdup(tmp_ctx, sanitized); - } - if (filter == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n"); - ret = ENOMEM; - goto done; - } - - ret = EOK; - -done: - if (ret == EOK) { - talloc_free(*_filter); - *_filter = talloc_steal(tctx, filter); - } - - talloc_free(tmp_ctx); - return ret; - -} - -/* This function updates all filters for specified domain using this - * domains regex to parse string into domain and name (if exists). */ -static errno_t update_all_filters(struct cache_tool_ctx *tctx, - struct sss_domain_info *dinfo) -{ - errno_t ret; - - /* Update user filter */ - ret = update_filter(tctx, dinfo, tctx->user_name, - tctx->update_user_filter, "(%s=%s)", - TYPE_USER, false, - &tctx->user_filter); - if (ret != EOK) { - return ret; - } - - /* Update group filter */ - ret = update_filter(tctx, dinfo, tctx->group_name, - tctx->update_group_filter, "(%s=%s)", - TYPE_GROUP, false, - &tctx->group_filter); - if (ret != EOK) { - return ret; - } - - /* Update netgroup filter */ - ret = update_filter(tctx, dinfo, tctx->netgroup_name, - tctx->update_netgroup_filter, "(%s=%s)", - TYPE_NETGROUP, false, - &tctx->netgroup_filter); - if (ret != EOK) { - return ret; - } - - /* Update service filter */ - ret = update_filter(tctx, dinfo, tctx->service_name, - tctx->update_service_filter, "(%s=%s)", - TYPE_SERVICE, false, - &tctx->service_filter); - if (ret != EOK) { - return ret; - } - - /* Update autofs filter */ - ret = update_filter(tctx, dinfo, tctx->autofs_name, - tctx->update_autofs_filter, - "(&(objectclass="SYSDB_AUTOFS_MAP_OC")(%s=%s))", - TYPE_AUTOFSMAP, true, - &tctx->autofs_filter); - if (ret != EOK) { - return ret; - } - - /* Update ssh host filter */ - ret = update_filter(tctx, dinfo, tctx->ssh_host_name, - tctx->update_ssh_host_filter, "(%s=%s)", - TYPE_SSH_HOST, false, - &tctx->ssh_host_filter); - if (ret != EOK) { - return ret; - } - - /* Update sudo rule filter */ - ret = update_filter(tctx, dinfo, tctx->sudo_rule_name, - tctx->update_sudo_rule_filter, - "(%s=%s)", TYPE_SUDO_RULE, false, - &tctx->sudo_rule_filter); - if (ret != EOK) { - return ret; - } - - return EOK; -} - -static bool invalidate_entries(TALLOC_CTX *ctx, - struct sss_domain_info *dinfo, - enum sss_cache_entry entry_type, - const char *filter, const char *name) -{ - const char *attrs[] = {SYSDB_NAME, NULL}; - size_t msg_count; - struct ldb_message **msgs; - const char *type_string = "unknown"; - errno_t ret = EINVAL; - int i; - const char *c_name; - bool iret; - - if (!filter) return false; - switch (entry_type) { - case TYPE_USER: - type_string = "user"; - ret = sysdb_search_users(ctx, dinfo, - filter, attrs, &msg_count, &msgs); - break; - case TYPE_GROUP: - type_string = "group"; - ret = sysdb_search_groups(ctx, dinfo, - filter, attrs, &msg_count, &msgs); - break; - case TYPE_NETGROUP: - type_string = "netgroup"; - ret = sysdb_search_netgroups(ctx, dinfo, - filter, attrs, &msg_count, &msgs); - break; - case TYPE_SERVICE: - type_string = "service"; - ret = sysdb_search_services(ctx, dinfo, - filter, attrs, &msg_count, &msgs); - break; - case TYPE_AUTOFSMAP: - type_string = "autofs map"; - ret = search_autofsmaps(ctx, dinfo, filter, attrs, &msg_count, &msgs); - break; - case TYPE_SSH_HOST: - type_string = "ssh_host"; -#ifdef BUILD_SSH - ret = sysdb_search_ssh_hosts(ctx, dinfo, - filter, attrs, &msg_count, &msgs); -#else /* BUILD_SSH */ - ret = ENOSYS; -#endif /* BUILD_SSH */ - break; - case TYPE_SUDO_RULE: - type_string = "sudo_rule"; -#ifdef BUILD_SUDO - ret = sysdb_search_sudo_rules(ctx, dinfo, - filter, attrs, &msg_count, &msgs); -#else /* BUILD_SUDO */ - ret = ENOSYS; -#endif /* BUILD_SUDO */ - break; - } - - if (ret != EOK) { - if (ret == ENOENT) { - DEBUG(SSSDBG_TRACE_FUNC, "'%s' %s: Not found in domain '%s'\n", - type_string, name ? name : "", dinfo->name); - } else { - DEBUG(SSSDBG_CRIT_FAILURE, - "Searching for %s in domain %s with filter %s failed\n", - type_string, dinfo->name, filter); - } - return false; - } - - iret = true; - for (i = 0; i < msg_count; i++) { - c_name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL); - if (c_name == NULL) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Something bad happened, can't find attribute %s\n", - SYSDB_NAME); - ERROR("Couldn't invalidate %1$s\n", type_string); - iret = false; - } else { - ret = invalidate_entry(ctx, dinfo, c_name, entry_type); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Couldn't invalidate %s %s\n", type_string, c_name); - ERROR("Couldn't invalidate %1$s %2$s\n", type_string, c_name); - iret = false; - } - } - } - talloc_zfree(msgs); - return iret; -} - -static errno_t invalidate_entry(TALLOC_CTX *ctx, - struct sss_domain_info *domain, - const char *name, int entry_type) -{ - struct sysdb_attrs *sys_attrs = NULL; - errno_t ret; - - sys_attrs = sysdb_new_attrs(ctx); - if (sys_attrs) { - ret = sysdb_attrs_add_time_t(sys_attrs, - SYSDB_CACHE_EXPIRE, 1); - if (ret == EOK) { - switch (entry_type) { - case TYPE_USER: - /* For users, we also need to reset the initgroups - * cache expiry */ - ret = sysdb_attrs_add_time_t(sys_attrs, - SYSDB_INITGR_EXPIRE, 1); - if (ret != EOK) return ret; - - ret = sysdb_set_user_attr(domain, name, sys_attrs, - SYSDB_MOD_REP); - if (ret != EOK) break; - - /* WARNING: Direct writing to persistent cache!! */ - ret = sysdb_invalidate_user_cache_entry(domain, name); - break; - case TYPE_GROUP: - ret = sysdb_set_group_attr(domain, name, sys_attrs, - SYSDB_MOD_REP); - if (ret != EOK) break; - - /* WARNING: Direct writing to persistent cache!! */ - ret = sysdb_invalidate_group_cache_entry(domain, name); - break; - case TYPE_NETGROUP: - ret = sysdb_set_netgroup_attr(domain, name, sys_attrs, - SYSDB_MOD_REP); - break; - case TYPE_SERVICE: - ret = sysdb_set_service_attr(domain, name, - sys_attrs, SYSDB_MOD_REP); - break; - case TYPE_AUTOFSMAP: - ret = sysdb_set_autofsmap_attr(domain, name, - sys_attrs, SYSDB_MOD_REP); - break; - case TYPE_SSH_HOST: -#ifdef BUILD_SSH - ret = sysdb_set_ssh_host_attr(domain, name, - sys_attrs, SYSDB_MOD_REP); -#else /* BUILD_SSH */ - ret = ENOSYS; -#endif /* BUILD_SSH */ - break; - case TYPE_SUDO_RULE: -#ifdef BUILD_SUDO - ret = sysdb_set_sudo_rule_attr(domain, name, - sys_attrs, SYSDB_MOD_REP); -#else /* BUILD_SUDO */ - ret = ENOSYS; -#endif /* BUILD_SUDO */ - break; - default: - return EINVAL; - } - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, "Could not set entry attributes\n"); - } - } else { - DEBUG(SSSDBG_MINOR_FAILURE, - "Could not add expiration time to attributes\n"); - } - talloc_zfree(sys_attrs); - } else { - DEBUG(SSSDBG_MINOR_FAILURE, "Could not create sysdb attributes\n"); - ret = ENOMEM; - } - return ret; -} - -static errno_t init_domains(struct cache_tool_ctx *ctx, - const char *domain) -{ - char *confdb_path; - int ret; - struct sss_domain_info *dinfo; - - confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE); - if (confdb_path == NULL) { - return ENOMEM; - } - - /* Connect to the conf db */ - ret = confdb_init(ctx, &ctx->confdb, confdb_path); - talloc_free(confdb_path); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not initialize connection to the confdb\n"); - return ret; - } - - if (domain) { - ret = sssd_domain_init(ctx, ctx->confdb, - domain, DB_PATH, &ctx->domains); - if (ret != EOK) { - SYSDB_VERSION_ERROR(ret); - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not initialize connection to the sysdb\n"); - return ret; - } - - } else { - ret = confdb_get_domains(ctx->confdb, &ctx->domains); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Could not initialize domains\n"); - return ret; - } - - ret = sysdb_init(ctx, ctx->domains); - SYSDB_VERSION_ERROR(ret); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not initialize connection to the sysdb\n"); - return ret; - } - } - - for (dinfo = ctx->domains; dinfo; dinfo = get_next_domain(dinfo, 0)) { - ret = sss_names_init(ctx, ctx->confdb, dinfo->name, &dinfo->names); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "sss_names_init() failed\n"); - return ret; - } - } - - return EOK; -} - -static errno_t init_context(int argc, const char *argv[], - struct cache_tool_ctx **tctx) -{ - struct cache_tool_ctx *ctx = NULL; - int idb = INVALIDATE_NONE; - struct input_values values = { 0 }; - int debug = SSSDBG_DEFAULT; - errno_t ret = EOK; - - poptContext pc = NULL; - struct poptOption long_options[] = { - POPT_AUTOHELP - { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &debug, - 0, _("The debug level to run with"), NULL }, - { "everything", 'E', POPT_ARG_NONE, NULL, 'e', - _("Invalidate all cached entries"), NULL }, - { "user", 'u', POPT_ARG_STRING, &(values.user), 0, - _("Invalidate particular user"), NULL }, - { "users", 'U', POPT_ARG_NONE, NULL, 'u', - _("Invalidate all users"), NULL }, - { "group", 'g', POPT_ARG_STRING, &(values.group), 0, - _("Invalidate particular group"), NULL }, - { "groups", 'G', POPT_ARG_NONE, NULL, 'g', - _("Invalidate all groups"), NULL }, - { "netgroup", 'n', POPT_ARG_STRING, &(values.netgroup), 0, - _("Invalidate particular netgroup"), NULL }, - { "netgroups", 'N', POPT_ARG_NONE, NULL, 'n', - _("Invalidate all netgroups"), NULL }, - { "service", 's', POPT_ARG_STRING, &(values.service), 0, - _("Invalidate particular service"), NULL }, - { "services", 'S', POPT_ARG_NONE, NULL, 's', - _("Invalidate all services"), NULL }, -#ifdef BUILD_AUTOFS - { "autofs-map", 'a', POPT_ARG_STRING, &(values.map), 0, - _("Invalidate particular autofs map"), NULL }, - { "autofs-maps", 'A', POPT_ARG_NONE, NULL, 'a', - _("Invalidate all autofs maps"), NULL }, -#endif /* BUILD_AUTOFS */ -#ifdef BUILD_SSH - { "ssh-host", 'h', POPT_ARG_STRING, &(values.ssh_host), 0, - _("Invalidate particular SSH host"), NULL }, - { "ssh-hosts", 'H', POPT_ARG_NONE, NULL, 'h', - _("Invalidate all SSH hosts"), NULL }, -#endif /* BUILD_SSH */ -#ifdef BUILD_SUDO - { "sudo-rule", 'r', POPT_ARG_STRING, &(values.sudo_rule), 0, - _("Invalidate particular sudo rule"), NULL }, - { "sudo-rules", 'R', POPT_ARG_NONE, NULL, 'r', - _("Invalidate all cached sudo rules"), NULL }, -#endif /* BUILD_SUDO */ - { "domain", 'd', POPT_ARG_STRING, &(values.domain), 0, - _("Only invalidate entries from a particular domain"), NULL }, - POPT_TABLEEND - }; - - ret = set_locale(); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "set_locale failed (%d): %s\n", ret, strerror(ret)); - ERROR("Error setting the locale\n"); - goto fini; - } - - pc = poptGetContext(NULL, argc, argv, long_options, 0); - while ((ret = poptGetNextOpt(pc)) > 0) { - switch (ret) { - case 'u': - idb |= INVALIDATE_USERS; - break; - case 'g': - idb |= INVALIDATE_GROUPS; - break; - case 'n': - idb |= INVALIDATE_NETGROUPS; - break; - case 's': - idb |= INVALIDATE_SERVICES; - break; - case 'a': - idb |= INVALIDATE_AUTOFSMAPS; - break; - case 'h': - idb |= INVALIDATE_SSH_HOSTS; - break; - case 'r': - idb |= INVALIDATE_SUDO_RULES; - break; - case 'e': - idb = INVALIDATE_EVERYTHING; -#ifdef BUILD_SUDO - idb |= INVALIDATE_SUDO_RULES; -#endif /* BUILD_SUDO */ - break; - } - } - - DEBUG_CLI_INIT(debug); - debug_prg_name = argv[0]; - - if (ret != -1) { - BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini); - } - - if (poptGetArg(pc)) { - BAD_POPT_PARAMS(pc, - _("Unexpected argument(s) provided, options that " - "invalidate a single object only accept a single " - "provided argument.\n"), - ret, fini); - } - - if (idb == INVALIDATE_NONE && !values.user && !values.group && - !values.netgroup && !values.service && !values.map && - !values.ssh_host && !values.sudo_rule) { - BAD_POPT_PARAMS(pc, - _("Please select at least one object to invalidate\n"), - ret, fini); - } - - CHECK_ROOT(ret, debug_prg_name); - - ctx = talloc_zero(NULL, struct cache_tool_ctx); - if (ctx == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not allocate memory for tools context\n"); - ret = ENOMEM; - goto fini; - } - - if (idb & INVALIDATE_USERS) { - ctx->user_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); - ctx->update_user_filter = false; - } else if (values.user) { - ctx->user_name = talloc_strdup(ctx, values.user); - ctx->update_user_filter = true; - } - - if (idb & INVALIDATE_GROUPS) { - ctx->group_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); - ctx->update_group_filter = false; - } else if (values.group) { - ctx->group_name = talloc_strdup(ctx, values.group); - ctx->update_group_filter = true; - } - - if (idb & INVALIDATE_NETGROUPS) { - ctx->netgroup_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); - ctx->update_netgroup_filter = false; - } else if (values.netgroup) { - ctx->netgroup_name = talloc_strdup(ctx, values.netgroup); - ctx->update_netgroup_filter = true; - } - - if (idb & INVALIDATE_SERVICES) { - ctx->service_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); - ctx->update_service_filter = false; - } else if (values.service) { - ctx->service_name = talloc_strdup(ctx, values.service); - ctx->update_service_filter = true; - } - - if (idb & INVALIDATE_AUTOFSMAPS) { - ctx->autofs_filter = talloc_asprintf(ctx, "(&(objectclass=%s)(%s=*))", - SYSDB_AUTOFS_MAP_OC, SYSDB_NAME); - ctx->update_autofs_filter = false; - } else if (values.map) { - ctx->autofs_name = talloc_strdup(ctx, values.map); - ctx->update_autofs_filter = true; - } - - if (idb & INVALIDATE_SSH_HOSTS) { - ctx->ssh_host_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); - ctx->update_ssh_host_filter = false; - } else if (values.ssh_host) { - ctx->ssh_host_name = talloc_strdup(ctx, values.ssh_host); - ctx->update_ssh_host_filter = true; - } - - if (idb & INVALIDATE_SUDO_RULES) { - ctx->sudo_rule_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); - ctx->update_sudo_rule_filter = false; - } else if (values.sudo_rule) { - ctx->sudo_rule_name = talloc_strdup(ctx, values.sudo_rule); - ctx->update_sudo_rule_filter = true; - } - - if (is_filter_valid(ctx, &values, idb) == false) { - DEBUG(SSSDBG_CRIT_FAILURE, "Construction of filters failed\n"); - ret = ENOMEM; - goto fini; - } - - ret = init_domains(ctx, values.domain); - if (ret != EOK) { - if (values.domain) { - ERROR("Could not open domain %1$s. If the domain is a subdomain " - "(trusted domain), use fully qualified name instead of " - "--domain/-d parameter.\n", values.domain); - } else { - ERROR("Could not open available domains\n"); - } - DEBUG(SSSDBG_OP_FAILURE, - "Initialization of sysdb connections failed\n"); - goto fini; - } - - ret = EOK; - -fini: - poptFreeContext(pc); - free_input_values(&values); - if (ret != EOK && ctx) { - talloc_zfree(ctx); - } - if (ret == EOK) { - *tctx = ctx; - } - return ret; -} - -static bool is_filter_valid(struct cache_tool_ctx *ctx, - struct input_values *values, int idb) -{ - if ((idb & INVALIDATE_USERS) && ctx->user_filter == NULL) { - return false; - } - - if ((idb & INVALIDATE_GROUPS) && ctx->group_filter == NULL) { - return false; - } - - if ((idb & INVALIDATE_NETGROUPS) && ctx->netgroup_filter == NULL) { - return false; - } - - if ((idb & INVALIDATE_SERVICES) && ctx->service_filter == NULL) { - return false; - } - - if ((idb & INVALIDATE_AUTOFSMAPS) && ctx->autofs_filter == NULL) { - return false; - } - - if ((idb & INVALIDATE_SSH_HOSTS) && ctx->ssh_host_filter == NULL) { - return false; - } - - if (values->user && ctx->user_name == NULL) { - return false; - } - - if (values->group && ctx->group_name == NULL) { - return false; - } - - if (values->netgroup && ctx->netgroup_name == NULL) { - return false; - } - - if (values->service && ctx->service_name == NULL) { - return false; - } - - if (values->map && ctx->autofs_name == NULL) { - return false; - } - - if (values->ssh_host && ctx->ssh_host_name == NULL) { - return false; - } - - if (values->sudo_rule && ctx->sudo_rule_name == NULL) { - return false; - } - - return true; -} - -static errno_t -search_autofsmaps(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - const char *sub_filter, const char **attrs, - size_t *msgs_count, struct ldb_message ***msgs) -{ -#ifdef BUILD_AUTOFS - return sysdb_search_custom(mem_ctx, domain, sub_filter, - AUTOFS_MAP_SUBDIR, attrs, - msgs_count, msgs); -#else - return ENOSYS; -#endif /* BUILD_AUTOFS */ -} - -/* WARNING: Direct writing to persistent cache!! */ -static int sysdb_invalidate_user_cache_entry(struct sss_domain_info *domain, - const char *name) -{ - return sysdb_invalidate_cache_entry(domain, name, true); -} - -/* WARNING: Direct writing to persistent cache!! */ -static int sysdb_invalidate_group_cache_entry(struct sss_domain_info *domain, - const char *name) -{ - return sysdb_invalidate_cache_entry(domain, name, false); -} diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c index 509d2e1..d0bf752 100644 --- a/src/tools/sssctl/sssctl.c +++ b/src/tools/sssctl/sssctl.c @@ -264,10 +264,11 @@ int main(int argc, const char **argv) SSS_TOOL_COMMAND("domain-list", "List available domains", 0, sssctl_domain_list), SSS_TOOL_COMMAND("domain-status", "Print information about domain", 0, sssctl_domain_status), SSS_TOOL_COMMAND("user-checks", "Print information about a user and check authentication", 0, sssctl_user_checks), - SSS_TOOL_DELIMITER("Information about cached content:"), + SSS_TOOL_DELIMITER("Cached Content tools:"), SSS_TOOL_COMMAND("user-show", "Information about cached user", 0, sssctl_user_show), SSS_TOOL_COMMAND("group-show", "Information about cached group", 0, sssctl_group_show), SSS_TOOL_COMMAND("netgroup-show", "Information about cached netgroup", 0, sssctl_netgroup_show), + SSS_TOOL_COMMAND("expire-cache", "Invalidate cached objects", 0, sssctl_expire_cache), SSS_TOOL_DELIMITER("Local data tools:"), SSS_TOOL_COMMAND("client-data-backup", "Backup local data", 0, sssctl_client_data_backup), SSS_TOOL_COMMAND("client-data-restore", "Restore local data from backup", 0, sssctl_client_data_restore), diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h index 22626e2..dd7e039 100644 --- a/src/tools/sssctl/sssctl.h +++ b/src/tools/sssctl/sssctl.h @@ -118,6 +118,10 @@ errno_t sssctl_netgroup_show(struct sss_cmdline *cmdline, struct sss_tool_ctx *tool_ctx, void *pvt); +errno_t sssctl_expire_cache(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + errno_t sssctl_config_check(struct sss_cmdline *cmdline, struct sss_tool_ctx *tool_ctx, void *pvt); diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c index 8f0fc28..cc75f00 100644 --- a/src/tools/sssctl/sssctl_cache.c +++ b/src/tools/sssctl/sssctl_cache.c @@ -22,11 +22,19 @@ #include <stdio.h> #include <time.h> #include <errno.h> +#include <stdlib.h> +#include <talloc.h> +#include <sys/types.h> #include "util/util.h" #include "db/sysdb.h" +#include "db/sysdb_services.h" +#include "db/sysdb_autofs.h" +#include "db/sysdb_ssh.h" +#include "db/sysdb_sudo.h" #include "tools/common/sss_tools.h" #include "tools/sssctl/sssctl.h" +#include "tools/sss_sync_ops.h" #define NOT_FOUND_MSG(obj) _(obj " %s is not present in cache.\n") @@ -37,12 +45,52 @@ #define SSSCTL_CACHE_IFP {_("Cached in InfoPipe"), SYSDB_IFP_CACHED, attr_yesno} #define SSSCTL_CACHE_NULL {NULL, NULL, NULL} +#define INVALIDATE_NONE 0 +#define INVALIDATE_USERS 1 +#define INVALIDATE_GROUPS 2 +#define INVALIDATE_NETGROUPS 4 +#define INVALIDATE_SERVICES 8 +#define INVALIDATE_AUTOFSMAPS 16 +#define INVALIDATE_SSH_HOSTS 32 +#define INVALIDATE_SUDO_RULES 64 + +#ifdef BUILD_AUTOFS +#ifdef BUILD_SSH +#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \ + INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \ + INVALIDATE_AUTOFSMAPS | INVALIDATE_SSH_HOSTS ) +#else /* BUILD_SSH */ +#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \ + INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \ + INVALIDATE_AUTOFSMAPS ) +#endif /* BUILD_SSH */ +#else /* BUILD_AUTOFS */ +#ifdef BUILD_SSH +#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \ + INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \ + INVALIDATE_SSH_HOSTS ) +#else /* BUILD_SSH */ +#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \ + INVALIDATE_NETGROUPS | INVALIDATE_SERVICES ) +#endif /* BUILD_SSH */ +#endif /* BUILD_AUTOFS */ + enum cache_object { CACHED_USER, CACHED_GROUP, CACHED_NETGROUP, }; +enum sss_cache_entry { + TYPE_USER=0, + TYPE_GROUP, + TYPE_NETGROUP, + TYPE_SERVICE, + TYPE_AUTOFSMAP, + TYPE_SSH_HOST, + TYPE_SUDO_RULE +}; + typedef errno_t (*sssctl_attr_fn)(TALLOC_CTX *mem_ctx, struct sysdb_attrs *entry, struct sss_domain_info *dom, @@ -58,6 +106,779 @@ struct sssctl_object_info { sssctl_attr_fn attr_fn; }; +struct input_values { + char *domain; + char *group; + char *map; + char *netgroup; + char *service; + char *ssh_host; + char *sudo_rule; + char *user; +}; + +struct cache_tool_ctx { + struct confdb_ctx *confdb; + struct sss_domain_info *domains; + + char *user_filter; + char *group_filter; + char *netgroup_filter; + char *service_filter; + char *autofs_filter; + char *ssh_host_filter; + char *sudo_rule_filter; + + char *user_name; + char *group_name; + char *netgroup_name; + char *service_name; + char *autofs_name; + char *ssh_host_name; + char *sudo_rule_name; + + bool update_user_filter; + bool update_group_filter; + bool update_netgroup_filter; + bool update_service_filter; + bool update_autofs_filter; + bool update_ssh_host_filter; + bool update_sudo_rule_filter; +}; + +static void free_input_values(struct input_values *values) +{ + free(values->domain); + free(values->group); + free(values->map); + free(values->netgroup); + free(values->service); + free(values->ssh_host); + free(values->sudo_rule); + free(values->user); +} + +static errno_t +search_autofsmaps(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *sub_filter, const char **attrs, + size_t *msgs_count, struct ldb_message ***msgs) +{ +#ifdef BUILD_AUTOFS + return sysdb_search_custom(mem_ctx, domain, sub_filter, + AUTOFS_MAP_SUBDIR, attrs, + msgs_count, msgs); +#else + return ENOSYS; +#endif /* BUILD_AUTOFS */ +} + +/* WARNING: Direct writing to persistent cache!! */ +static int sysdb_invalidate_user_cache_entry(struct sss_domain_info *domain, + const char *name) +{ + return sysdb_invalidate_cache_entry(domain, name, true); +} + +/* WARNING: Direct writing to persistent cache!! */ +static int sysdb_invalidate_group_cache_entry(struct sss_domain_info *domain, + const char *name) +{ + return sysdb_invalidate_cache_entry(domain, name, false); +} + +static errno_t update_filter(struct cache_tool_ctx *tctx, + struct sss_domain_info *dinfo, + char *name, bool update, const char *fmt, + enum sss_cache_entry entry_type, + bool force_case_sensitivity, + char **_filter) +{ + errno_t ret; + char *parsed_domain = NULL; + char *parsed_name = NULL; + TALLOC_CTX *tmp_ctx = NULL; + char *use_name = NULL; + char *filter; + char *sanitized; + char *lc_sanitized; + + if (!name || !update) { + /* Nothing to do */ + return EOK; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n"); + return ENOMEM; + } + + ret = sss_parse_name(tmp_ctx, dinfo->names, name, + &parsed_domain, &parsed_name); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_name failed\n"); + goto done; + } + + if (parsed_domain != NULL && strcasecmp(dinfo->name, parsed_domain) != 0) { + /* We were able to parse the domain from given fqdn, but it + * does not match with currently processed domain. */ + filter = NULL; + ret = EOK; + goto done; + } + + if (!dinfo->case_sensitive && !force_case_sensitivity) { + use_name = sss_tc_utf8_str_tolower(tmp_ctx, parsed_name); + if (!use_name) { + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n"); + ret = ENOMEM; + goto done; + } + } else { + use_name = parsed_name; + } + + switch (entry_type) { + case TYPE_USER: + case TYPE_GROUP: + use_name = sss_create_internal_fqname(tmp_ctx, use_name, dinfo->name); + default: + break; + } + if (!use_name) { + ret = ENOMEM; + goto done; + } + + ret = sss_filter_sanitize_for_dom(tmp_ctx, use_name, dinfo, + &sanitized, &lc_sanitized); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to sanitize the given name.\n"); + goto done; + } + + if (fmt) { + if (!dinfo->case_sensitive && !force_case_sensitivity) { + filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)(%s=%s))", + SYSDB_NAME_ALIAS, lc_sanitized, + SYSDB_NAME_ALIAS, sanitized); + } else { + filter = talloc_asprintf(tmp_ctx, fmt, SYSDB_NAME, sanitized); + } + } else { + filter = talloc_strdup(tmp_ctx, sanitized); + } + if (filter == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n"); + ret = ENOMEM; + goto done; + } + + ret = EOK; + +done: + if (ret == EOK) { + talloc_free(*_filter); + *_filter = talloc_steal(tctx, filter); + } + + talloc_free(tmp_ctx); + return ret; + +} + +/* This function updates all filters for specified domain using this + * domains regex to parse string into domain and name (if exists). */ +static errno_t update_all_filters(struct cache_tool_ctx *tctx, + struct sss_domain_info *dinfo) +{ + errno_t ret; + + /* Update user filter */ + ret = update_filter(tctx, dinfo, tctx->user_name, + tctx->update_user_filter, "(%s=%s)", + TYPE_USER, false, + &tctx->user_filter); + if (ret != EOK) { + return ret; + } + + /* Update group filter */ + ret = update_filter(tctx, dinfo, tctx->group_name, + tctx->update_group_filter, "(%s=%s)", + TYPE_GROUP, false, + &tctx->group_filter); + if (ret != EOK) { + return ret; + } + + /* Update netgroup filter */ + ret = update_filter(tctx, dinfo, tctx->netgroup_name, + tctx->update_netgroup_filter, "(%s=%s)", + TYPE_NETGROUP, false, + &tctx->netgroup_filter); + if (ret != EOK) { + return ret; + } + + /* Update service filter */ + ret = update_filter(tctx, dinfo, tctx->service_name, + tctx->update_service_filter, "(%s=%s)", + TYPE_SERVICE, false, + &tctx->service_filter); + if (ret != EOK) { + return ret; + } + + /* Update autofs filter */ + ret = update_filter(tctx, dinfo, tctx->autofs_name, + tctx->update_autofs_filter, + "(&(objectclass="SYSDB_AUTOFS_MAP_OC")(%s=%s))", + TYPE_AUTOFSMAP, true, + &tctx->autofs_filter); + if (ret != EOK) { + return ret; + } + + /* Update ssh host filter */ + ret = update_filter(tctx, dinfo, tctx->ssh_host_name, + tctx->update_ssh_host_filter, "(%s=%s)", + TYPE_SSH_HOST, false, + &tctx->ssh_host_filter); + if (ret != EOK) { + return ret; + } + + /* Update sudo rule filter */ + ret = update_filter(tctx, dinfo, tctx->sudo_rule_name, + tctx->update_sudo_rule_filter, + "(%s=%s)", TYPE_SUDO_RULE, false, + &tctx->sudo_rule_filter); + if (ret != EOK) { + return ret; + } + + return EOK; +} + +static errno_t invalidate_entry(TALLOC_CTX *ctx, + struct sss_domain_info *domain, + const char *name, int entry_type) +{ + struct sysdb_attrs *sys_attrs = NULL; + errno_t ret; + + sys_attrs = sysdb_new_attrs(ctx); + if (sys_attrs) { + ret = sysdb_attrs_add_time_t(sys_attrs, + SYSDB_CACHE_EXPIRE, 1); + if (ret == EOK) { + switch (entry_type) { + case TYPE_USER: + /* For users, we also need to reset the initgroups + * cache expiry */ + ret = sysdb_attrs_add_time_t(sys_attrs, + SYSDB_INITGR_EXPIRE, 1); + if (ret != EOK) return ret; + + ret = sysdb_set_user_attr(domain, name, sys_attrs, + SYSDB_MOD_REP); + if (ret != EOK) break; + + /* WARNING: Direct writing to persistent cache!! */ + ret = sysdb_invalidate_user_cache_entry(domain, name); + break; + case TYPE_GROUP: + ret = sysdb_set_group_attr(domain, name, sys_attrs, + SYSDB_MOD_REP); + if (ret != EOK) break; + + /* WARNING: Direct writing to persistent cache!! */ + ret = sysdb_invalidate_group_cache_entry(domain, name); + break; + case TYPE_NETGROUP: + ret = sysdb_set_netgroup_attr(domain, name, sys_attrs, + SYSDB_MOD_REP); + break; + case TYPE_SERVICE: + ret = sysdb_set_service_attr(domain, name, + sys_attrs, SYSDB_MOD_REP); + break; + case TYPE_AUTOFSMAP: + ret = sysdb_set_autofsmap_attr(domain, name, + sys_attrs, SYSDB_MOD_REP); + break; + case TYPE_SSH_HOST: +#ifdef BUILD_SSH + ret = sysdb_set_ssh_host_attr(domain, name, + sys_attrs, SYSDB_MOD_REP); +#else /* BUILD_SSH */ + ret = ENOSYS; +#endif /* BUILD_SSH */ + break; + case TYPE_SUDO_RULE: +#ifdef BUILD_SUDO + ret = sysdb_set_sudo_rule_attr(domain, name, + sys_attrs, SYSDB_MOD_REP); +#else /* BUILD_SUDO */ + ret = ENOSYS; +#endif /* BUILD_SUDO */ + break; + default: + return EINVAL; + } + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "Could not set entry attributes\n"); + } + } else { + DEBUG(SSSDBG_MINOR_FAILURE, + "Could not add expiration time to attributes\n"); + } + talloc_zfree(sys_attrs); + } else { + DEBUG(SSSDBG_MINOR_FAILURE, "Could not create sysdb attributes\n"); + ret = ENOMEM; + } + return ret; +} + +static bool invalidate_entries(TALLOC_CTX *ctx, + struct sss_domain_info *dinfo, + enum sss_cache_entry entry_type, + const char *filter, const char *name) +{ + const char *attrs[] = {SYSDB_NAME, NULL}; + size_t msg_count; + struct ldb_message **msgs; + const char *type_string = "unknown"; + errno_t ret = EINVAL; + int i; + const char *c_name; + bool iret; + + if (!filter) return false; + switch (entry_type) { + case TYPE_USER: + type_string = "user"; + ret = sysdb_search_users(ctx, dinfo, + filter, attrs, &msg_count, &msgs); + break; + case TYPE_GROUP: + type_string = "group"; + ret = sysdb_search_groups(ctx, dinfo, + filter, attrs, &msg_count, &msgs); + break; + case TYPE_NETGROUP: + type_string = "netgroup"; + ret = sysdb_search_netgroups(ctx, dinfo, + filter, attrs, &msg_count, &msgs); + break; + case TYPE_SERVICE: + type_string = "service"; + ret = sysdb_search_services(ctx, dinfo, + filter, attrs, &msg_count, &msgs); + break; + case TYPE_AUTOFSMAP: + type_string = "autofs map"; + ret = search_autofsmaps(ctx, dinfo, filter, attrs, &msg_count, &msgs); + break; + case TYPE_SSH_HOST: + type_string = "ssh_host"; +#ifdef BUILD_SSH + ret = sysdb_search_ssh_hosts(ctx, dinfo, + filter, attrs, &msg_count, &msgs); +#else /* BUILD_SSH */ + ret = ENOSYS; +#endif /* BUILD_SSH */ + break; + case TYPE_SUDO_RULE: + type_string = "sudo_rule"; +#ifdef BUILD_SUDO + ret = sysdb_search_sudo_rules(ctx, dinfo, + filter, attrs, &msg_count, &msgs); +#else /* BUILD_SUDO */ + ret = ENOSYS; +#endif /* BUILD_SUDO */ + break; + } + + if (ret != EOK) { + if (ret == ENOENT) { + DEBUG(SSSDBG_TRACE_FUNC, "'%s' %s: Not found in domain '%s'\n", + type_string, name ? name : "", dinfo->name); + } else { + DEBUG(SSSDBG_CRIT_FAILURE, + "Searching for %s in domain %s with filter %s failed\n", + type_string, dinfo->name, filter); + } + return false; + } + + iret = true; + for (i = 0; i < msg_count; i++) { + c_name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL); + if (c_name == NULL) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Something bad happened, can't find attribute %s\n", + SYSDB_NAME); + ERROR("Couldn't invalidate %1$s\n", type_string); + iret = false; + } else { + ret = invalidate_entry(ctx, dinfo, c_name, entry_type); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Couldn't invalidate %s %s\n", type_string, c_name); + ERROR("Couldn't invalidate %1$s %2$s\n", type_string, c_name); + iret = false; + } + } + } + talloc_zfree(msgs); + return iret; +} + + + +static errno_t init_domains(struct cache_tool_ctx *ctx, + const char *domain) +{ + char *confdb_path; + int ret; + struct sss_domain_info *dinfo; + + confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE); + if (confdb_path == NULL) { + return ENOMEM; + } + + /* Connect to the conf db */ + ret = confdb_init(ctx, &ctx->confdb, confdb_path); + talloc_free(confdb_path); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not initialize connection to the confdb\n"); + return ret; + } + + if (domain) { + ret = sssd_domain_init(ctx, ctx->confdb, + domain, DB_PATH, &ctx->domains); + if (ret != EOK) { + SYSDB_VERSION_ERROR(ret); + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not initialize connection to the sysdb\n"); + return ret; + } + + } else { + ret = confdb_get_domains(ctx->confdb, &ctx->domains); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not initialize domains\n"); + return ret; + } + + ret = sysdb_init(ctx, ctx->domains); + SYSDB_VERSION_ERROR(ret); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not initialize connection to the sysdb\n"); + return ret; + } + } + + for (dinfo = ctx->domains; dinfo; dinfo = get_next_domain(dinfo, 0)) { + ret = sss_names_init(ctx, ctx->confdb, dinfo->name, &dinfo->names); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "sss_names_init() failed\n"); + return ret; + } + } + + return EOK; +} + +static bool is_filter_valid(struct cache_tool_ctx *ctx, + struct input_values *values, int idb) +{ + if ((idb & INVALIDATE_USERS) && ctx->user_filter == NULL) { + return false; + } + + if ((idb & INVALIDATE_GROUPS) && ctx->group_filter == NULL) { + return false; + } + + if ((idb & INVALIDATE_NETGROUPS) && ctx->netgroup_filter == NULL) { + return false; + } + + if ((idb & INVALIDATE_SERVICES) && ctx->service_filter == NULL) { + return false; + } + + if ((idb & INVALIDATE_AUTOFSMAPS) && ctx->autofs_filter == NULL) { + return false; + } + + if ((idb & INVALIDATE_SSH_HOSTS) && ctx->ssh_host_filter == NULL) { + return false; + } + + if (values->user && ctx->user_name == NULL) { + return false; + } + + if (values->group && ctx->group_name == NULL) { + return false; + } + + if (values->netgroup && ctx->netgroup_name == NULL) { + return false; + } + + if (values->service && ctx->service_name == NULL) { + return false; + } + + if (values->map && ctx->autofs_name == NULL) { + return false; + } + + if (values->ssh_host && ctx->ssh_host_name == NULL) { + return false; + } + + if (values->sudo_rule && ctx->sudo_rule_name == NULL) { + return false; + } + + return true; +} + +static errno_t init_context(int argc, const char *argv[], + struct cache_tool_ctx **tctx) +{ + struct cache_tool_ctx *ctx = NULL; + int idb = INVALIDATE_NONE; + struct input_values values = { 0 }; + int debug = SSSDBG_DEFAULT; + errno_t ret = EOK; + + poptContext pc = NULL; + struct poptOption long_options[] = { + POPT_AUTOHELP + { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &debug, + 0, _("The debug level to run with"), NULL }, + { "everything", 'E', POPT_ARG_NONE, NULL, 'e', + _("Invalidate all cached entries"), NULL }, + { "user", 'u', POPT_ARG_STRING, &(values.user), 0, + _("Invalidate particular user"), NULL }, + { "users", 'U', POPT_ARG_NONE, NULL, 'u', + _("Invalidate all users"), NULL }, + { "group", 'g', POPT_ARG_STRING, &(values.group), 0, + _("Invalidate particular group"), NULL }, + { "groups", 'G', POPT_ARG_NONE, NULL, 'g', + _("Invalidate all groups"), NULL }, + { "netgroup", 'n', POPT_ARG_STRING, &(values.netgroup), 0, + _("Invalidate particular netgroup"), NULL }, + { "netgroups", 'N', POPT_ARG_NONE, NULL, 'n', + _("Invalidate all netgroups"), NULL }, + { "service", 's', POPT_ARG_STRING, &(values.service), 0, + _("Invalidate particular service"), NULL }, + { "services", 'S', POPT_ARG_NONE, NULL, 's', + _("Invalidate all services"), NULL }, +#ifdef BUILD_AUTOFS + { "autofs-map", 'a', POPT_ARG_STRING, &(values.map), 0, + _("Invalidate particular autofs map"), NULL }, + { "autofs-maps", 'A', POPT_ARG_NONE, NULL, 'a', + _("Invalidate all autofs maps"), NULL }, +#endif /* BUILD_AUTOFS */ +#ifdef BUILD_SSH + { "ssh-host", 'h', POPT_ARG_STRING, &(values.ssh_host), 0, + _("Invalidate particular SSH host"), NULL }, + { "ssh-hosts", 'H', POPT_ARG_NONE, NULL, 'h', + _("Invalidate all SSH hosts"), NULL }, +#endif /* BUILD_SSH */ +#ifdef BUILD_SUDO + { "sudo-rule", 'r', POPT_ARG_STRING, &(values.sudo_rule), 0, + _("Invalidate particular sudo rule"), NULL }, + { "sudo-rules", 'R', POPT_ARG_NONE, NULL, 'r', + _("Invalidate all cached sudo rules"), NULL }, +#endif /* BUILD_SUDO */ + { "domain", 'd', POPT_ARG_STRING, &(values.domain), 0, + _("Only invalidate entries from a particular domain"), NULL }, + POPT_TABLEEND + }; + + ret = set_locale(); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "set_locale failed (%d): %s\n", ret, strerror(ret)); + ERROR("Error setting the locale\n"); + goto fini; + } + + pc = poptGetContext(NULL, argc, argv, long_options, POPT_CONTEXT_KEEP_FIRST); + while ((ret = poptGetNextOpt(pc)) > 0) { + switch (ret) { + case 'u': + idb |= INVALIDATE_USERS; + break; + case 'g': + idb |= INVALIDATE_GROUPS; + break; + case 'n': + idb |= INVALIDATE_NETGROUPS; + break; + case 's': + idb |= INVALIDATE_SERVICES; + break; + case 'a': + idb |= INVALIDATE_AUTOFSMAPS; + break; + case 'h': + idb |= INVALIDATE_SSH_HOSTS; + break; + case 'r': + idb |= INVALIDATE_SUDO_RULES; + break; + case 'e': + idb = INVALIDATE_EVERYTHING; +#ifdef BUILD_SUDO + idb |= INVALIDATE_SUDO_RULES; +#endif /* BUILD_SUDO */ + break; + } + } + + DEBUG_CLI_INIT(debug); + debug_prg_name = argv[0]; + + if (ret != -1) { + BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini); + } + + if (poptGetArg(pc)) { + BAD_POPT_PARAMS(pc, + _("Unexpected argument(s) provided, options that " + "invalidate a single object only accept a single " + "provided argument.\n"), + ret, fini); + } + + if (idb == INVALIDATE_NONE && !values.user && !values.group && + !values.netgroup && !values.service && !values.map && + !values.ssh_host && !values.sudo_rule) { + BAD_POPT_PARAMS(pc, + _("Please select at least one object to invalidate\n"), + ret, fini); + } + + CHECK_ROOT(ret, debug_prg_name); + + ctx = talloc_zero(NULL, struct cache_tool_ctx); + if (ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not allocate memory for tools context\n"); + ret = ENOMEM; + goto fini; + } + + if (idb & INVALIDATE_USERS) { + ctx->user_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); + ctx->update_user_filter = false; + } else if (values.user) { + ctx->user_name = talloc_strdup(ctx, values.user); + ctx->update_user_filter = true; + } + + if (idb & INVALIDATE_GROUPS) { + ctx->group_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); + ctx->update_group_filter = false; + } else if (values.group) { + ctx->group_name = talloc_strdup(ctx, values.group); + ctx->update_group_filter = true; + } + + if (idb & INVALIDATE_NETGROUPS) { + ctx->netgroup_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); + ctx->update_netgroup_filter = false; + } else if (values.netgroup) { + ctx->netgroup_name = talloc_strdup(ctx, values.netgroup); + ctx->update_netgroup_filter = true; + } + + if (idb & INVALIDATE_SERVICES) { + ctx->service_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); + ctx->update_service_filter = false; + } else if (values.service) { + ctx->service_name = talloc_strdup(ctx, values.service); + ctx->update_service_filter = true; + } + + if (idb & INVALIDATE_AUTOFSMAPS) { + ctx->autofs_filter = talloc_asprintf(ctx, "(&(objectclass=%s)(%s=*))", + SYSDB_AUTOFS_MAP_OC, SYSDB_NAME); + ctx->update_autofs_filter = false; + } else if (values.map) { + ctx->autofs_name = talloc_strdup(ctx, values.map); + ctx->update_autofs_filter = true; + } + + if (idb & INVALIDATE_SSH_HOSTS) { + ctx->ssh_host_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); + ctx->update_ssh_host_filter = false; + } else if (values.ssh_host) { + ctx->ssh_host_name = talloc_strdup(ctx, values.ssh_host); + ctx->update_ssh_host_filter = true; + } + + if (idb & INVALIDATE_SUDO_RULES) { + ctx->sudo_rule_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME); + ctx->update_sudo_rule_filter = false; + } else if (values.sudo_rule) { + ctx->sudo_rule_name = talloc_strdup(ctx, values.sudo_rule); + ctx->update_sudo_rule_filter = true; + } + + if (is_filter_valid(ctx, &values, idb) == false) { + DEBUG(SSSDBG_CRIT_FAILURE, "Construction of filters failed\n"); + ret = ENOMEM; + goto fini; + } + + ret = init_domains(ctx, values.domain); + if (ret != EOK) { + if (values.domain) { + ERROR("Could not open domain %1$s. If the domain is a subdomain " + "(trusted domain), use fully qualified name instead of " + "--domain/-d parameter.\n", values.domain); + } else { + ERROR("Could not open available domains\n"); + } + DEBUG(SSSDBG_OP_FAILURE, + "Initialization of sysdb connections failed\n"); + goto fini; + } + + ret = EOK; + +fini: + poptFreeContext(pc); + free_input_values(&values); + if (ret != EOK && ctx) { + talloc_zfree(ctx); + } + if (ret == EOK) { + *tctx = ctx; + } + return ret; +} + + + static errno_t time_to_string(TALLOC_CTX *mem_ctx, time_t timestamp, const char **_value) @@ -702,3 +1523,98 @@ errno_t sssctl_netgroup_show(struct sss_cmdline *cmdline, return EOK; } + +errno_t sssctl_expire_cache(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + errno_t ret; + struct cache_tool_ctx *tctx = NULL; + struct sysdb_ctx *sysdb; + bool skipped = true; + struct sss_domain_info *dinfo; + + ret = init_context(cmdline->argc, cmdline->argv, &tctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Error initializing context for the application\n"); + goto done; + } + + for (dinfo = tctx->domains; dinfo; + dinfo = get_next_domain(dinfo, SSS_GND_DESCEND)) { + if (!IS_SUBDOMAIN(dinfo)) { + /* Update list of subdomains for this domain */ + ret = sysdb_update_subdomains(dinfo, tctx->confdb); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to update subdomains for domain %s.\n", dinfo->name); + } + } + + sysdb = dinfo->sysdb; + /* Update filters for each domain */ + ret = update_all_filters(tctx, dinfo); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to update filters.\n"); + goto done; + } + + ret = sysdb_transaction_start(sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not start the transaction!\n"); + goto done; + } + + skipped &= !invalidate_entries(tctx, dinfo, TYPE_USER, + tctx->user_filter, + tctx->user_name); + skipped &= !invalidate_entries(tctx, dinfo, TYPE_GROUP, + tctx->group_filter, + tctx->group_name); + skipped &= !invalidate_entries(tctx, dinfo, TYPE_NETGROUP, + tctx->netgroup_filter, + tctx->netgroup_name); + skipped &= !invalidate_entries(tctx, dinfo, TYPE_SERVICE, + tctx->service_filter, + tctx->service_name); + skipped &= !invalidate_entries(tctx, dinfo, TYPE_AUTOFSMAP, + tctx->autofs_filter, + tctx->autofs_name); + skipped &= !invalidate_entries(tctx, dinfo, TYPE_SSH_HOST, + tctx->ssh_host_filter, + tctx->ssh_host_name); + skipped &= !invalidate_entries(tctx, dinfo, TYPE_SUDO_RULE, + tctx->sudo_rule_filter, + tctx->sudo_rule_name); + + ret = sysdb_transaction_commit(sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not commit the transaction!\n"); + ret = sysdb_transaction_cancel(sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to cancel transaction\n"); + } + } + } + + if (skipped == true) { + ERROR("No cache object matched the specified search\n"); + ret = ENOENT; + goto done; + } else { + ret = sss_memcache_clear_all(); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to clear memory cache.\n"); + goto done; + } + } + + ret = EOK; +done: + if (tctx) talloc_free(tctx); + return ret; +} From e00a269f1f08234365941d9c8e4edd060e89a0b5 Mon Sep 17 00:00:00 2001 From: Justin Stephenson <[email protected]> Date: Fri, 12 May 2017 22:42:40 -0400 Subject: [PATCH 3/4] SSSCTL: Add sss_debuglevel shell wrapper The added sss_debuglevel shell wrapper will be used to replace /usr/sbin/sss_debuglevel binary to merge sss_debuglevel into sssctl. The wrapper will redirect sss_debuglevel to the sssctl debug-level command performing the same task. The sss_debuglevel(8) man page is updated to indicate that sss_debuglevel is deprecated and functionality exists now in sssctl. Resolves: https://pagure.io/SSSD/sssd/issue/3057 --- Makefile.am | 5 ++++- configure.ac | 1 + contrib/tools/sss_debuglevel.in | 4 ++++ src/man/sss_debuglevel.8.xml | 36 ++++-------------------------------- 4 files changed, 13 insertions(+), 33 deletions(-) create mode 100644 contrib/tools/sss_debuglevel.in diff --git a/Makefile.am b/Makefile.am index 73b3153..fe43a9b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -455,7 +455,10 @@ dist_noinst_SCRIPTS = \ src/tests/krb5_proxy_check_test_data.conf \ $(NULL) -dist_sbin_SCRIPTS = contrib/tools/sss_cache +dist_sbin_SCRIPTS = \ + contrib/tools/sss_cache \ + contrib/tools/sss_debuglevel \ + $(NULL) dist_noinst_DATA = \ src/config/testconfigs/sssd-valid.conf \ diff --git a/configure.ac b/configure.ac index 1dfa2d2..1b2f88d 100644 --- a/configure.ac +++ b/configure.ac @@ -505,5 +505,6 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config src/config/setup.py src/systemtap/sssd.stp contrib/tools/sss_cache + contrib/tools/sss_debuglevel src/config/SSSDConfig/__init__.py]) AC_OUTPUT diff --git a/contrib/tools/sss_debuglevel.in b/contrib/tools/sss_debuglevel.in new file mode 100644 index 0000000..8df4918 --- /dev/null +++ b/contrib/tools/sss_debuglevel.in @@ -0,0 +1,4 @@ +#!/bin/sh +sbindir=@sbindir@ +echo "Redirecting to $sbindir/sssctl debug-level" +$sbindir/sssctl debug-level $@ diff --git a/src/man/sss_debuglevel.8.xml b/src/man/sss_debuglevel.8.xml index eb11540..0538dc5 100644 --- a/src/man/sss_debuglevel.8.xml +++ b/src/man/sss_debuglevel.8.xml @@ -13,7 +13,7 @@ <refnamediv id='name'> <refname>sss_debuglevel</refname> - <refpurpose>change debug level while SSSD is running</refpurpose> + <refpurpose>[DEPRECATED] change debug level while SSSD is running</refpurpose> </refnamediv> <refsynopsisdiv id='synopsis'> @@ -29,40 +29,12 @@ <refsect1 id='description'> <title>DESCRIPTION</title> <para> - <command>sss_debuglevel</command> changes debug level of SSSD monitor - and providers to <replaceable>NEW_DEBUG_LEVEL</replaceable> while SSSD is running. + <command>sss_debuglevel</command> is deprecated and replaced + by the sssctl debug-level command. Please refer to the + <command>sssctl</command> man page for more information on sssctl usage. </para> </refsect1> - <refsect1 id='options'> - <title>OPTIONS</title> - <variablelist remap='IP'> - <varlistentry> - <term> - <option>-c</option>,<option>--config</option> - </term> - <listitem> - <para> - Specify a non-default config file. The default is - <filename>/etc/sssd/sssd.conf</filename>. For reference - on the config file syntax and options, consult the - <citerefentry> - <refentrytitle>sssd.conf</refentrytitle> - <manvolnum>5</manvolnum> - </citerefentry> - manual page. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <replaceable>NEW_DEBUG_LEVEL</replaceable> - </term> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/debug_levels.xml" /> - </varlistentry> - </variablelist> - </refsect1> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/seealso.xml" /> </refentry> From e70f52bdf71856165f32657f9f7de97a19f33d7e Mon Sep 17 00:00:00 2001 From: Justin Stephenson <[email protected]> Date: Fri, 12 May 2017 23:10:18 -0400 Subject: [PATCH 4/4] SSSCTL: Move sss_debuglevel to sssctl debug-level Move code from sss_debuglevel to sssctl_logs.c and add new debug-logs sssctl command to perform the same task of changing debug level dynamically. POPT_CONTEXT_KEEP_FIRST Flag added to poptGetContext call in sssctl_debug_level() to fix argument parsing. Resolves: https://pagure.io/SSSD/sssd/issue/3057 --- Makefile.am | 1 - po/POTFILES.in | 1 - src/tools/sss_debuglevel.c | 323 ----------------------------------------- src/tools/sssctl/sssctl.c | 1 + src/tools/sssctl/sssctl.h | 4 + src/tools/sssctl/sssctl_logs.c | 293 +++++++++++++++++++++++++++++++++++++ 6 files changed, 298 insertions(+), 325 deletions(-) delete mode 100644 src/tools/sss_debuglevel.c diff --git a/Makefile.am b/Makefile.am index fe43a9b..97b0cc1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -141,7 +141,6 @@ sbin_PROGRAMS = \ sss_usermod \ sss_groupmod \ sss_groupshow \ - sss_debuglevel \ sss_override \ sss_seed \ sssctl \ diff --git a/po/POTFILES.in b/po/POTFILES.in index b928473..e11bbab 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -19,7 +19,6 @@ src/tools/sss_groupshow.c src/tools/sss_useradd.c src/tools/sss_userdel.c src/tools/sss_usermod.c -src/tools/sss_debuglevel.c src/tools/tools_util.c src/tools/tools_util.h src/tools/sssctl/sssctl.c diff --git a/src/tools/sss_debuglevel.c b/src/tools/sss_debuglevel.c deleted file mode 100644 index e8b156e..0000000 --- a/src/tools/sss_debuglevel.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - Authors: - Pavel Březina <[email protected]> - - Copyright (C) 2011 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <limits.h> -#include <talloc.h> -#include <popt.h> -#include <sys/types.h> -#include <dirent.h> -#include <ctype.h> -#include <signal.h> -#include <utime.h> -#include <ldb.h> - -#include "config.h" -#include "util/util.h" -#include "tools/tools_util.h" -#include "tools/common/sss_process.h" -#include "confdb/confdb.h" - -#define CHECK(expr, done, msg) do { \ - if (expr) { \ - ERROR(msg "\n"); \ - goto done; \ - } \ -} while(0) - -struct debuglevel_tool_ctx { - struct confdb_ctx *confdb; - char **sections; -}; - -static errno_t set_debug_level(struct debuglevel_tool_ctx *tool_ctx, - int debug_to_set, const char *config_file); -static errno_t connect_to_confdb(TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx); -static errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb, - char ***output_sections); -static int parse_debug_level(const char *strlevel); - -int main(int argc, const char **argv) -{ - int ret; - int pc_debug = SSSDBG_DEFAULT; - int debug_to_set = SSSDBG_INVALID; - const char *debug_as_string = NULL; - const char *config_file = NULL; - const char *pc_config_file = NULL; - struct debuglevel_tool_ctx *ctx = NULL; - struct poptOption long_options[] = { - POPT_AUTOHELP - {"debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, - 0, _("The debug level to run with"), NULL }, - {"config", 'c', POPT_ARG_STRING, &pc_config_file, - 0, _("Specify a non-default config file"), NULL}, - POPT_TABLEEND - }; - poptContext pc = NULL; - - debug_prg_name = argv[0]; - - /* parse parameters */ - pc = poptGetContext(argv[0], argc, argv, long_options, 0); - poptSetOtherOptionHelp(pc, "DEBUG_LEVEL_TO_SET"); - while((ret = poptGetNextOpt(pc)) != -1) { - switch(ret) { - default: - fprintf(stderr, "\nInvalid option %s: %s\n\n", - poptBadOption(pc, 0), poptStrerror(ret)); - poptPrintUsage(pc, stderr, 0); - ret = EXIT_FAILURE; - goto fini; - } - } - DEBUG_CLI_INIT(pc_debug); - - /* get debug level */ - debug_as_string = poptGetArg(pc); - if (debug_as_string == NULL) { - BAD_POPT_PARAMS(pc, _("Specify debug level you want to set\n"), - ret, fini); - } - - /* No more arguments expected. If something follows it is an error. */ - if (poptGetArg(pc)) { - BAD_POPT_PARAMS(pc, _("Only one argument expected\n"), - ret, fini); - } - - /* get config file */ - if (pc_config_file) { - config_file = talloc_strdup(ctx, pc_config_file); - } else { - config_file = talloc_strdup(ctx, SSSD_CONFIG_FILE); - } - - if (config_file == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); - ret = ENOMEM; - goto fini; - } - - CHECK_ROOT(ret, debug_prg_name); - - /* free pc_config_file? */ - /* free debug_as_string? */ - - debug_to_set = parse_debug_level(debug_as_string); - CHECK(debug_to_set == SSSDBG_INVALID, fini, "Invalid debug level."); - - /* allocate context */ - ctx = talloc_zero(NULL, struct debuglevel_tool_ctx); - if (ctx == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not allocate memory for tools context\n"); - ret = ENOMEM; - goto fini; - } - - ret = connect_to_confdb(ctx, &ctx->confdb); - CHECK(ret != EOK, fini, "Could not connect to configuration database."); - - ret = get_confdb_sections(ctx, ctx->confdb, &ctx->sections); - CHECK(ret != EOK, fini, "Could not get all configuration sections."); - - ret = set_debug_level(ctx, debug_to_set, config_file); - CHECK(ret != EOK, fini, "Could not set debug level."); - - ret = sss_signal(SIGHUP); - CHECK(ret != EOK, fini, - "Could not force sssd processes to reload configuration. " - "Is sssd running?"); - -fini: - poptFreeContext(pc); - talloc_free(ctx); - return ret; -} - -errno_t set_debug_level(struct debuglevel_tool_ctx *tool_ctx, - int debug_to_set, const char *config_file) -{ - int ret; - int err; - const char *values[2]; - char **section = NULL; - TALLOC_CTX *tmp_ctx = talloc_new(NULL); - - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); - return ENOMEM; - } - - /* convert debug_to_set to string */ - values[0] = talloc_asprintf(tmp_ctx, "0x%.4x", debug_to_set); - if (values[0] == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate memory for " - "debug_to_set to string conversion\n"); - ret = ENOMEM; - goto done; - } - values[1] = NULL; - - /* write to confdb */ - for (section = tool_ctx->sections; *section != NULL; section++) { - ret = confdb_add_param(tool_ctx->confdb, 1, *section, - CONFDB_SERVICE_DEBUG_LEVEL, values); - if (ret != EOK) { - goto done; - } - } - - /* - * Change atime and mtime of sssd.conf, - * so the configuration can be restored on next start. - */ - errno = 0; - if (utime(config_file, NULL) == -1 ) { - err = errno; - DEBUG(SSSDBG_MINOR_FAILURE, "Unable to change mtime of \"%s\": %s\n", - config_file, strerror(err)); - } - - ret = EOK; - -done: - talloc_free(tmp_ctx); - return ret; -} - -errno_t connect_to_confdb(TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx) -{ - int ret; - char* confdb_path = NULL; - - confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE); - if (confdb_path == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not allocate memory for confdb path\n"); - return ENOMEM; - } - - ret = confdb_init(ctx, cdb_ctx, confdb_path); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not initialize connection to the confdb\n"); - } - - talloc_free(confdb_path); - return ret; -} - -errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb, - char ***output_sections) -{ - int ret; - int domain_count = 0; - int i = 0; - struct sss_domain_info *domain = NULL; - struct sss_domain_info *domain_list = NULL; - char **sections; - const char *known_services[] = { - CONFDB_MONITOR_CONF_ENTRY, - CONFDB_NSS_CONF_ENTRY, - CONFDB_PAM_CONF_ENTRY, - CONFDB_PAC_CONF_ENTRY, - CONFDB_SSH_CONF_ENTRY, - CONFDB_SUDO_CONF_ENTRY, - CONFDB_AUTOFS_CONF_ENTRY, - CONFDB_IFP_CONF_ENTRY, - }; - static const int known_services_count = sizeof(known_services) - / sizeof(*known_services); - TALLOC_CTX *tmp_ctx = talloc_new(NULL); - - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); - return ENOMEM; - } - - /* get domains */ - ret = confdb_get_domains(confdb, &domain_list); - if (ret != EOK) - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain list\n"); - - for (domain = domain_list; - domain; - domain = get_next_domain(domain, 0)) { - domain_count++; - } - - /* allocate output space */ - sections = talloc_array(ctx, char*, - domain_count + known_services_count + 1); - if (sections == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Could not allocate memory for sections\n"); - ret = ENOMEM; - goto fail; - } - - for (i = 0; i < known_services_count; i++) { - sections[i] = talloc_strdup(tmp_ctx, known_services[i]); - if (sections[i] == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); - ret = ENOMEM; - goto fail; - } - } - - for (domain = domain_list; - domain; - domain = get_next_domain(domain, 0), i++) { - sections[i] = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL, - domain->name); - if (sections[i] == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); - ret = ENOMEM; - goto fail; - } - } - - /* add NULL to the end */ - sections[i] = NULL; - - *output_sections = talloc_steal(ctx, sections); - - return EOK; -fail: - talloc_free(tmp_ctx); - return ret; -} - -int parse_debug_level(const char *strlevel) -{ - long value; - char *endptr; - - errno = 0; - value = strtol(strlevel, &endptr, 0); - if ((errno != 0) || (endptr == strlevel) || (*endptr != '\0')) { - return SSSDBG_INVALID; - } - - return debug_convert_old_level(value); -} diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c index d0bf752..0f25414 100644 --- a/src/tools/sssctl/sssctl.c +++ b/src/tools/sssctl/sssctl.c @@ -277,6 +277,7 @@ int main(int argc, const char **argv) SSS_TOOL_DELIMITER("Log files tools:"), SSS_TOOL_COMMAND("logs-remove", "Remove existing SSSD log files", 0, sssctl_logs_remove), SSS_TOOL_COMMAND("logs-fetch", "Archive SSSD log files in tarball", 0, sssctl_logs_fetch), + SSS_TOOL_COMMAND("debug-level", "Change SSSD debug level", 0, sssctl_debug_level), #ifdef HAVE_LIBINI_CONFIG_V1_3 SSS_TOOL_DELIMITER("Configuration files tools:"), SSS_TOOL_COMMAND_FLAGS("config-check", "Perform static analysis of SSSD configuration", 0, sssctl_config_check, SSS_TOOL_FLAG_SKIP_CMD_INIT), diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h index dd7e039..f6f4b1a 100644 --- a/src/tools/sssctl/sssctl.h +++ b/src/tools/sssctl/sssctl.h @@ -106,6 +106,10 @@ errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline, struct sss_tool_ctx *tool_ctx, void *pvt); +errno_t sssctl_debug_level(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); + errno_t sssctl_user_show(struct sss_cmdline *cmdline, struct sss_tool_ctx *tool_ctx, void *pvt); diff --git a/src/tools/sssctl/sssctl_logs.c b/src/tools/sssctl/sssctl_logs.c index 571207c..1a6a243 100644 --- a/src/tools/sssctl/sssctl_logs.c +++ b/src/tools/sssctl/sssctl_logs.c @@ -18,23 +18,214 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <stdlib.h> +#include <limits.h> +#include <talloc.h> +#include <sys/types.h> +#include <dirent.h> +#include <ctype.h> +#include <signal.h> +#include <utime.h> +#include <ldb.h> #include <popt.h> #include <stdio.h> +#include "config.h" #include "util/util.h" #include "tools/common/sss_tools.h" #include "tools/common/sss_process.h" #include "tools/sssctl/sssctl.h" #include "tools/tools_util.h" +#include "confdb/confdb.h" #define LOG_FILE(file) " " LOG_PATH "/" file #define LOG_FILES LOG_FILE("*.log") +#define CHECK(expr, done, msg) do { \ + if (expr) { \ + ERROR(msg "\n"); \ + goto done; \ + } \ +} while(0) + +struct debuglevel_tool_ctx { + struct confdb_ctx *confdb; + char **sections; +}; + struct sssctl_logs_opts { int delete; int archived; }; +errno_t set_debug_level(struct debuglevel_tool_ctx *tool_ctx, + int debug_to_set, const char *config_file) +{ + int ret; + int err; + const char *values[2]; + char **section = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return ENOMEM; + } + + /* convert debug_to_set to string */ + values[0] = talloc_asprintf(tmp_ctx, "0x%.4x", debug_to_set); + if (values[0] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate memory for " + "debug_to_set to string conversion\n"); + ret = ENOMEM; + goto done; + } + values[1] = NULL; + + /* write to confdb */ + for (section = tool_ctx->sections; *section != NULL; section++) { + ret = confdb_add_param(tool_ctx->confdb, 1, *section, + CONFDB_SERVICE_DEBUG_LEVEL, values); + if (ret != EOK) { + goto done; + } + } + + /* + * Change atime and mtime of sssd.conf, + * so the configuration can be restored on next start. + */ + errno = 0; + if (utime(config_file, NULL) == -1 ) { + err = errno; + DEBUG(SSSDBG_MINOR_FAILURE, "Unable to change mtime of \"%s\": %s\n", + config_file, strerror(err)); + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t connect_to_confdb(TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx) +{ + int ret; + char* confdb_path = NULL; + + confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE); + if (confdb_path == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not allocate memory for confdb path\n"); + return ENOMEM; + } + + ret = confdb_init(ctx, cdb_ctx, confdb_path); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not initialize connection to the confdb\n"); + } + + talloc_free(confdb_path); + return ret; +} + +errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb, + char ***output_sections) +{ + int ret; + int domain_count = 0; + int i = 0; + struct sss_domain_info *domain = NULL; + struct sss_domain_info *domain_list = NULL; + char **sections; + const char *known_services[] = { + CONFDB_MONITOR_CONF_ENTRY, + CONFDB_NSS_CONF_ENTRY, + CONFDB_PAM_CONF_ENTRY, + CONFDB_PAC_CONF_ENTRY, + CONFDB_SSH_CONF_ENTRY, + CONFDB_SUDO_CONF_ENTRY, + CONFDB_AUTOFS_CONF_ENTRY, + CONFDB_IFP_CONF_ENTRY, + }; + static const int known_services_count = sizeof(known_services) + / sizeof(*known_services); + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return ENOMEM; + } + + /* get domains */ + ret = confdb_get_domains(confdb, &domain_list); + if (ret != EOK) + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain list\n"); + + for (domain = domain_list; + domain; + domain = get_next_domain(domain, 0)) { + domain_count++; + } + + /* allocate output space */ + sections = talloc_array(ctx, char*, + domain_count + known_services_count + 1); + if (sections == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not allocate memory for sections\n"); + ret = ENOMEM; + goto fail; + } + + for (i = 0; i < known_services_count; i++) { + sections[i] = talloc_strdup(tmp_ctx, known_services[i]); + if (sections[i] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); + ret = ENOMEM; + goto fail; + } + } + + for (domain = domain_list; + domain; + domain = get_next_domain(domain, 0), i++) { + sections[i] = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL, + domain->name); + if (sections[i] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); + ret = ENOMEM; + goto fail; + } + } + + /* add NULL to the end */ + sections[i] = NULL; + + *output_sections = talloc_steal(ctx, sections); + + return EOK; +fail: + talloc_free(tmp_ctx); + return ret; +} + +int parse_debug_level(const char *strlevel) +{ + long value; + char *endptr; + + errno = 0; + value = strtol(strlevel, &endptr, 0); + if ((errno != 0) || (endptr == strlevel) || (*endptr != '\0')) { + return SSSDBG_INVALID; + } + + return debug_convert_old_level(value); +} + errno_t sssctl_logs_remove(struct sss_cmdline *cmdline, struct sss_tool_ctx *tool_ctx, void *pvt) @@ -105,3 +296,105 @@ errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline, return EOK; } + +errno_t sssctl_debug_level(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + int ret; + int pc_debug = SSSDBG_DEFAULT; + int debug_to_set = SSSDBG_INVALID; + const char *debug_as_string = NULL; + const char *config_file = NULL; + const char *pc_config_file = NULL; + struct debuglevel_tool_ctx *ctx = NULL; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, + 0, _("The debug level to run with"), NULL }, + {"config", 'c', POPT_ARG_STRING, &pc_config_file, + 0, _("Specify a non-default config file"), NULL}, + POPT_TABLEEND + }; + poptContext pc = NULL; + + debug_prg_name = cmdline->argv[0]; + + /* parse parameters */ + pc = poptGetContext(cmdline->argv[0], cmdline->argc, cmdline->argv, + long_options, POPT_CONTEXT_KEEP_FIRST); + poptSetOtherOptionHelp(pc, "DEBUG_LEVEL_TO_SET"); + while((ret = poptGetNextOpt(pc)) != -1) { + switch(ret) { + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(ret)); + poptPrintUsage(pc, stderr, 0); + ret = EXIT_FAILURE; + goto fini; + } + } + DEBUG_CLI_INIT(pc_debug); + + /* get debug level */ + debug_as_string = poptGetArg(pc); + if (debug_as_string == NULL) { + BAD_POPT_PARAMS(pc, _("Specify debug level you want to set\n"), + ret, fini); + } + + /* No more arguments expected. If something follows it is an error. */ + if (poptGetArg(pc)) { + BAD_POPT_PARAMS(pc, _("Only one argument expected\n"), + ret, fini); + } + + /* get config file */ + if (pc_config_file) { + config_file = talloc_strdup(ctx, pc_config_file); + } else { + config_file = talloc_strdup(ctx, SSSD_CONFIG_FILE); + } + + if (config_file == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); + ret = ENOMEM; + goto fini; + } + + CHECK_ROOT(ret, debug_prg_name); + + /* free pc_config_file? */ + /* free debug_as_string? */ + + debug_to_set = parse_debug_level(debug_as_string); + CHECK(debug_to_set == SSSDBG_INVALID, fini, "Invalid debug level."); + + /* allocate context */ + ctx = talloc_zero(NULL, struct debuglevel_tool_ctx); + if (ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not allocate memory for tools context\n"); + ret = ENOMEM; + goto fini; + } + + ret = connect_to_confdb(ctx, &ctx->confdb); + CHECK(ret != EOK, fini, "Could not connect to configuration database."); + + ret = get_confdb_sections(ctx, ctx->confdb, &ctx->sections); + CHECK(ret != EOK, fini, "Could not get all configuration sections."); + + ret = set_debug_level(ctx, debug_to_set, config_file); + CHECK(ret != EOK, fini, "Could not set debug level."); + + ret = sss_signal(SIGHUP); + CHECK(ret != EOK, fini, + "Could not force sssd processes to reload configuration. " + "Is sssd running?"); + +fini: + poptFreeContext(pc); + talloc_free(ctx); + return ret; +}
_______________________________________________ sssd-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
