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:
@@ -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);
|
||||
|
Reference in New Issue
Block a user