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:
@@ -369,6 +369,12 @@ this is of the form C<ou=SUDOers,dc=example,dc=com> for the domain
|
||||
C<example.com>. Multiple B<SUDOERS_BASE> lines may be specified,
|
||||
in which case they are queried in the order specified.
|
||||
|
||||
=item B<SUDOERS_SEARCH_FILTER> ldap_filter
|
||||
|
||||
An LDAP filter which is used to restrict the set of records returned
|
||||
when performing a B<sudo> LDAP query. Typically, this is of the
|
||||
form C<attribute=value> or C<(&(attribute=value)(attribute2=value2))>.
|
||||
|
||||
=item B<SUDOERS_TIMED> on/true/yes/off/false/no
|
||||
|
||||
Whether or not to evaluate the C<sudoNotBefore> and C<sudoNotAfter>
|
||||
|
@@ -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",
|
||||
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user