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,
|
C<example.com>. Multiple B<SUDOERS_BASE> lines may be specified,
|
||||||
in which case they are queried in the order 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
|
=item B<SUDOERS_TIMED> on/true/yes/off/false/no
|
||||||
|
|
||||||
Whether or not to evaluate the C<sudoNotBefore> and C<sudoNotAfter>
|
Whether or not to evaluate the C<sudoNotBefore> and C<sudoNotAfter>
|
||||||
|
@@ -201,6 +201,7 @@ static struct ldap_config {
|
|||||||
char *bindpw;
|
char *bindpw;
|
||||||
char *rootbinddn;
|
char *rootbinddn;
|
||||||
struct ldap_config_list_str *base;
|
struct ldap_config_list_str *base;
|
||||||
|
char *search_filter;
|
||||||
char *ssl;
|
char *ssl;
|
||||||
char *tls_cacertfile;
|
char *tls_cacertfile;
|
||||||
char *tls_cacertdir;
|
char *tls_cacertdir;
|
||||||
@@ -285,6 +286,7 @@ static struct ldap_config_table ldap_conf_table[] = {
|
|||||||
{ "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
|
{ "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
|
||||||
{ "sudoers_base", CONF_LIST_STR, FALSE, -1, &ldap_conf.base },
|
{ "sudoers_base", CONF_LIST_STR, FALSE, -1, &ldap_conf.base },
|
||||||
{ "sudoers_timed", CONF_BOOL, FALSE, -1, &ldap_conf.timed },
|
{ "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
|
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
|
||||||
{ "use_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.use_sasl },
|
{ "use_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.use_sasl },
|
||||||
{ "sasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.sasl_auth_id },
|
{ "sasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.sasl_auth_id },
|
||||||
@@ -949,6 +951,21 @@ done:
|
|||||||
return bytes;
|
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.
|
* Builds up a filter to check against LDAP.
|
||||||
*/
|
*/
|
||||||
@@ -957,11 +974,15 @@ sudo_ldap_build_pass1(struct passwd *pw)
|
|||||||
{
|
{
|
||||||
struct group *grp;
|
struct group *grp;
|
||||||
char *buf, timebuffer[TIMEFILTER_LENGTH];
|
char *buf, timebuffer[TIMEFILTER_LENGTH];
|
||||||
size_t sz;
|
size_t sz = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Start with (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
|
/* Start with LDAP search filter length + 3 */
|
||||||
sz = 29 + strlen(pw->pw_name);
|
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 */
|
/* Add space for groups */
|
||||||
if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
|
if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
|
||||||
@@ -984,12 +1005,15 @@ sudo_ldap_build_pass1(struct passwd *pw)
|
|||||||
*buf = '\0';
|
*buf = '\0';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If timed, start a global AND clause that will have the time limits
|
* If timed or using a search filter, start a global AND clause to
|
||||||
* as the second leg.
|
* 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);
|
(void) strlcpy(buf, "(&", sz);
|
||||||
|
|
||||||
|
if (ldap_conf.search_filter)
|
||||||
|
(void) strlcat(buf, ldap_conf.search_filter, sz);
|
||||||
|
|
||||||
/* Global OR + sudoUser=user_name filter */
|
/* Global OR + sudoUser=user_name filter */
|
||||||
(void) strlcat(buf, "(|(sudoUser=", sz);
|
(void) strlcat(buf, "(|(sudoUser=", sz);
|
||||||
(void) strlcat(buf, pw->pw_name, 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 */
|
strlcat(buf, ")", sz); /* closes the global OR */
|
||||||
sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
|
sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
|
||||||
strlcat(buf, timebuffer, sz);
|
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 */
|
strlcat(buf, ")", sz); /* closes the global OR or the global AND */
|
||||||
|
|
||||||
@@ -1036,21 +1062,23 @@ sudo_ldap_build_pass1(struct passwd *pw)
|
|||||||
static char *
|
static char *
|
||||||
sudo_ldap_build_pass2(void)
|
sudo_ldap_build_pass2(void)
|
||||||
{
|
{
|
||||||
char *buf, timebuffer[TIMEFILTER_LENGTH];
|
char *filt, timebuffer[TIMEFILTER_LENGTH];
|
||||||
|
|
||||||
if (ldap_conf.timed) {
|
if (ldap_conf.timed)
|
||||||
/*
|
|
||||||
* If timed, use a global AND clause that has the time limit as
|
|
||||||
* as the second leg.
|
|
||||||
*/
|
|
||||||
sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
|
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
|
static void
|
||||||
@@ -1178,6 +1206,10 @@ sudo_ldap_read_config(void)
|
|||||||
sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base %s\n",
|
sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base %s\n",
|
||||||
"(NONE: LDAP disabled)");
|
"(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",
|
sudo_printf(SUDO_CONV_ERROR_MSG, "binddn %s\n",
|
||||||
ldap_conf.binddn ? ldap_conf.binddn : "(anonymous)");
|
ldap_conf.binddn ? ldap_conf.binddn : "(anonymous)");
|
||||||
sudo_printf(SUDO_CONV_ERROR_MSG, "bindpw %s\n",
|
sudo_printf(SUDO_CONV_ERROR_MSG, "bindpw %s\n",
|
||||||
@@ -1188,7 +1220,7 @@ sudo_ldap_read_config(void)
|
|||||||
}
|
}
|
||||||
if (ldap_conf.timelimit > 0) {
|
if (ldap_conf.timelimit > 0) {
|
||||||
sudo_printf(SUDO_CONV_ERROR_MSG, "timelimit %d\n",
|
sudo_printf(SUDO_CONV_ERROR_MSG, "timelimit %d\n",
|
||||||
ldap_conf.timelimit);
|
ldap_conf.timelimit);
|
||||||
}
|
}
|
||||||
sudo_printf(SUDO_CONV_ERROR_MSG, "ssl %s\n",
|
sudo_printf(SUDO_CONV_ERROR_MSG, "ssl %s\n",
|
||||||
ldap_conf.ssl ? ldap_conf.ssl : "(no)");
|
ldap_conf.ssl ? ldap_conf.ssl : "(no)");
|
||||||
@@ -1291,6 +1323,18 @@ sudo_ldap_read_config(void)
|
|||||||
#endif
|
#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 rootbinddn set, read in /etc/ldap.secret if it exists. */
|
||||||
if (ldap_conf.rootbinddn)
|
if (ldap_conf.rootbinddn)
|
||||||
sudo_ldap_read_secret(_PATH_LDAP_SECRET);
|
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;
|
struct sudo_ldap_handle *handle = nss->handle;
|
||||||
LDAP *ld;
|
LDAP *ld;
|
||||||
LDAPMessage *entry, *result;
|
LDAPMessage *entry, *result;
|
||||||
char *prefix;
|
char *prefix, *filt;
|
||||||
int rc, count = 0;
|
int rc, count = 0;
|
||||||
|
|
||||||
if (handle == NULL || handle->ld == NULL)
|
if (handle == NULL || handle->ld == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
ld = handle->ld;
|
ld = handle->ld;
|
||||||
|
|
||||||
|
filt = sudo_ldap_build_default_filter();
|
||||||
for (base = ldap_conf.base; base != NULL; base = base->next) {
|
for (base = ldap_conf.base; base != NULL; base = base->next) {
|
||||||
if (ldap_conf.timeout > 0) {
|
if (ldap_conf.timeout > 0) {
|
||||||
tv.tv_sec = ldap_conf.timeout;
|
tv.tv_sec = ldap_conf.timeout;
|
||||||
@@ -1376,7 +1421,7 @@ sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
|
|||||||
}
|
}
|
||||||
result = NULL;
|
result = NULL;
|
||||||
rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
|
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))) {
|
if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
|
||||||
bv = ldap_get_values_len(ld, entry, "sudoOption");
|
bv = ldap_get_values_len(ld, entry, "sudoOption");
|
||||||
if (bv != NULL) {
|
if (bv != NULL) {
|
||||||
@@ -1395,6 +1440,7 @@ sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
|
|||||||
if (result)
|
if (result)
|
||||||
ldap_msgfree(result);
|
ldap_msgfree(result);
|
||||||
}
|
}
|
||||||
|
efree(filt);
|
||||||
done:
|
done:
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@@ -2005,12 +2051,16 @@ sudo_ldap_setdefs(struct sudo_nss *nss)
|
|||||||
struct timeval tv, *tvp = NULL;
|
struct timeval tv, *tvp = NULL;
|
||||||
LDAP *ld;
|
LDAP *ld;
|
||||||
LDAPMessage *entry, *result;
|
LDAPMessage *entry, *result;
|
||||||
|
char *filt;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (handle == NULL || handle->ld == NULL)
|
if (handle == NULL || handle->ld == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
ld = handle->ld;
|
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) {
|
for (base = ldap_conf.base; base != NULL; base = base->next) {
|
||||||
if (ldap_conf.timeout > 0) {
|
if (ldap_conf.timeout > 0) {
|
||||||
tv.tv_sec = ldap_conf.timeout;
|
tv.tv_sec = ldap_conf.timeout;
|
||||||
@@ -2019,7 +2069,7 @@ sudo_ldap_setdefs(struct sudo_nss *nss)
|
|||||||
}
|
}
|
||||||
result = NULL;
|
result = NULL;
|
||||||
rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
|
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))) {
|
if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
|
||||||
DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
|
DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
|
||||||
sudo_ldap_parse_options(ld, entry);
|
sudo_ldap_parse_options(ld, entry);
|
||||||
@@ -2029,6 +2079,7 @@ sudo_ldap_setdefs(struct sudo_nss *nss)
|
|||||||
if (result)
|
if (result)
|
||||||
ldap_msgfree(result);
|
ldap_msgfree(result);
|
||||||
}
|
}
|
||||||
|
efree(filt);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2062,7 +2113,7 @@ sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
|
|||||||
enum def_tuple pwcheck =
|
enum def_tuple pwcheck =
|
||||||
(pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
|
(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;
|
entry = lres->entries[i].entry;
|
||||||
if ((pwcheck == any && doauth != FALSE) ||
|
if ((pwcheck == any && doauth != FALSE) ||
|
||||||
(pwcheck == all && 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;
|
struct ldap_search_list *result = lres->searches;
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
while (result->next)
|
while (result->next)
|
||||||
result = result->next;
|
result = result->next;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
Reference in New Issue
Block a user