Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15:Update
sudo
feature-not-user-ldap.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File feature-not-user-ldap.patch of Package sudo
From e88087721be391ec851b3cad8a88a5476f03d317 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" <Todd.Miller@sudo.ws> 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(-) Index: sudo-1.8.27/plugins/sudoers/ldap.c =================================================================== --- sudo-1.8.27.orig/plugins/sudoers/ldap.c +++ sudo-1.8.27/plugins/sudoers/ldap.c @@ -314,18 +314,18 @@ sudo_ldap_get_values_len(LDAP *ld, LDAPM /* * 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); @@ -337,18 +337,29 @@ sudo_ldap_check_non_unix_group(LDAP *ld, /* 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; } } @@ -900,7 +911,8 @@ done: static char * sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) { - char *buf, timebuffer[TIMEFILTER_LENGTH + 1], gidbuf[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; @@ -913,33 +925,44 @@ sudo_ldap_build_pass1(LDAP *ld, struct p 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; + } - /* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */ - sz += 29 + sudo_ldap_value_len(pw->pw_name); + /* Add space for the global OR clause + (sudoUser=ALL) + NOT + NUL. */ + sz += sizeof("(|(sudoUser=ALL)(!(|)))"); + + /* 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; } } @@ -948,7 +971,7 @@ sudo_ldap_build_pass1(LDAP *ld, struct p 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. */ @@ -960,12 +983,12 @@ sudo_ldap_build_pass1(LDAP *ld, struct p } } - /* 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 @@ -981,17 +1004,26 @@ sudo_ldap_build_pass1(LDAP *ld, struct p 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 primary group and gid */ 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(gidbuf, sizeof(gidbuf), "%u", (unsigned int)pw->pw_gid); + (void) snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int)pw->pw_gid); CHECK_STRLCAT(buf, "(sudoUser=%#", sz); - CHECK_STRLCAT(buf, gidbuf, 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 gids */ if (grlist != NULL) { @@ -1001,17 +1033,23 @@ sudo_ldap_build_pass1(LDAP *ld, struct p 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) { for (i = 0; i < gidlist->ngids; i++) { if (pw->pw_gid == gidlist->gids[i]) continue; - (void) snprintf(gidbuf, sizeof(gidbuf), "%u", + (void) snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int)gidlist->gids[i]); CHECK_STRLCAT(buf, "(sudoUser=%#", sz); - CHECK_STRLCAT(buf, gidbuf, sz); + CHECK_STRLCAT(buf, idbuf, sz); CHECK_STRLCAT(buf, ")", sz); + CHECK_STRLCAT(notbuf, "(sudoUser=!%#", sz); + CHECK_STRLCAT(notbuf, idbuf, sz); + CHECK_STRLCAT(notbuf, ")", sz); } } @@ -1029,12 +1067,20 @@ sudo_ldap_build_pass1(LDAP *ld, struct p 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) { @@ -1045,8 +1091,10 @@ sudo_ldap_build_pass1(LDAP *ld, struct p } 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__); @@ -1063,6 +1111,7 @@ bad: free(ng); } free(buf); + free(notbuf); debug_return_str(NULL); } @@ -1099,16 +1148,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;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor