diff --git a/src/config/SSSDConfig/sssdoptions.py b/src/config/SSSDConfig/sssdoptions.py index f3234781c88..163b7b2b3f8 100644 --- a/src/config/SSSDConfig/sssdoptions.py +++ b/src/config/SSSDConfig/sssdoptions.py @@ -466,6 +466,8 @@ def __init__(self): 'ldap_group_nesting_level': _('Maximum nesting level SSSD will follow'), 'ldap_group_search_filter': _('Filter for group lookups'), 'ldap_group_search_scope': _('Scope of group lookups'), + 'ldap_group_absent_gid_local': _('Use gid from /etc/group if group has no LDAP gid attribute'), + 'ldap_group_negative_gid_local': _('Use gid from /etc/group if LDAP gid is negative'), 'ldap_netgroup_search_base': _('Base DN for netgroup lookups'), 'ldap_netgroup_object_class': _('Objectclass for netgroups'), diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini index d37ca3ae21c..989ba6f5c28 100644 --- a/src/config/cfg_rules.ini +++ b/src/config/cfg_rules.ini @@ -635,12 +635,14 @@ option = ldap_enumeration_refresh_timeout option = ldap_enumeration_refresh_offset option = ldap_enumeration_search_timeout option = ldap_force_upper_case_realm +option = ldap_group_absent_gid_local option = ldap_group_entry_usn option = ldap_group_external_member option = ldap_group_gid_number option = ldap_group_member option = ldap_group_modify_timestamp option = ldap_group_name +option = ldap_group_negative_gid_local option = ldap_group_nesting_level option = ldap_group_object_class option = ldap_group_objectsid diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml index 430171632ce..7f35b6d7999 100644 --- a/src/man/sssd-ldap.5.xml +++ b/src/man/sssd-ldap.5.xml @@ -1006,6 +1006,56 @@ + + ldap_group_negative_gid_local + + + Enables merging LDAP groups with negative gid values + with local groups of the same name, picking up the + local gid. This is intended for assigning system + groups to users, e.g. the audio or bluetooth groups. + Any negative value is accepted in order to allow + the LDAP server to enforce uniqueness constraints on + gids for other groups. This option is preferable + over the one below (gid attribute entirely absent) + since it has a lower risk of unintended side effects. + + + Note this specifically checks local groups in + /etc/group; other sources of group IDs are not + considered. It must be combined with + "files [SUCCESS=merge] sss" in /etc/nssswitch.conf. + + + Default: False + + + + + + ldap_group_absent_gid_local + + + Enables merging LDAP groups without gid attribute + with local groups of the same name, picking up the + local gid. This is intended for assigning system + groups to users, e.g. the audio or bluetooth groups. + Note that this may result in mapping some LDAP groups + that were not intended as POSIX groups, if they have + the same name. + + + Note this specifically checks local groups in + /etc/group; other sources of group IDs are not + considered. It must be combined with + "files [SUCCESS=merge] sss" in /etc/nssswitch.conf. + + + Default: False + + + + ldap_sasl_mech (string) diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c index c6ea741e4f0..88cb0eef578 100644 --- a/src/providers/ldap/ldap_opts.c +++ b/src/providers/ldap/ldap_opts.c @@ -48,6 +48,8 @@ struct dp_option default_basic_opts[] = { { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_group_absent_gid_local", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_group_negative_gid_local", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, { "ldap_host_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_service_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_sudo_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index aaed7d0fd74..4307e69f846 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -155,6 +155,8 @@ enum sdap_basic_opt { SDAP_GROUP_SEARCH_BASE, SDAP_GROUP_SEARCH_SCOPE, SDAP_GROUP_SEARCH_FILTER, + SDAP_GROUP_ABSENT_GID_LOCAL, + SDAP_GROUP_NEGATIVE_GID_LOCAL, SDAP_HOST_SEARCH_BASE, SDAP_SERVICE_SEARCH_BASE, SDAP_SUDO_SEARCH_BASE, diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c index 6d0c7e49907..dfd51aca6ad 100644 --- a/src/providers/ldap/sdap_async_groups.c +++ b/src/providers/ldap/sdap_async_groups.c @@ -629,6 +629,10 @@ static int sdap_save_group(TALLOC_CTX *memctx, group_name, dom->name); ret = EINVAL; goto done; + } else { + DEBUG(SSSDBG_TRACE_FUNC, + "gid provided for [%s] in domain [%s] is %d.\n", + group_name, dom->name, (int)gid); } } } @@ -1893,6 +1897,84 @@ static void sdap_search_group_copy_batch(struct sdap_get_groups_state *state, struct sysdb_attrs **groups, size_t count); +static void sdap_group_apply_remap(struct sysdb_attrs *attrs, + struct sdap_options *opts) { + int ret; + const char *group_name = NULL; + int32_t gid = -1; + char buf[2048]; + char *grname, *p; + struct group gbuf, *gr; + + ret = sysdb_attrs_get_string( + attrs, opts->group_map[SDAP_AT_GROUP_NAME].sys_name, &group_name); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "GID remap: group has no group name?\n"); + return; + } + + ret = sysdb_attrs_get_int32_t( + attrs, opts->group_map[SDAP_AT_GROUP_GID].sys_name, &gid); + switch (ret) { + case EOK: + if (gid >= 0) + return; + if (!dp_opt_get_bool(opts->basic, SDAP_GROUP_NEGATIVE_GID_LOCAL)) + return; + break; + + case ENOENT: + if (!dp_opt_get_bool(opts->basic, SDAP_GROUP_ABSENT_GID_LOCAL)) + return; + break; + + default: + return; + } + + DEBUG(SSSDBG_TRACE_FUNC, "GID remap: checking group %s\n", group_name); + + FILE *etc_group = fopen("/etc/group", "r"); + if (!etc_group) { + DEBUG(SSSDBG_CRIT_FAILURE, "failed to open /etc/group: %s\n", + strerror(errno)); + return; + } + + grname = strdup(group_name); + p = strchr(grname, '@'); + if (p) + *p = '\0'; + + while (!fgetgrent_r(etc_group, &gbuf, buf, sizeof(buf), &gr)) { + if (strcmp(gr->gr_name, grname)) + continue; + + ret = sysdb_attrs_replace_name( + attrs, opts->group_map[SDAP_AT_GROUP_GID].sys_name, "origGid"); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "failed to rename gid attribute on %s\n", + group_name); + break; + } + + ret = sysdb_attrs_add_uint32( + attrs, opts->group_map[SDAP_AT_GROUP_GID].sys_name, gr->gr_gid); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "failed to add remapped gid attribute on %s\n", + group_name); + break; + } + + DEBUG(SSSDBG_TRACE_FUNC, "GID remap: group %s mapped to local gid %d\n", + group_name, (int)gr->gr_gid); + break; + } + + free(grname); + fclose(etc_group); +} + static void sdap_get_groups_process(struct tevent_req *subreq) { struct tevent_req *req = @@ -1936,6 +2018,9 @@ static void sdap_get_groups_process(struct tevent_req *subreq) return; } + for (i = 0; i < count; i++) + sdap_group_apply_remap(groups[i], state->opts); + sdap_search_group_copy_batch(state, groups, count); }