diff -up sudo-1.8.6p3/plugins/sudoers/sssd.c.netgrfilterfix sudo-1.8.6p3/plugins/sudoers/sssd.c --- sudo-1.8.6p3/plugins/sudoers/sssd.c.netgrfilterfix 2014-07-30 13:29:47.713823996 +0200 +++ sudo-1.8.6p3/plugins/sudoers/sssd.c 2014-07-30 13:30:08.917436088 +0200 @@ -614,16 +615,13 @@ sudo_sss_check_host(struct sudo_sss_hand } /* - * Look for netgroup specifcations in the sudoUser attribute and - * if found, filter according to netgroup membership. - * returns: - * true -> netgroup spec found && negroup member - * false -> netgroup spec found && not a meber of netgroup - * true -> netgroup spec not found (filtered by SSSD already, netgroups are an exception) + * SSSD doesn't handle netgroups, we have to ensure they are correctly filtered + * in sudo. The rules may contain mixed sudoUser specification so we have to check + * not only for netgroup membership but also for user and group matches. */ -bool sudo_sss_filter_user_netgroup(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule) +bool sudo_sss_filter_sudoUser(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule) { - bool ret = false, netgroup_spec_found = false; + bool ret = false; char **val_array, *val; int i; debug_decl(sudo_sss_check_user_netgroup, SUDO_DEBUG_SSSD); @@ -641,21 +639,48 @@ bool sudo_sss_filter_user_netgroup(struc sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values(sudoUser): != 0"); debug_return_bool(ret); } - + /* + * Scan sudoUser values and look for netgroup specs. + * Netgroup-only rule specification should be filtered + * out if the user isn't member of any specified netgroup. + */ for (i = 0; val_array[i] != NULL && !ret; ++i) { val = val_array[i]; - if (*val == '+') { - netgroup_spec_found = true; - } sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val); - if (strcmp(val, "ALL") == 0 || netgr_matches(val, NULL, NULL, user_name)) { - ret = true; - sudo_debug_printf(SUDO_DEBUG_DIAG, - "sssd/ldap sudoUser '%s' ... MATCH! (%s)", val, user_name); + if (*val == '+') { + /* Netgroup spec found, check netgroup membership */ + if (netgr_matches(val, NULL, NULL, handle->pw->pw_name)) { + ret = true; + sudo_debug_printf(SUDO_DEBUG_DIAG, + "sssd/ldap sudoUser '%s' ... MATCH! (%s)", val, handle->pw->pw_name); + } + } else { + /* + * Non-netgroup sudoUser value + */ + if (strcmp(val, "ALL") == 0) { + ret = true; + } else { + const char *match_val = (*val == '!' ? val + 1 : val); + const bool negated = (*val == '!' ? true : false); + const bool group_spec = (*match_val == '%' ? true : false); + + if (group_spec) { + if (usergr_matches(match_val, + handle->pw->pw_name, handle->pw)) { + ret = !negated; + } + } else { + if (userpw_matches(match_val, + handle->pw->pw_name, handle->pw)) { + ret = !negated; + } + } + } } } handle->fn_free_values(val_array); - debug_return_bool(netgroup_spec_found ? ret : true); + debug_return_bool(ret); } static int @@ -666,7 +691,7 @@ sudo_sss_result_filterp(struct sudo_sss_ debug_decl(sudo_sss_result_filterp, SUDO_DEBUG_SSSD); if (sudo_sss_check_host(handle, rule) && - sudo_sss_filter_user_netgroup(handle, rule)) + sudo_sss_filter_sudoUser(handle, rule)) debug_return_int(1); else debug_return_int(0);