diff options
-rw-r--r-- | src/confdb/confdb.c | 9 | ||||
-rw-r--r-- | src/confdb/confdb.h | 2 | ||||
-rw-r--r-- | src/config/SSSDConfig.py | 1 | ||||
-rwxr-xr-x | src/config/SSSDConfigTest.py | 2 | ||||
-rw-r--r-- | src/config/etc/sssd.api.conf | 2 | ||||
-rw-r--r-- | src/man/sssd.conf.5.xml | 37 | ||||
-rw-r--r-- | src/responder/nss/nsssrv.c | 5 | ||||
-rw-r--r-- | src/responder/nss/nsssrv.h | 2 | ||||
-rw-r--r-- | src/responder/nss/nsssrv_cmd.c | 134 |
9 files changed, 192 insertions, 2 deletions
diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c index fdf409f9..87d33f9b 100644 --- a/src/confdb/confdb.c +++ b/src/confdb/confdb.c @@ -849,9 +849,16 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, goto done; } + tmp = ldb_msg_find_attr_as_string(res->msgs[0], + CONFDB_NSS_OVERRIDE_HOMEDIR, NULL); + domain->override_homedir = talloc_strdup(domain, tmp); + if (!domain->name) { + ret = ENOMEM; + goto done; + } + *_domain = domain; ret = EOK; - done: talloc_free(tmp_ctx); return ret; diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index 4e8a6dd8..20e82b4d 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -72,6 +72,7 @@ #define CONFDB_NSS_FILTER_USERS "filter_users" #define CONFDB_NSS_FILTER_GROUPS "filter_groups" #define CONFDB_NSS_PWFIELD "pwfield" +#define CONFDB_NSS_OVERRIDE_HOMEDIR "override_homedir" /* PAM */ #define CONFDB_PAM_CONF_ENTRY "config/pam" @@ -145,6 +146,7 @@ struct sss_domain_info { bool legacy_passwords; gid_t override_gid; + const char *override_homedir; uint32_t entry_cache_timeout; diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py index 25484dbc..8e962f33 100644 --- a/src/config/SSSDConfig.py +++ b/src/config/SSSDConfig.py @@ -58,6 +58,7 @@ option_strings = { 'filter_groups' : _('Groups that SSSD should explicitly ignore'), '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'), # [pam] 'offline_credentials_expiration' : _('How long to allow cached logins between online logins (days)'), diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py index 7bd45b47..5b01b990 100755 --- a/src/config/SSSDConfigTest.py +++ b/src/config/SSSDConfigTest.py @@ -481,6 +481,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): 'dns_resolver_timeout', 'dns_discovery_domain', 'override_gid', + 'override_homedir', 'id_provider', 'auth_provider', 'access_provider', @@ -786,6 +787,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): 'dns_resolver_timeout', 'dns_discovery_domain', 'override_gid', + 'override_homedir', 'id_provider', 'auth_provider', 'access_provider', diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index dfb5badc..6f15495f 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -27,6 +27,7 @@ filter_users = list, str, false filter_groups = list, str, false filter_users_in_groups = bool, None, false pwfield = str, None, false +override_homedir = str, None, false [pam] # Authentication service @@ -65,6 +66,7 @@ filter_groups = list, str, false dns_resolver_timeout = int, None, false dns_discovery_domain = str, None, false override_gid = int, None, false +override_homedir = str, None, false # Special providers [provider/permit] diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 386dd035..57454dd8 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -354,6 +354,43 @@ </para> </listitem> </varlistentry> + <varlistentry> + <term>override_homedir (string)</term> + <listitem> + <para> + Override the user's home directory. You + can either provide an absolute value or a + template. In the template, the following + sequences are substituted: + <variablelist> + <varlistentry> + <term>%u</term> + <listitem><para>login name</para></listitem> + </varlistentry> + <varlistentry> + <term>%U</term> + <listitem><para>UID number</para></listitem> + </varlistentry> + <varlistentry> + <term>%d</term> + <listitem><para>domain name</para></listitem> + </varlistentry> + <varlistentry> + <term>%f</term> + <listitem><para>fully qualified user name (user@domain)</para></listitem> + </varlistentry> + <varlistentry> + <term>%%</term> + <listitem><para>a literal '%'</para> + </listitem> + </varlistentry> + </variablelist> + </para> + <para> + This option can also be set per-domain. + </para> + </listitem> + </varlistentry> </variablelist> </refsect2> <refsect2 id='PAM'> diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c index 6c20ca31..a5323bd7 100644 --- a/src/responder/nss/nsssrv.c +++ b/src/responder/nss/nsssrv.c @@ -110,6 +110,11 @@ static int nss_get_config(struct nss_ctx *nctx, &nctx->pwfield); if (ret != EOK) goto done; + ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY, + CONFDB_NSS_OVERRIDE_HOMEDIR, NULL, + &nctx->override_homedir); + 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 062d937f..e3e774f9 100644 --- a/src/responder/nss/nsssrv.h +++ b/src/responder/nss/nsssrv.h @@ -57,6 +57,8 @@ struct nss_ctx { bool filter_users_in_groups; char *pwfield; + + char *override_homedir; }; struct nss_packet; diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c index 2f510b9b..4386da71 100644 --- a/src/responder/nss/nsssrv_cmd.c +++ b/src/responder/nss/nsssrv_cmd.c @@ -169,6 +169,114 @@ struct setent_ctx { /**************************************************************************** * PASSWD db related functions ***************************************************************************/ +char *expand_homedir_template(TALLOC_CTX *mem_ctx, const char *template, + const char *username, uint32_t uid, + const char *domain) +{ + char *copy; + char *p; + char *n; + char *result = NULL; + char *res = NULL; + TALLOC_CTX *tmp_ctx = NULL; + + if (template == NULL) { + DEBUG(1, ("Missing template.\n")); + return NULL; + } + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return NULL; + + copy = talloc_strdup(tmp_ctx, template); + if (copy == NULL) { + DEBUG(1, ("talloc_strdup failed.\n")); + goto done; + } + + result = talloc_strdup(tmp_ctx, ""); + if (result == NULL) { + DEBUG(1, ("talloc_strdup failed.\n")); + goto done; + } + + p = copy; + while ( (n = strchr(p, '%')) != NULL) { + *n = '\0'; + n++; + if ( *n == '\0' ) { + DEBUG(1, ("format error, single %% at the end of the template.\n")); + goto done; + } + switch( *n ) { + case 'u': + if (username == NULL) { + DEBUG(1, ("Cannot expand user name template " + "because user name is empty.\n")); + goto done; + } + result = talloc_asprintf_append(result, "%s%s", p, + username); + break; + + case 'U': + if (uid == 0) { + DEBUG(1, ("Cannot expand uid template " + "because uid is invalid.\n")); + goto done; + } + result = talloc_asprintf_append(result, "%s%d", p, + uid); + break; + + case 'd': + if (domain == NULL) { + DEBUG(1, ("Cannot expand domain name template " + "because domain name is empty.\n")); + goto done; + } + result = talloc_asprintf_append(result, "%s%s", p, + domain); + break; + + case 'f': + if (domain == NULL || username == NULL) { + DEBUG(1, ("Cannot expand fully qualified name template " + "because domain or user name is empty.\n")); + goto done; + } + result = talloc_asprintf_append(result, "%s%s@%s", p, + username, domain); + break; + + case '%': + result = talloc_asprintf_append(result, "%s%%", p); + break; + + default: + DEBUG(1, ("format error, unknown template [%%%c].\n", *n)); + goto done; + } + + if (result == NULL) { + DEBUG(1, ("talloc_asprintf_append failed.\n")); + goto done; + } + + p = n + 1; + } + + result = talloc_asprintf_append(result, "%s", p); + if (result == NULL) { + DEBUG(1, ("talloc_asprintf_append failed.\n")); + goto done; + } + + res = talloc_move(mem_ctx, &result); +done: + talloc_zfree(tmp_ctx); + return res; +} static gid_t get_gid_override(struct ldb_message *msg, struct sss_domain_info *dom) @@ -178,6 +286,25 @@ static gid_t get_gid_override(struct ldb_message *msg, ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0); } +static const char *get_homedir_override(TALLOC_CTX *mem_ctx, + struct ldb_message *msg, + struct nss_ctx *nctx, + struct sss_domain_info *dom, + const char *name, + uint32_t uid) +{ + if (dom->override_homedir) { + return expand_homedir_template(mem_ctx, dom->override_homedir, + name, uid, dom->name); + } else if (nctx->override_homedir) { + return expand_homedir_template(mem_ctx, nctx->override_homedir, + name, uid, dom->name); + } + + return talloc_strdup(mem_ctx, + ldb_msg_find_attr_as_string(msg, SYSDB_HOMEDIR, NULL)); +} + static int fill_pwent(struct sss_packet *packet, struct sss_domain_info *dom, struct nss_ctx *nctx, @@ -203,6 +330,7 @@ static int fill_pwent(struct sss_packet *packet, const char *namefmt = nctx->rctx->names->fq_fmt; bool packet_initialized = false; int ncret; + TALLOC_CTX *tmp_ctx = NULL; if (add_domain) dom_len = strlen(domain); @@ -210,6 +338,9 @@ static int fill_pwent(struct sss_packet *packet, num = 0; for (i = 0; i < *count; i++) { + talloc_zfree(tmp_ctx); + tmp_ctx = talloc_new(NULL); + msg = msgs[i]; name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); @@ -241,7 +372,7 @@ static int fill_pwent(struct sss_packet *packet, } gecos = ldb_msg_find_attr_as_string(msg, SYSDB_GECOS, NULL); - homedir = ldb_msg_find_attr_as_string(msg, SYSDB_HOMEDIR, NULL); + homedir = get_homedir_override(tmp_ctx, msg, nctx, dom, name, uid); shell = ldb_msg_find_attr_as_string(msg, SYSDB_SHELL, NULL); if (!gecos) gecos = ""; @@ -306,6 +437,7 @@ static int fill_pwent(struct sss_packet *packet, num++; } + talloc_zfree(tmp_ctx); done: *count = i; |