Add support for sudoers_search_filter setting in ldap.conf. This

can be used to restrict the set of records returned by the LDAP
query.
This commit is contained in:
Todd C. Miller
2011-03-18 09:38:42 -04:00
parent 13b9c7b17b
commit e8776da730
2 changed files with 81 additions and 24 deletions

View File

@@ -201,6 +201,7 @@ static struct ldap_config {
char *bindpw;
char *rootbinddn;
struct ldap_config_list_str *base;
char *search_filter;
char *ssl;
char *tls_cacertfile;
char *tls_cacertdir;
@@ -285,6 +286,7 @@ static struct ldap_config_table ldap_conf_table[] = {
{ "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
{ "sudoers_base", CONF_LIST_STR, FALSE, -1, &ldap_conf.base },
{ "sudoers_timed", CONF_BOOL, FALSE, -1, &ldap_conf.timed },
{ "sudoers_search_filter", CONF_STR, FALSE, -1, &ldap_conf.search_filter },
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
{ "use_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.use_sasl },
{ "sasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.sasl_auth_id },
@@ -949,6 +951,21 @@ done:
return bytes;
}
/*
* Builds up a filter to search for default settings
*/
static char *
sudo_ldap_build_default_filter()
{
char *filt;
if (ldap_conf.search_filter)
easprintf(&filt, "(&(%s)(cn=defaults))", ldap_conf.search_filter);
else
filt = estrdup("cn=defaults");
return filt;
}
/*
* Builds up a filter to check against LDAP.
*/
@@ -957,11 +974,15 @@ sudo_ldap_build_pass1(struct passwd *pw)
{
struct group *grp;
char *buf, timebuffer[TIMEFILTER_LENGTH];
size_t sz;
size_t sz = 0;
int i;
/* Start with (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
sz = 29 + strlen(pw->pw_name);
/* Start with LDAP search filter length + 3 */
if (ldap_conf.search_filter)
sz += strlen(ldap_conf.search_filter) + 3;
/* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
sz += 29 + strlen(pw->pw_name);
/* Add space for groups */
if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
@@ -984,12 +1005,15 @@ sudo_ldap_build_pass1(struct passwd *pw)
*buf = '\0';
/*
* If timed, start a global AND clause that will have the time limits
* as the second leg.
* If timed or using a search filter, start a global AND clause to
* contain the search filter, search criteria, and time restriction.
*/
if (ldap_conf.timed)
if (ldap_conf.timed || ldap_conf.search_filter)
(void) strlcpy(buf, "(&", sz);
if (ldap_conf.search_filter)
(void) strlcat(buf, ldap_conf.search_filter, sz);
/* Global OR + sudoUser=user_name filter */
(void) strlcat(buf, "(|(sudoUser=", sz);
(void) strlcat(buf, pw->pw_name, sz);
@@ -1024,6 +1048,8 @@ sudo_ldap_build_pass1(struct passwd *pw)
strlcat(buf, ")", sz); /* closes the global OR */
sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
strlcat(buf, timebuffer, sz);
} else if (ldap_conf.search_filter) {
strlcat(buf, ")", sz); /* closes the global OR */
}
strlcat(buf, ")", sz); /* closes the global OR or the global AND */
@@ -1036,21 +1062,23 @@ sudo_ldap_build_pass1(struct passwd *pw)
static char *
sudo_ldap_build_pass2(void)
{
char *buf, timebuffer[TIMEFILTER_LENGTH];
char *filt, timebuffer[TIMEFILTER_LENGTH];
if (ldap_conf.timed) {
/*
* If timed, use a global AND clause that has the time limit as
* as the second leg.
*/
if (ldap_conf.timed)
sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
easprintf(&buf, "(&(sudoUser=+*)%s)", timebuffer);
} else {
/* No time limit, just the netgroup selection. */
buf = estrdup("sudoUser=+*");
}
return buf;
/*
* Match all sudoUsers beginning with a '+'.
* If a search filter or time restriction is specified,
* those get ANDed in to the expression.
*/
easprintf(&filt, "%s%s(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) ? ")" : "");
return filt;
}
static void
@@ -1178,6 +1206,10 @@ sudo_ldap_read_config(void)
sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base %s\n",
"(NONE: LDAP disabled)");
}
if (ldap_conf.search_filter) {
sudo_printf(SUDO_CONV_ERROR_MSG, "search_filter %s\n",
ldap_conf.search_filter);
}
sudo_printf(SUDO_CONV_ERROR_MSG, "binddn %s\n",
ldap_conf.binddn ? ldap_conf.binddn : "(anonymous)");
sudo_printf(SUDO_CONV_ERROR_MSG, "bindpw %s\n",
@@ -1188,7 +1220,7 @@ sudo_ldap_read_config(void)
}
if (ldap_conf.timelimit > 0) {
sudo_printf(SUDO_CONV_ERROR_MSG, "timelimit %d\n",
ldap_conf.timelimit);
ldap_conf.timelimit);
}
sudo_printf(SUDO_CONV_ERROR_MSG, "ssl %s\n",
ldap_conf.ssl ? ldap_conf.ssl : "(no)");
@@ -1291,6 +1323,18 @@ sudo_ldap_read_config(void)
#endif
}
/* If search filter is not parenthesized, make it so. */
if (ldap_conf.search_filter && ldap_conf.search_filter[0] != '(') {
size_t len = strlen(ldap_conf.search_filter);
cp = ldap_conf.search_filter;
ldap_conf.search_filter = emalloc(len + 3);
ldap_conf.search_filter[0] = '(';
memcpy(ldap_conf.search_filter + 1, cp, len);
ldap_conf.search_filter[len + 1] = ')';
ldap_conf.search_filter[len + 2] = '\0';
efree(cp);
}
/* If rootbinddn set, read in /etc/ldap.secret if it exists. */
if (ldap_conf.rootbinddn)
sudo_ldap_read_secret(_PATH_LDAP_SECRET);
@@ -1361,13 +1405,14 @@ sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
struct sudo_ldap_handle *handle = nss->handle;
LDAP *ld;
LDAPMessage *entry, *result;
char *prefix;
char *prefix, *filt;
int rc, count = 0;
if (handle == NULL || handle->ld == NULL)
goto done;
ld = handle->ld;
filt = sudo_ldap_build_default_filter();
for (base = ldap_conf.base; base != NULL; base = base->next) {
if (ldap_conf.timeout > 0) {
tv.tv_sec = ldap_conf.timeout;
@@ -1376,7 +1421,7 @@ sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
}
result = NULL;
rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
"cn=defaults", NULL, 0, NULL, NULL, tvp, 0, &result);
filt, NULL, 0, NULL, NULL, tvp, 0, &result);
if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
bv = ldap_get_values_len(ld, entry, "sudoOption");
if (bv != NULL) {
@@ -1395,6 +1440,7 @@ sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
if (result)
ldap_msgfree(result);
}
efree(filt);
done:
return count;
}
@@ -2005,12 +2051,16 @@ sudo_ldap_setdefs(struct sudo_nss *nss)
struct timeval tv, *tvp = NULL;
LDAP *ld;
LDAPMessage *entry, *result;
char *filt;
int rc;
if (handle == NULL || handle->ld == NULL)
return -1;
ld = handle->ld;
filt = sudo_ldap_build_default_filter();
DPRINTF(("Looking for cn=defaults: %s", filt), 1);
for (base = ldap_conf.base; base != NULL; base = base->next) {
if (ldap_conf.timeout > 0) {
tv.tv_sec = ldap_conf.timeout;
@@ -2019,7 +2069,7 @@ sudo_ldap_setdefs(struct sudo_nss *nss)
}
result = NULL;
rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
"cn=defaults", NULL, 0, NULL, NULL, NULL, 0, &result);
filt, NULL, 0, NULL, NULL, NULL, 0, &result);
if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
sudo_ldap_parse_options(ld, entry);
@@ -2029,6 +2079,7 @@ sudo_ldap_setdefs(struct sudo_nss *nss)
if (result)
ldap_msgfree(result);
}
efree(filt);
return 0;
}
@@ -2062,7 +2113,7 @@ sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
enum def_tuple pwcheck =
(pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
for (i = 0; i < lres->nentries; i++) {
for (i = 0; i < lres->nentries; i++) {
entry = lres->entries[i].entry;
if ((pwcheck == any && doauth != FALSE) ||
(pwcheck == all && doauth == FALSE)) {
@@ -2178,7 +2229,7 @@ sudo_ldap_result_last_search(struct ldap_result *lres)
struct ldap_search_list *result = lres->searches;
if (result) {
while (result->next)
while (result->next)
result = result->next;
}
return result;