[sudo-workers] Supporting sudoUser:!foo in sudo.ldap
Todd C. Miller
Todd.Miller at sudo.ws
Mon Jan 17 19:19:33 MST 2022
On Mon, 17 Jan 2022 12:00:07 +1030, Simon Lees wrote:
> Now I'm back from Summer Holidays here is round 2 that implements the
> same Idea for everything.
>
> Given the patch is larger i'm happy to upload it somewhere else if that
> works better.
I had to make a few changes but the following works for me in limited
testing. I got rid of the magic numbers to make it easier to match
the length checks to the string concatenation and reorderd a few
things.
- todd
diff -r d1a097783717 -r ab52defce8db plugins/sudoers/ldap.c
--- a/plugins/sudoers/ldap.c Wed Jan 12 15:30:39 2022 -0700
+++ b/plugins/sudoers/ldap.c Mon Jan 17 19:17:13 2022 -0700
@@ -928,7 +928,8 @@ done:
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 +941,45 @@ 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);
- /* Then add (|(sudoUser=USERNAME)(sudoUser=#uid)(sudoUser=ALL)) + NUL */
- sz += 29 + (12 + MAX_UID_T_LEN) + sudo_ldap_value_len(pw->pw_name);
+ /* 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)(!(|)))");
+
+ /* 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 +988,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. */
@@ -988,12 +1000,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
@@ -1009,23 +1021,35 @@ 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 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 +1059,9 @@ 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) {
@@ -1046,6 +1073,9 @@ sudo_ldap_build_pass1(LDAP *ld, struct p
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 +1093,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) {
@@ -1079,8 +1117,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__);
@@ -1097,6 +1137,7 @@ bad:
free(ng);
}
free(buf);
+ free(notbuf);
debug_return_str(NULL);
}
More information about the sudo-workers
mailing list