diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/conf_macros.m4 | 14 | ||||
-rw-r--r-- | src/confdb/confdb.h | 3 | ||||
-rw-r--r-- | src/config/SSSDConfig.py | 2 | ||||
-rw-r--r-- | src/config/etc/sssd.api.conf | 2 | ||||
-rw-r--r-- | src/man/sssd.conf.5.xml | 44 | ||||
-rw-r--r-- | src/responder/nss/nsssrv.c | 82 | ||||
-rw-r--r-- | src/responder/nss/nsssrv.h | 3 | ||||
-rw-r--r-- | src/responder/nss/nsssrv_cmd.c | 39 |
9 files changed, 189 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index ba1c03bd..b96c42ae 100644 --- a/configure.ac +++ b/configure.ac @@ -95,6 +95,7 @@ WITH_SELINUX WITH_NSCD WITH_SEMANAGE WITH_LIBNL +WITH_NOLOGIN_SHELL m4_include([src/external/pkg.m4]) m4_include([src/external/libpopt.m4]) diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 index 31048d3d..af9cb4f2 100644 --- a/src/conf_macros.m4 +++ b/src/conf_macros.m4 @@ -317,3 +317,17 @@ AC_DEFUN([WITH_CRYPTO], AM_CONDITIONAL([HAVE_NSS], [test x"$cryptolib" = xnss]) AM_CONDITIONAL([HAVE_LIBCRYPTO], [test x"$cryptolib" = xlibcrypto]) ]) + +AC_DEFUN([WITH_NOLOGIN_SHELL], + [ AC_ARG_WITH([nologin-shell], + [AC_HELP_STRING([--with-nologin-shell=PATH], + [The shell used to deny access to users [/sbin/nologin]] + ) + ] + ) + nologin_shell="/sbin/nologin" + if test x"$with_nologin_shell" != x; then + nologin_shell=$with_nologin_shell + fi + AC_DEFINE_UNQUOTED(NOLOGIN_SHELL, "$nologin_shell", [The shell used to deny access to users]) + ]) diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index 20e82b4d..c2ae9fcb 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -41,6 +41,7 @@ #define CONFDB_DEFAULT_CONFIG_FILE SSSD_CONF_DIR"/sssd.conf" #define SSSD_MIN_ID 1 #define SSSD_LOCAL_MINID 1000 +#define CONFDB_DEFAULT_SHELL_FALLBACK "/bin/sh" /* Configuration options */ @@ -73,6 +74,8 @@ #define CONFDB_NSS_FILTER_GROUPS "filter_groups" #define CONFDB_NSS_PWFIELD "pwfield" #define CONFDB_NSS_OVERRIDE_HOMEDIR "override_homedir" +#define CONFDB_NSS_ALLOWED_SHELL "allowed_shells" +#define CONFDB_NSS_SHELL_FALLBACK "shell_fallback" /* PAM */ #define CONFDB_PAM_CONF_ENTRY "config/pam" diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py index 8e962f33..5a26e31a 100644 --- a/src/config/SSSDConfig.py +++ b/src/config/SSSDConfig.py @@ -59,6 +59,8 @@ option_strings = { 'filter_users_in_groups' : _('Should filtered users appear in groups'), 'pwfield' : _('The value of the password field the NSS provider should return'), 'override_homedir' : _('Override homedir value from the identity provider with this value'), + 'allowed_shells' : _('The list of shells users are allowed to log in with'), + 'shell_fallback' : _('If a shell stored in central directory is allowed but not available, use this fallback'), # [pam] 'offline_credentials_expiration' : _('How long to allow cached logins between online logins (days)'), diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index 6f15495f..ae9ba559 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -28,6 +28,8 @@ filter_groups = list, str, false filter_users_in_groups = bool, None, false pwfield = str, None, false override_homedir = str, None, false +allowed_shells = list, str, false +shell_fallback = str, None, false [pam] # Authentication service diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 57454dd8..b4f38465 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -391,6 +391,50 @@ </para> </listitem> </varlistentry> + <varlistentry> + <term>allowed_shells (string)</term> + <listitem> + <para> + Restrict user shell to one of the listed values. The order of evaluation is: + </para> + <para> + 1. If the shell is present in + <quote>/etc/shells</quote>, it is used. + </para> + <para> + 2. If the shell is in the allowed_shells list but + not in <quote>/etc/shells</quote>, use the + value of the shell_fallback parameter. + </para> + <para> + 3. If the shell is not in the allowed_shells list and + not in <quote>/etc/shells</quote>, a nologin shell + is used. + </para> + <para> + An empty string for shell is passed as-is to libc. + </para> + <para> + The <quote>/etc/shells</quote> is only read on SSSD start up, which means that + a restart of the SSSD is required in case a new shell is installed. + </para> + <para> + Default: Not set. The user shell is automatically used. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>shell_fallback (string)</term> + <listitem> + <para> + The default shell to use if an allowed shell is not + installed on the machine. + </para> + <para> + Default: /bin/sh + </para> + </listitem> + </varlistentry> </variablelist> </refsect2> <refsect2 id='PAM'> diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c index a5323bd7..b9d548e4 100644 --- a/src/responder/nss/nsssrv.c +++ b/src/responder/nss/nsssrv.c @@ -48,6 +48,9 @@ #define DEFAULT_PWFIELD "*" +#define SHELL_REALLOC_INCREMENT 5 +#define SHELL_REALLOC_MAX 50 + struct sbus_method monitor_nss_methods[] = { { MON_CLI_METHOD_PING, monitor_common_pong }, { MON_CLI_METHOD_RES_INIT, monitor_common_res_init }, @@ -63,6 +66,71 @@ struct sbus_interface monitor_nss_interface = { NULL }; +static errno_t nss_get_etc_shells(TALLOC_CTX *mem_ctx, char ***_shells) +{ + int i = 0; + char *sh; + char **shells = NULL; + TALLOC_CTX *tmp_ctx; + errno_t ret; + int size; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; + + shells = talloc_array(tmp_ctx, char *, SHELL_REALLOC_INCREMENT); + if (!shells) { + ret = ENOMEM; + goto done; + } + size = SHELL_REALLOC_INCREMENT; + + setusershell(); + while ((sh = getusershell())) { + shells[i] = talloc_strdup(shells, sh); + if (!shells[i]) { + endusershell(); + ret = ENOMEM; + goto done; + } + DEBUG(6, ("Found shell %s in /etc/shells\n", shells[i])); + i++; + + if (i == size) { + size += SHELL_REALLOC_INCREMENT; + if (size > SHELL_REALLOC_MAX) { + DEBUG(0, ("Reached maximum number of shells [%d]. " + "Users may be denied access. " + "Please check /etc/shells for sanity\n", + SHELL_REALLOC_MAX)); + break; + } + shells = talloc_realloc(NULL, shells, char *, + size); + if (!shells) { + ret = ENOMEM; + goto done; + } + } + } + endusershell(); + + if (i + 1 < size) { + shells = talloc_realloc(NULL, shells, char *, i + 1); + if (!shells) { + ret = ENOMEM; + goto done; + } + } + shells[i] = NULL; + + *_shells = talloc_move(mem_ctx, &shells); + ret = EOK; +done: + talloc_zfree(tmp_ctx); + return ret; +} + static int nss_get_config(struct nss_ctx *nctx, struct resp_ctx *rctx, struct confdb_ctx *cdb) @@ -115,6 +183,20 @@ static int nss_get_config(struct nss_ctx *nctx, &nctx->override_homedir); if (ret != EOK) goto done; + ret = confdb_get_string_as_list(cdb, nctx, CONFDB_NSS_CONF_ENTRY, + CONFDB_NSS_ALLOWED_SHELL, + &nctx->allowed_shells); + if (ret != EOK && ret != ENOENT) goto done; + + ret = nss_get_etc_shells(nctx, &nctx->etc_shells); + if (ret != EOK) goto done; + + ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY, + CONFDB_NSS_SHELL_FALLBACK, + CONFDB_DEFAULT_SHELL_FALLBACK, + &nctx->shell_fallback); + if (ret != EOK) goto done; + ret = 0; done: talloc_free(tmpctx); diff --git a/src/responder/nss/nsssrv.h b/src/responder/nss/nsssrv.h index e3e774f9..f9aff566 100644 --- a/src/responder/nss/nsssrv.h +++ b/src/responder/nss/nsssrv.h @@ -59,6 +59,9 @@ struct nss_ctx { char *pwfield; char *override_homedir; + char **allowed_shells; + char **etc_shells; + char *shell_fallback; }; struct nss_packet; diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c index 4386da71..e698b5ec 100644 --- a/src/responder/nss/nsssrv_cmd.c +++ b/src/responder/nss/nsssrv_cmd.c @@ -305,6 +305,43 @@ static const char *get_homedir_override(TALLOC_CTX *mem_ctx, ldb_msg_find_attr_as_string(msg, SYSDB_HOMEDIR, NULL)); } +static const char *get_shell_override(TALLOC_CTX *mem_ctx, + struct ldb_message *msg, + struct nss_ctx *nctx) +{ + const char *user_shell; + int i; + + user_shell = ldb_msg_find_attr_as_string(msg, SYSDB_SHELL, NULL); + if (!user_shell) return NULL; + if (!nctx->allowed_shells) return talloc_strdup(mem_ctx, user_shell); + + for (i=0; nctx->etc_shells[i]; i++) { + if (strcmp(user_shell, nctx->etc_shells[i]) == 0) { + DEBUG(9, ("Shell %s found in /etc/shells\n", + nctx->etc_shells[i])); + break; + } + } + + if (nctx->etc_shells[i]) { + DEBUG(9, ("Using original shell '%s'\n", user_shell)); + return talloc_strdup(mem_ctx, user_shell); + } + + for (i=0; nctx->allowed_shells[i]; i++) { + if (strcmp(nctx->allowed_shells[i], user_shell) == 0) { + DEBUG(5, ("The shell '%s' is allowed but does not exist. " + "Using fallback\n", user_shell)); + return talloc_strdup(mem_ctx, nctx->shell_fallback); + } + } + + DEBUG(5, ("The shell '%s' is not allowed and does not exist.\n", + user_shell)); + return talloc_strdup(mem_ctx, NOLOGIN_SHELL); +} + static int fill_pwent(struct sss_packet *packet, struct sss_domain_info *dom, struct nss_ctx *nctx, @@ -373,7 +410,7 @@ static int fill_pwent(struct sss_packet *packet, gecos = ldb_msg_find_attr_as_string(msg, SYSDB_GECOS, NULL); homedir = get_homedir_override(tmp_ctx, msg, nctx, dom, name, uid); - shell = ldb_msg_find_attr_as_string(msg, SYSDB_SHELL, NULL); + shell = get_shell_override(tmp_ctx, msg, nctx); if (!gecos) gecos = ""; if (!homedir) homedir = "/"; |