From bb99464edf36b92ca1eef61befd22e2c683ec4013ce0a9c7e1b739cd3c0bcd08 Mon Sep 17 00:00:00 2001 From: Kristyna Streitova Date: Mon, 31 Jan 2022 08:20:47 +0000 Subject: [PATCH] Accepting request 949359 from home:simotek:branches:Base:System - Add support in the LDAP filter for negated users, patch taken from upstream (jsc#20068) * Adds sudo-feature-negated-LDAP-users.patch OBS-URL: https://build.opensuse.org/request/show/949359 OBS-URL: https://build.opensuse.org/package/show/Base:System/sudo?expand=0&rev=206 --- sudo-feature-negated-LDAP-users.patch | 295 ++++++++++++++++++++++++++ sudo.changes | 7 + sudo.spec | 2 + 3 files changed, 304 insertions(+) create mode 100644 sudo-feature-negated-LDAP-users.patch diff --git a/sudo-feature-negated-LDAP-users.patch b/sudo-feature-negated-LDAP-users.patch new file mode 100644 index 0000000..1c59dd7 --- /dev/null +++ b/sudo-feature-negated-LDAP-users.patch @@ -0,0 +1,295 @@ +From e88087721be391ec851b3cad8a88a5476f03d317 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Tue, 18 Jan 2022 11:20:22 -0700 +Subject: [PATCH] Add support in the LDAP filter for negated users. Based on a + diff from Simon Lees + +--- + docs/sudoers.ldap.man.in | 31 ++++------ + docs/sudoers.ldap.mdoc.in | 28 ++++----- + plugins/sudoers/ldap.c | 116 ++++++++++++++++++++++++++++---------- + 3 files changed, 109 insertions(+), 66 deletions(-) + +diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c +index 4b768fdfb..e3c47b9bc 100644 +--- a/plugins/sudoers/ldap.c ++++ b/plugins/sudoers/ldap.c +@@ -1,7 +1,7 @@ + /* + * SPDX-License-Identifier: ISC + * +- * Copyright (c) 2003-2020 Todd C. Miller ++ * Copyright (c) 2003-2022 Todd C. Miller + * + * This code is derived from software contributed by Aaron Spangler. + * +@@ -315,18 +315,18 @@ sudo_ldap_get_values_len(LDAP *ld, LDAPMessage *entry, char *attr, int *rc) + /* + * Walk through search results and return true if we have a matching + * non-Unix group (including netgroups), else false. ++ * A matching entry that is negated will always return false. + */ + static int + sudo_ldap_check_non_unix_group(LDAP *ld, LDAPMessage *entry, struct passwd *pw) + { + struct berval **bv, **p; + bool ret = false; +- char *val; + int rc; + debug_decl(sudo_ldap_check_non_unix_group, SUDOERS_DEBUG_LDAP); + + if (!entry) +- debug_return_bool(ret); ++ debug_return_bool(false); + + /* get the values from the entry */ + bv = sudo_ldap_get_values_len(ld, entry, "sudoUser", &rc); +@@ -338,18 +338,29 @@ sudo_ldap_check_non_unix_group(LDAP *ld, LDAPMessage *entry, struct passwd *pw) + + /* walk through values */ + for (p = bv; *p != NULL && !ret; p++) { +- val = (*p)->bv_val; ++ bool negated = false; ++ char *val = (*p)->bv_val; ++ ++ if (*val == '!') { ++ val++; ++ negated = true; ++ } + if (*val == '+') { + if (netgr_matches(val, def_netgroup_tuple ? user_runhost : NULL, + def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name)) + ret = true; +- DPRINTF2("ldap sudoUser netgroup '%s' ... %s", val, +- ret ? "MATCH!" : "not"); ++ DPRINTF2("ldap sudoUser netgroup '%s%s' ... %s", ++ negated ? "!" : "", val, ret ? "MATCH!" : "not"); + } else { + if (group_plugin_query(pw->pw_name, val + 2, pw)) + ret = true; +- DPRINTF2("ldap sudoUser non-Unix group '%s' ... %s", val, +- ret ? "MATCH!" : "not"); ++ DPRINTF2("ldap sudoUser non-Unix group '%s%s' ... %s", ++ negated ? "!" : "", val, ret ? "MATCH!" : "not"); ++ } ++ /* A negated match overrides all other entries. */ ++ if (ret && negated) { ++ ret = false; ++ break; + } + } + +@@ -928,7 +939,8 @@ sudo_netgroup_lookup(LDAP *ld, struct passwd *pw, + static char * + sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) + { +- char *buf, timebuffer[TIMEFILTER_LENGTH + 1], idbuf[MAX_UID_T_LEN + 1]; ++ char timebuffer[TIMEFILTER_LENGTH + 1], idbuf[MAX_UID_T_LEN + 1]; ++ char *buf, *notbuf; + struct ldap_netgroup_list netgroups; + struct ldap_netgroup *ng = NULL; + struct gid_list *gidlist; +@@ -940,34 +952,45 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) + + STAILQ_INIT(&netgroups); + +- /* If there is a filter, allocate space for the global AND. */ +- if (ldap_conf.timed || ldap_conf.search_filter) ++ if (ldap_conf.timed || ldap_conf.search_filter) { ++ /* Allocate space for the global AND. */ + sz += 3; + +- /* Add LDAP search filter if present. */ +- if (ldap_conf.search_filter) +- sz += strlen(ldap_conf.search_filter); ++ /* Add LDAP search filter if present. */ ++ if (ldap_conf.search_filter) ++ sz += strlen(ldap_conf.search_filter); ++ ++ /* If timed, add space for time limits. */ ++ if (ldap_conf.timed) ++ sz += TIMEFILTER_LENGTH; ++ } ++ ++ /* Add space for the global OR clause + (sudoUser=ALL) + NOT + NUL. */ ++ sz += sizeof("(|(sudoUser=ALL)(!(|)))"); + +- /* Then add (|(sudoUser=USERNAME)(sudoUser=#uid)(sudoUser=ALL)) + NUL */ +- sz += 29 + (12 + MAX_UID_T_LEN) + sudo_ldap_value_len(pw->pw_name); ++ /* Add space for username and uid, including the negated versions. */ ++ sz += ((sizeof("(sudoUser=)(sudoUser=#)") - 1 + ++ sudo_ldap_value_len(pw->pw_name) + MAX_UID_T_LEN) * 2) + 2; + + /* Add space for primary and supplementary groups and gids */ + if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) { +- sz += 12 + sudo_ldap_value_len(grp->gr_name); ++ sz += ((sizeof("(sudoUser=%)") - 1 + ++ sudo_ldap_value_len(grp->gr_name)) * 2) + 1; + } +- sz += 13 + MAX_UID_T_LEN; ++ sz += ((sizeof("(sudoUser=%#)") - 1 + MAX_UID_T_LEN) * 2) + 1; + if ((grlist = sudo_get_grlist(pw)) != NULL) { + for (i = 0; i < grlist->ngroups; i++) { + if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0) + continue; +- sz += 12 + sudo_ldap_value_len(grlist->groups[i]); ++ sz += ((sizeof("(sudoUser=%)") - 1 + ++ sudo_ldap_value_len(grlist->groups[i])) * 2) + 1; + } + } + if ((gidlist = sudo_get_gidlist(pw, ENTRY_TYPE_ANY)) != NULL) { + for (i = 0; i < gidlist->ngids; i++) { + if (pw->pw_gid == gidlist->gids[i]) + continue; +- sz += 13 + MAX_UID_T_LEN; ++ sz += ((sizeof("(sudoUser=%#)") - 1 + MAX_UID_T_LEN) * 2) + 1; + } + } + +@@ -976,7 +999,7 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) + DPRINTF1("Looking up netgroups for %s", pw->pw_name); + if (sudo_netgroup_lookup(ld, pw, &netgroups)) { + STAILQ_FOREACH(ng, &netgroups, entries) { +- sz += 14 + strlen(ng->name); ++ sz += ((sizeof("(sudoUser=+)") - 1 + strlen(ng->name)) * 2) + 1; + } + } else { + /* sudo_netgroup_lookup() failed, clean up. */ +@@ -988,12 +1011,12 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) + } + } + +- /* If timed, add space for time limits. */ +- if (ldap_conf.timed) +- sz += TIMEFILTER_LENGTH; +- if ((buf = malloc(sz)) == NULL) ++ buf = malloc(sz); ++ notbuf = malloc(sz); ++ if (buf == NULL || notbuf == NULL) + goto bad; + *buf = '\0'; ++ *notbuf = '\0'; + + /* + * If timed or using a search filter, start a global AND clause to +@@ -1009,23 +1032,35 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) + CHECK_STRLCAT(buf, "(|(sudoUser=", sz); + CHECK_LDAP_VCAT(buf, pw->pw_name, sz); + CHECK_STRLCAT(buf, ")", sz); ++ CHECK_STRLCAT(notbuf, "(sudoUser=!", sz); ++ CHECK_LDAP_VCAT(notbuf, pw->pw_name, sz); ++ CHECK_STRLCAT(notbuf, ")", sz); + + /* Append user-ID */ + (void) snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int)pw->pw_uid); + CHECK_STRLCAT(buf, "(sudoUser=#", sz); + CHECK_STRLCAT(buf, idbuf, sz); + CHECK_STRLCAT(buf, ")", sz); ++ CHECK_STRLCAT(notbuf, "(sudoUser=!#", sz); ++ CHECK_STRLCAT(notbuf, idbuf, sz); ++ CHECK_STRLCAT(notbuf, ")", sz); + + /* Append primary group and group-ID */ + if (grp != NULL) { + CHECK_STRLCAT(buf, "(sudoUser=%", sz); + CHECK_LDAP_VCAT(buf, grp->gr_name, sz); + CHECK_STRLCAT(buf, ")", sz); ++ CHECK_STRLCAT(notbuf, "(sudoUser=!%", sz); ++ CHECK_LDAP_VCAT(notbuf, grp->gr_name, sz); ++ CHECK_STRLCAT(notbuf, ")", sz); + } + (void) snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int)pw->pw_gid); + CHECK_STRLCAT(buf, "(sudoUser=%#", sz); + CHECK_STRLCAT(buf, idbuf, sz); + CHECK_STRLCAT(buf, ")", sz); ++ CHECK_STRLCAT(notbuf, "(sudoUser=!%#", sz); ++ CHECK_STRLCAT(notbuf, idbuf, sz); ++ CHECK_STRLCAT(notbuf, ")", sz); + + /* Append supplementary groups and group-IDs */ + if (grlist != NULL) { +@@ -1035,6 +1070,9 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) + CHECK_STRLCAT(buf, "(sudoUser=%", sz); + CHECK_LDAP_VCAT(buf, grlist->groups[i], sz); + CHECK_STRLCAT(buf, ")", sz); ++ CHECK_STRLCAT(notbuf, "(sudoUser=!%", sz); ++ CHECK_LDAP_VCAT(notbuf, grlist->groups[i], sz); ++ CHECK_STRLCAT(notbuf, ")", sz); + } + } + if (gidlist != NULL) { +@@ -1046,6 +1084,9 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) + CHECK_STRLCAT(buf, "(sudoUser=%#", sz); + CHECK_STRLCAT(buf, idbuf, sz); + CHECK_STRLCAT(buf, ")", sz); ++ CHECK_STRLCAT(notbuf, "(sudoUser=!%#", sz); ++ CHECK_STRLCAT(notbuf, idbuf, sz); ++ CHECK_STRLCAT(notbuf, ")", sz); + } + } + +@@ -1063,12 +1104,20 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) + CHECK_STRLCAT(buf, "(sudoUser=+", sz); + CHECK_LDAP_VCAT(buf, ng->name, sz); + CHECK_STRLCAT(buf, ")", sz); ++ CHECK_STRLCAT(notbuf, "(sudoUser=!+", sz); ++ CHECK_LDAP_VCAT(notbuf, ng->name, sz); ++ CHECK_STRLCAT(notbuf, ")", sz); + free(ng->name); + free(ng); + } + +- /* Add ALL to list and end the global OR. */ +- CHECK_STRLCAT(buf, "(sudoUser=ALL)", sz); ++ /* Add ALL to list. */ ++ CHECK_STRLCAT(buf, "(sudoUser=ALL))", sz); ++ ++ /* Add filter for negated entries. */ ++ CHECK_STRLCAT(buf, "(!(|", sz); ++ CHECK_STRLCAT(buf, notbuf, sz); ++ CHECK_STRLCAT(buf, ")", sz); + + /* Add the time restriction, or simply end the global OR. */ + if (ldap_conf.timed) { +@@ -1079,8 +1128,10 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) + } else if (ldap_conf.search_filter) { + CHECK_STRLCAT(buf, ")", sz); /* closes the global OR */ + } ++ + CHECK_STRLCAT(buf, ")", sz); /* closes the global OR or the global AND */ + ++ free(notbuf); + debug_return_str(buf); + overflow: + sudo_warnx(U_("internal error, %s overflow"), __func__); +@@ -1097,6 +1148,7 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) + free(ng); + } + free(buf); ++ free(notbuf); + debug_return_str(NULL); + } + +@@ -1133,16 +1185,18 @@ sudo_ldap_build_pass2(void) + * those get ANDed in to the expression. + */ + if (query_netgroups && def_group_plugin) { +- len = asprintf(&filt, "%s%s(|(sudoUser=+*)(sudoUser=%%:*))%s%s", ++ len = asprintf(&filt, "%s%s(|(sudoUser=+*)(sudoUser=!+*)(sudoUser=%%:*)(sudoUser=!%%:*))%s%s", + (ldap_conf.timed || ldap_conf.search_filter) ? "(&" : "", + ldap_conf.search_filter ? ldap_conf.search_filter : "", + ldap_conf.timed ? timebuffer : "", + (ldap_conf.timed || ldap_conf.search_filter) ? ")" : ""); + } else { +- len = asprintf(&filt, "(&%s(sudoUser=*)(sudoUser=%s*)%s)", ++ len = asprintf(&filt, "%s%s(|(sudoUser=%s*)(sudoUser=!%s*))%s%s", ++ (ldap_conf.timed || ldap_conf.search_filter) ? "(&" : "", + ldap_conf.search_filter ? ldap_conf.search_filter : "", +- query_netgroups ? "+" : "%:", +- ldap_conf.timed ? timebuffer : ""); ++ query_netgroups ? "+" : "%:", query_netgroups ? "+" : "%:", ++ ldap_conf.timed ? timebuffer : "", ++ (ldap_conf.timed || ldap_conf.search_filter) ? ")" : ""); + } + if (len == -1) + filt = NULL; diff --git a/sudo.changes b/sudo.changes index 692583d..e9c39c8 100644 --- a/sudo.changes +++ b/sudo.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Thu Jan 27 03:00:26 UTC 2022 - Simon Lees + +- Add support in the LDAP filter for negated users, patch taken + from upstream (jsc#20068) + * Adds sudo-feature-negated-LDAP-users.patch + ------------------------------------------------------------------- Wed Sep 22 12:27:51 UTC 2021 - Kristyna Streitova diff --git a/sudo.spec b/sudo.spec index 48730b6..9c1c846 100644 --- a/sudo.spec +++ b/sudo.spec @@ -38,6 +38,8 @@ Source6: fate_313276_test.sh Source7: README_313276.test # PATCH-OPENSUSE: the "SUSE" branding of the default sudo config Patch0: sudo-sudoers.patch +# PATCH-Upstream fixes jira SLE-20068 - sflees@suse.de +Patch1: sudo-feature-negated-LDAP-users.patch BuildRequires: audit-devel BuildRequires: cyrus-sasl-devel BuildRequires: groff