2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-31 14:25:15 +00:00

When iterating over returned LDAP entries, keep looking at remaining

matches even if we have a positive match.  This catches negative
matches that may exist in other entries and more closely match the
sudoers file behavior.
This commit is contained in:
Todd C. Miller
2010-10-01 12:17:01 -04:00
parent acaceb4242
commit a627c60deb

View File

@@ -116,6 +116,11 @@
#define SUDO_LDAP_SSL 1
#define SUDO_LDAP_STARTTLS 2
struct ldap_result_list {
struct ldap_result_list *next;
LDAPMessage *result;
};
struct ldap_config_table {
const char *conf_str; /* config file string */
short type; /* CONF_BOOL, CONF_INT, CONF_STR */
@@ -1795,12 +1800,13 @@ sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
{
struct ldap_config_list_str *base;
LDAP *ld = (LDAP *) nss->handle;
LDAPMessage *entry, *result;
LDAPMessage *entry, *result, *matching_entry = NULL;
char *filt;
int do_netgr, rc, matched;
int do_netgr, rc, allowed = UNSPEC;
int setenv_implied;
int ldap_user_matches = FALSE, ldap_host_matches = FALSE;
struct passwd *pw = list_pw ? list_pw : sudo_user.pw;
struct ldap_result_list *rl, *results = NULL;
if (ld == NULL)
return(ret);
@@ -1810,7 +1816,7 @@ sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
enum def_tupple pwcheck =
(pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) {
for (allowed = 0, do_netgr = 0; !allowed && do_netgr < 2; do_netgr++) {
filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
for (base = ldap_conf.base; base != NULL; base = base->next) {
result = NULL;
@@ -1834,7 +1840,7 @@ sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
if (user_uid == 0 || list_pw == NULL ||
user_uid == list_pw->pw_uid ||
sudo_ldap_check_command(ld, entry, NULL)) {
matched = 1;
allowed = 1;
break; /* end foreach */
}
}
@@ -1843,7 +1849,7 @@ sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
}
efree(filt);
}
if (matched || user_uid == 0) {
if (allowed || user_uid == 0) {
SET(ret, VALIDATE_OK);
CLR(ret, VALIDATE_NOT_OK);
if (def_authenticate) {
@@ -1882,10 +1888,10 @@ sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
* try to match them against the username.
*/
setenv_implied = FALSE;
for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) {
for (do_netgr = 0; allowed != FALSE && do_netgr < 2; do_netgr++) {
filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
DPRINTF(("ldap search '%s'", filt), 1);
for (base = ldap_conf.base; base != NULL; base = base->next) {
for (base = ldap_conf.base; allowed != FALSE && base != NULL; base = base->next) {
result = NULL;
rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt,
NULL, 0, NULL, NULL, NULL, 0, &result);
@@ -1894,6 +1900,12 @@ sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
continue;
}
/* Add result to list for later free()ing. */
rl = emalloc(sizeof(*rl));
rl->result = result;
rl->next = results;
results = rl;
/* parse each entry returned from this most recent search */
LDAP_FOREACH(entry, ld, result) {
DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
@@ -1913,34 +1925,46 @@ sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
) {
/* We have a match! */
DPRINTF(("Command %sallowed", rc == TRUE ? "" : "NOT "), 1);
matched = TRUE;
if (rc == TRUE) {
/* pick up any options */
if (setenv_implied)
def_setenv = TRUE;
sudo_ldap_parse_options(ld, entry);
#ifdef HAVE_SELINUX
/* Set role and type if not specified on command line. */
if (user_role == NULL)
user_role = def_role;
if (user_type == NULL)
user_type = def_type;
#endif /* HAVE_SELINUX */
/* make sure we don't reenter loop */
SET(ret, VALIDATE_OK);
CLR(ret, VALIDATE_NOT_OK);
} else {
SET(ret, VALIDATE_NOT_OK);
CLR(ret, VALIDATE_OK);
if (rc == FALSE) {
/* Command explicitly denied, we are done. */
allowed = FALSE;
break;
} else if (rc == TRUE && allowed == UNSPEC) {
/* Command allowed, no other matches yet. */
allowed = TRUE;
matching_entry = entry;
}
/* break from inside for loop */
break;
}
}
ldap_msgfree(result);
}
efree(filt);
}
if (allowed == TRUE) {
SET(ret, VALIDATE_OK);
CLR(ret, VALIDATE_NOT_OK);
/* Set options based on matching entry. */
if (setenv_implied)
def_setenv = TRUE;
sudo_ldap_parse_options(ld, matching_entry);
#ifdef HAVE_SELINUX
/* Set role and type if not specified on command line. */
if (user_role == NULL)
user_role = def_role;
if (user_type == NULL)
user_type = def_type;
#endif /* HAVE_SELINUX */
} else if (allowed == FALSE) {
SET(ret, VALIDATE_NOT_OK);
CLR(ret, VALIDATE_OK);
}
/* Free all results. */
while ((rl = results) != NULL) {
results = results->next;
ldap_msgfree(rl->result);
efree(rl);
}
done:
DPRINTF(("user_matches=%d", ldap_user_matches), 1);