2 * Copyright (c) 2003-2011 Todd C. Miller <Todd.Miller@courtesan.com>
4 * This code is derived from software contributed by Aaron Spangler.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <sys/types.h>
23 #include <sys/param.h>
33 #endif /* STDC_HEADERS */
36 #endif /* HAVE_STRING_H */
39 #endif /* HAVE_STRINGS_H */
42 #endif /* HAVE_UNISTD_H */
43 #if TIME_WITH_SYS_TIME
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
56 #if defined(HAVE_LDAP_SSL_H)
57 # include <ldap_ssl.h>
58 #elif defined(HAVE_MPS_LDAP_SSL_H)
59 # include <mps/ldap_ssl.h>
61 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
62 # ifdef HAVE_SASL_SASL_H
63 # include <sasl/sasl.h>
67 # if HAVE_GSS_KRB5_CCACHE_NAME
68 # if defined(HAVE_GSSAPI_GSSAPI_KRB5_H)
69 # include <gssapi/gssapi.h>
70 # include <gssapi/gssapi_krb5.h>
71 # elif defined(HAVE_GSSAPI_GSSAPI_H)
72 # include <gssapi/gssapi.h>
83 /* Older Netscape LDAP SDKs don't prototype ldapssl_set_strength() */
84 #if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(HAVE_LDAP_SSL_H) && !defined(HAVE_MPS_LDAP_SSL_H)
85 extern int ldapssl_set_strength(LDAP *ldap, int strength);
88 #ifndef LDAP_OPT_SUCCESS
89 # define LDAP_OPT_SUCCESS LDAP_SUCCESS
93 # define LDAPS_PORT 636
96 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && !defined(LDAP_SASL_QUIET)
97 # define LDAP_SASL_QUIET 0
100 #ifndef HAVE_LDAP_UNBIND_EXT_S
101 #define ldap_unbind_ext_s(a, b, c) ldap_unbind_s(a)
104 #ifndef HAVE_LDAP_SEARCH_EXT_S
105 # ifdef HAVE_LDAP_SEARCH_ST
106 # define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k) \
107 ldap_search_st(a, b, c, d, e, f, i, k)
109 # define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k) \
110 ldap_search_s(a, b, c, d, e, f, k)
114 #define LDAP_FOREACH(var, ld, res) \
115 for ((var) = ldap_first_entry((ld), (res)); \
117 (var) = ldap_next_entry((ld), (var)))
119 #define DPRINTF(args, level) if (ldap_conf.debug >= level) warningx args
124 #define CONF_LIST_STR 4
125 #define CONF_DEREF_VAL 5
127 #define SUDO_LDAP_SSL 1
128 #define SUDO_LDAP_STARTTLS 2
130 /* The TIMEFILTER_LENGTH includes the filter itself plus the global AND
131 wrapped around the user filter and the time filter when timed entries
132 are used. The length is computed as follows:
134 + 2 * 13 for the now timestamp
135 + 3 for the global AND
137 #define TIMEFILTER_LENGTH 114
140 * The ldap_search structure implements a linked list of ldap and
141 * search result pointers, which allows us to remove them after
142 * all search results have been combined in memory.
143 * XXX - should probably be a tailq since we do appends
145 struct ldap_search_list {
147 LDAPMessage *searchresult;
148 struct ldap_search_list *next;
152 * The ldap_entry_wrapper structure is used to implement sorted result entries.
153 * A double is used for the order to allow for insertion of new entries
154 * without having to renumber everything.
155 * Note: there is no standard floating point type in LDAP.
156 * As a result, some LDAP servers will only allow an integer.
158 struct ldap_entry_wrapper {
164 * The ldap_result structure contains the list of matching searches as
165 * well as an array of all result entries sorted by the sudoOrder attribute.
168 struct ldap_search_list *searches;
169 struct ldap_entry_wrapper *entries;
170 int allocated_entries;
175 #define ALLOCATION_INCREMENT 100
177 struct ldap_config_table {
178 const char *conf_str; /* config file string */
179 short type; /* CONF_BOOL, CONF_INT, CONF_STR */
180 short connected; /* connection-specific value? */
181 int opt_val; /* LDAP_OPT_* (or -1 for sudo internal) */
182 void *valp; /* pointer into ldap_conf */
185 struct ldap_config_list_str {
186 struct ldap_config_list_str *next;
190 /* LDAP configuration structure */
191 static struct ldap_config {
206 struct ldap_config_list_str *uri;
210 struct ldap_config_list_str *base;
213 char *tls_cacertfile;
215 char *tls_random_file;
216 char *tls_cipher_suite;
220 char *rootsasl_auth_id;
225 static struct ldap_config_table ldap_conf_table[] = {
226 { "sudoers_debug", CONF_INT, false, -1, &ldap_conf.debug },
227 { "host", CONF_STR, false, -1, &ldap_conf.host },
228 { "port", CONF_INT, false, -1, &ldap_conf.port },
229 { "ssl", CONF_STR, false, -1, &ldap_conf.ssl },
230 { "sslpath", CONF_STR, false, -1, &ldap_conf.tls_certfile },
231 { "uri", CONF_LIST_STR, false, -1, &ldap_conf.uri },
232 #ifdef LDAP_OPT_DEBUG_LEVEL
233 { "debug", CONF_INT, false, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
235 #ifdef LDAP_OPT_PROTOCOL_VERSION
236 { "ldap_version", CONF_INT, true, LDAP_OPT_PROTOCOL_VERSION,
237 &ldap_conf.version },
239 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
240 { "tls_checkpeer", CONF_BOOL, false, LDAP_OPT_X_TLS_REQUIRE_CERT,
241 &ldap_conf.tls_checkpeer },
243 { "tls_checkpeer", CONF_BOOL, false, -1, &ldap_conf.tls_checkpeer },
245 #ifdef LDAP_OPT_X_TLS_CACERTFILE
246 { "tls_cacertfile", CONF_STR, false, LDAP_OPT_X_TLS_CACERTFILE,
247 &ldap_conf.tls_cacertfile },
248 { "tls_cacert", CONF_STR, false, LDAP_OPT_X_TLS_CACERTFILE,
249 &ldap_conf.tls_cacertfile },
251 #ifdef LDAP_OPT_X_TLS_CACERTDIR
252 { "tls_cacertdir", CONF_STR, false, LDAP_OPT_X_TLS_CACERTDIR,
253 &ldap_conf.tls_cacertdir },
255 #ifdef LDAP_OPT_X_TLS_RANDOM_FILE
256 { "tls_randfile", CONF_STR, false, LDAP_OPT_X_TLS_RANDOM_FILE,
257 &ldap_conf.tls_random_file },
259 #ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
260 { "tls_ciphers", CONF_STR, false, LDAP_OPT_X_TLS_CIPHER_SUITE,
261 &ldap_conf.tls_cipher_suite },
263 #ifdef LDAP_OPT_X_TLS_CERTFILE
264 { "tls_cert", CONF_STR, false, LDAP_OPT_X_TLS_CERTFILE,
265 &ldap_conf.tls_certfile },
267 { "tls_cert", CONF_STR, false, -1, &ldap_conf.tls_certfile },
269 #ifdef LDAP_OPT_X_TLS_KEYFILE
270 { "tls_key", CONF_STR, false, LDAP_OPT_X_TLS_KEYFILE,
271 &ldap_conf.tls_keyfile },
273 { "tls_key", CONF_STR, false, -1, &ldap_conf.tls_keyfile },
275 #ifdef LDAP_OPT_NETWORK_TIMEOUT
276 { "bind_timelimit", CONF_INT, true, -1 /* needs timeval, set manually */,
277 &ldap_conf.bind_timelimit },
278 { "network_timeout", CONF_INT, true, -1 /* needs timeval, set manually */,
279 &ldap_conf.bind_timelimit },
280 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
281 { "bind_timelimit", CONF_INT, true, LDAP_X_OPT_CONNECT_TIMEOUT,
282 &ldap_conf.bind_timelimit },
283 { "network_timeout", CONF_INT, true, LDAP_X_OPT_CONNECT_TIMEOUT,
284 &ldap_conf.bind_timelimit },
286 { "timelimit", CONF_INT, true, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit },
287 #ifdef LDAP_OPT_TIMEOUT
288 { "timeout", CONF_INT, true, -1 /* needs timeval, set manually */,
289 &ldap_conf.timeout },
291 #ifdef LDAP_OPT_DEREF
292 { "deref", CONF_DEREF_VAL, true, LDAP_OPT_DEREF, &ldap_conf.deref },
294 { "binddn", CONF_STR, false, -1, &ldap_conf.binddn },
295 { "bindpw", CONF_STR, false, -1, &ldap_conf.bindpw },
296 { "rootbinddn", CONF_STR, false, -1, &ldap_conf.rootbinddn },
297 { "sudoers_base", CONF_LIST_STR, false, -1, &ldap_conf.base },
298 { "sudoers_timed", CONF_BOOL, false, -1, &ldap_conf.timed },
299 { "sudoers_search_filter", CONF_STR, false, -1, &ldap_conf.search_filter },
300 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
301 { "use_sasl", CONF_BOOL, false, -1, &ldap_conf.use_sasl },
302 { "sasl_auth_id", CONF_STR, false, -1, &ldap_conf.sasl_auth_id },
303 { "rootuse_sasl", CONF_BOOL, false, -1, &ldap_conf.rootuse_sasl },
304 { "rootsasl_auth_id", CONF_STR, false, -1, &ldap_conf.rootsasl_auth_id },
305 # ifdef LDAP_OPT_X_SASL_SECPROPS
306 { "sasl_secprops", CONF_STR, true, LDAP_OPT_X_SASL_SECPROPS,
307 &ldap_conf.sasl_secprops },
309 { "krb5_ccname", CONF_STR, false, -1, &ldap_conf.krb5_ccname },
310 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
314 /* sudo_nss implementation */
315 static int sudo_ldap_open(struct sudo_nss *nss);
316 static int sudo_ldap_close(struct sudo_nss *nss);
317 static int sudo_ldap_parse(struct sudo_nss *nss);
318 static int sudo_ldap_setdefs(struct sudo_nss *nss);
319 static int sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag);
320 static int sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
321 static int sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
323 static int sudo_ldap_display_bound_defaults(struct sudo_nss *nss,
324 struct passwd *pw, struct lbuf *lbuf);
325 static int sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
327 static struct ldap_result *sudo_ldap_result_get(struct sudo_nss *nss,
331 * LDAP sudo_nss handle.
332 * We store the connection to the LDAP server, the cached ldap_result object
333 * (if any), and the name of the user the query was performed for.
334 * If a new query is launched with sudo_ldap_result_get() that specifies a
335 * different user, the old cached result is freed before the new query is run.
337 struct sudo_ldap_handle {
339 struct ldap_result *result;
341 struct group_list *grlist;
344 struct sudo_nss sudo_nss_ldap = {
352 sudo_ldap_display_cmnd,
353 sudo_ldap_display_defaults,
354 sudo_ldap_display_bound_defaults,
355 sudo_ldap_display_privs
358 #ifdef HAVE_LDAP_CREATE
360 * Rebuild the hosts list and include a specific port for each host.
361 * ldap_create() does not take a default port parameter so we must
362 * append one if we want something other than LDAP_PORT.
365 sudo_ldap_conf_add_ports(void)
368 char *host, *port, defport[13];
369 char hostbuf[LINE_MAX * 2];
370 debug_decl(sudo_ldap_conf_add_ports, SUDO_DEBUG_LDAP)
373 if (snprintf(defport, sizeof(defport), ":%d", ldap_conf.port) >= sizeof(defport))
374 errorx(1, _("sudo_ldap_conf_add_ports: port too large"));
376 for ((host = strtok(ldap_conf.host, " \t")); host; (host = strtok(NULL, " \t"))) {
377 if (hostbuf[0] != '\0') {
378 if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
382 if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
384 /* Append port if there is not one already. */
385 if ((port = strrchr(host, ':')) == NULL ||
386 !isdigit((unsigned char)port[1])) {
387 if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf))
392 efree(ldap_conf.host);
393 ldap_conf.host = estrdup(hostbuf);
397 errorx(1, _("sudo_ldap_conf_add_ports: out of space expanding hostbuf"));
401 #ifndef HAVE_LDAP_INITIALIZE
403 * For each uri, convert to host:port pairs. For ldaps:// enable SSL
404 * Accepts: uris of the form ldap:/// or ldap://hostname:portnum/
405 * where the trailing slash is optional.
408 sudo_ldap_parse_uri(const struct ldap_config_list_str *uri_list)
410 char *buf, *uri, *host, *cp, *port;
411 char hostbuf[LINE_MAX];
412 int nldap = 0, nldaps = 0;
414 debug_decl(sudo_ldap_parse_uri, SUDO_DEBUG_LDAP)
417 buf = estrdup(uri_list->val);
419 for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
420 if (strncasecmp(uri, "ldap://", 7) == 0) {
423 } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
427 warningx(_("unsupported LDAP uri type: %s"), uri);
431 /* trim optional trailing slash */
432 if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
436 if (hostbuf[0] != '\0') {
437 if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
442 host = "localhost"; /* no host specified, use localhost */
444 if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
447 /* If using SSL and no port specified, add port 636 */
449 if ((port = strrchr(host, ':')) == NULL ||
450 !isdigit((unsigned char)port[1]))
451 if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
455 if (hostbuf[0] == '\0') {
456 warningx(_("invalid uri: %s"), uri_list);
462 warningx(_("unable to mix ldap and ldaps URIs"));
465 if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
466 warningx(_("unable to mix ldaps and starttls"));
469 ldap_conf.ssl_mode = SUDO_LDAP_SSL;
472 efree(ldap_conf.host);
473 ldap_conf.host = estrdup(hostbuf);
475 } while ((uri_list = uri_list->next));
482 debug_return_int(rc);
485 errorx(1, _("sudo_ldap_parse_uri: out of space building hostbuf"));
489 sudo_ldap_join_uri(struct ldap_config_list_str *uri_list)
491 struct ldap_config_list_str *uri;
494 debug_decl(sudo_ldap_join_uri, SUDO_DEBUG_LDAP)
496 /* Usually just a single entry. */
497 if (uri_list->next == NULL)
498 debug_return_str(estrdup(uri_list->val));
500 for (uri = uri_list; uri != NULL; uri = uri->next) {
501 len += strlen(uri->val) + 1;
503 buf = cp = emalloc(len);
505 for (uri = uri_list; uri != NULL; uri = uri->next) {
506 cp += strlcpy(cp, uri->val, len - (cp - buf));
510 debug_return_str(buf);
512 #endif /* HAVE_LDAP_INITIALIZE */
515 sudo_ldap_init(LDAP **ldp, const char *host, int port)
518 int rc = LDAP_CONNECT_ERROR;
519 debug_decl(sudo_ldap_init, SUDO_DEBUG_LDAP)
521 #ifdef HAVE_LDAPSSL_INIT
522 if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
523 DPRINTF(("ldapssl_clientauth_init(%s, %s)",
524 ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
525 ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
526 rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
527 ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
529 * Mozilla-derived SDKs have a bug starting with version 5.0
530 * where the path can no longer be a file name and must be a dir.
532 if (rc != LDAP_SUCCESS) {
534 if (ldap_conf.tls_certfile) {
535 cp = strrchr(ldap_conf.tls_certfile, '/');
536 if (cp != NULL && strncmp(cp + 1, "cert", 4) == 0)
539 if (ldap_conf.tls_keyfile) {
540 cp = strrchr(ldap_conf.tls_keyfile, '/');
541 if (cp != NULL && strncmp(cp + 1, "key", 3) == 0)
544 DPRINTF(("ldapssl_clientauth_init(%s, %s)",
545 ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
546 ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
547 rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
548 ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
549 if (rc != LDAP_SUCCESS) {
550 warningx(_("unable to initialize SSL cert and key db: %s"),
551 ldapssl_err2string(rc));
556 DPRINTF(("ldapssl_init(%s, %d, 1)", host, port), 2);
557 if ((ld = ldapssl_init(host, port, 1)) != NULL)
562 #ifdef HAVE_LDAP_CREATE
563 DPRINTF(("ldap_create()"), 2);
564 if ((rc = ldap_create(&ld)) != LDAP_SUCCESS)
566 DPRINTF(("ldap_set_option(LDAP_OPT_HOST_NAME, %s)", host), 2);
567 rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, host);
569 DPRINTF(("ldap_init(%s, %d)", host, port), 2);
570 if ((ld = ldap_init(host, port)) != NULL)
577 debug_return_int(rc);
581 * Walk through search results and return true if we have a matching
582 * netgroup, else false.
585 sudo_ldap_check_user_netgroup(LDAP *ld, LDAPMessage *entry, char *user)
587 struct berval **bv, **p;
590 debug_decl(sudo_ldap_check_user_netgroup, SUDO_DEBUG_LDAP)
593 debug_return_bool(ret);
595 /* get the values from the entry */
596 bv = ldap_get_values_len(ld, entry, "sudoUser");
598 debug_return_bool(ret);
600 /* walk through values */
601 for (p = bv; *p != NULL && !ret; p++) {
604 if (netgr_matches(val, NULL, NULL, user))
606 DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val,
607 ret ? "MATCH!" : "not"), 2 + ((ret) ? 0 : 1));
610 ldap_value_free_len(bv); /* cleanup */
612 debug_return_bool(ret);
616 * Walk through search results and return true if we have a
617 * host match, else false.
620 sudo_ldap_check_host(LDAP *ld, LDAPMessage *entry)
622 struct berval **bv, **p;
625 debug_decl(sudo_ldap_check_host, SUDO_DEBUG_LDAP)
628 debug_return_bool(ret);
630 /* get the values from the entry */
631 bv = ldap_get_values_len(ld, entry, "sudoHost");
633 debug_return_bool(ret);
635 /* walk through values */
636 for (p = bv; *p != NULL && !ret; p++) {
638 /* match any or address or netgroup or hostname */
639 if (!strcmp(val, "ALL") || addr_matches(val) ||
640 netgr_matches(val, user_host, user_shost, NULL) ||
641 hostname_matches(user_shost, user_host, val))
643 DPRINTF(("ldap sudoHost '%s' ... %s", val,
644 ret ? "MATCH!" : "not"), 2);
647 ldap_value_free_len(bv); /* cleanup */
649 debug_return_bool(ret);
653 sudo_ldap_check_runas_user(LDAP *ld, LDAPMessage *entry)
655 struct berval **bv, **p;
658 debug_decl(sudo_ldap_check_runas_user, SUDO_DEBUG_LDAP)
661 debug_return_bool(UNSPEC);
663 /* get the runas user from the entry */
664 bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
666 bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */
671 * if runas is not specified on the command line, the only information
672 * as to which user to run as is in the runas_default option. We should
673 * check to see if we have the local option present. Unfortunately we
674 * don't parse these options until after this routine says yes or no.
675 * The query has already returned, so we could peek at the attribute
676 * values here though.
678 * For now just require users to always use -u option unless its set
679 * in the global defaults. This behaviour is no different than the global
682 * Sigh - maybe add this feature later
686 * If there are no runas entries, match runas_default against
687 * what the user specified on the command line.
690 debug_return_bool(!strcasecmp(runas_pw->pw_name, def_runas_default));
692 /* walk through values returned, looking for a match */
693 for (p = bv; *p != NULL && !ret; p++) {
697 if (netgr_matches(val, NULL, NULL, runas_pw->pw_name))
701 if (usergr_matches(val, runas_pw->pw_name, runas_pw))
705 if (strcmp(val, "ALL") == 0) {
711 if (strcasecmp(val, runas_pw->pw_name) == 0)
715 DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val,
716 ret ? "MATCH!" : "not"), 2);
719 ldap_value_free_len(bv); /* cleanup */
721 debug_return_bool(ret);
725 sudo_ldap_check_runas_group(LDAP *ld, LDAPMessage *entry)
727 struct berval **bv, **p;
730 debug_decl(sudo_ldap_check_runas_group, SUDO_DEBUG_LDAP)
732 /* runas_gr is only set if the user specified the -g flag */
734 debug_return_bool(UNSPEC);
736 /* get the values from the entry */
737 bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
739 debug_return_bool(ret);
741 /* walk through values returned, looking for a match */
742 for (p = bv; *p != NULL && !ret; p++) {
744 if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
746 DPRINTF(("ldap sudoRunAsGroup '%s' ... %s", val,
747 ret ? "MATCH!" : "not"), 2);
750 ldap_value_free_len(bv); /* cleanup */
752 debug_return_bool(ret);
756 * Walk through search results and return true if we have a runas match,
757 * else false. RunAs info is optional.
760 sudo_ldap_check_runas(LDAP *ld, LDAPMessage *entry)
763 debug_decl(sudo_ldap_check_runas, SUDO_DEBUG_LDAP)
766 debug_return_bool(false);
768 ret = sudo_ldap_check_runas_user(ld, entry) != false &&
769 sudo_ldap_check_runas_group(ld, entry) != false;
771 debug_return_bool(ret);
775 * Walk through search results and return true if we have a command match,
776 * false if disallowed and UNSPEC if not matched.
779 sudo_ldap_check_command(LDAP *ld, LDAPMessage *entry, int *setenv_implied)
781 struct berval **bv, **p;
782 char *allowed_cmnd, *allowed_args, *val;
785 debug_decl(sudo_ldap_check_command, SUDO_DEBUG_LDAP)
788 debug_return_bool(ret);
790 bv = ldap_get_values_len(ld, entry, "sudoCommand");
792 debug_return_bool(ret);
794 for (p = bv; *p != NULL && ret != false; p++) {
796 /* Match against ALL ? */
797 if (!strcmp(val, "ALL")) {
799 if (setenv_implied != NULL)
800 *setenv_implied = true;
801 DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2);
805 /* check for !command */
808 allowed_cmnd = estrdup(1 + val); /* !command */
811 allowed_cmnd = estrdup(val); /* command */
814 /* split optional args away from command */
815 allowed_args = strchr(allowed_cmnd, ' ');
817 *allowed_args++ = '\0';
819 /* check the command like normal */
820 if (command_matches(allowed_cmnd, allowed_args)) {
822 * If allowed (no bang) set ret but keep on checking.
823 * If disallowed (bang), exit loop.
825 ret = foundbang ? false : true;
827 DPRINTF(("ldap sudoCommand '%s' ... %s", val,
828 ret == true ? "MATCH!" : "not"), 2);
830 efree(allowed_cmnd); /* cleanup */
833 ldap_value_free_len(bv); /* more cleanup */
835 debug_return_bool(ret);
839 * Search for boolean "option" in sudoOption.
840 * Returns true if found and allowed, false if negated, else UNSPEC.
843 sudo_ldap_check_bool(LDAP *ld, LDAPMessage *entry, char *option)
845 struct berval **bv, **p;
848 debug_decl(sudo_ldap_check_bool, SUDO_DEBUG_LDAP)
851 debug_return_bool(ret);
853 bv = ldap_get_values_len(ld, entry, "sudoOption");
855 debug_return_bool(ret);
857 /* walk through options */
858 for (p = bv; *p != NULL; p++) {
860 DPRINTF(("ldap sudoOption: '%s'", var), 2);
862 if ((ch = *var) == '!')
864 if (strcmp(var, option) == 0)
868 ldap_value_free_len(bv);
870 debug_return_bool(ret);
874 * Read sudoOption and modify the defaults as we go. This is used once
875 * from the cn=defaults entry and also once when a final sudoRole is matched.
878 sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry)
880 struct berval **bv, **p;
882 debug_decl(sudo_ldap_parse_options, SUDO_DEBUG_LDAP)
887 bv = ldap_get_values_len(ld, entry, "sudoOption");
891 /* walk through options */
892 for (p = bv; *p != NULL; p++) {
893 var = estrdup((*p)->bv_val);
894 DPRINTF(("ldap sudoOption: '%s'", var), 2);
896 /* check for equals sign past first char */
897 val = strchr(var, '=');
899 *val++ = '\0'; /* split on = and truncate var */
900 op = *(val - 2); /* peek for += or -= cases */
901 if (op == '+' || op == '-') {
902 *(val - 2) = '\0'; /* found, remove extra char */
903 /* case var+=val or var-=val */
904 set_default(var, val, (int) op);
907 set_default(var, val, true);
909 } else if (*var == '!') {
910 /* case !var Boolean False */
911 set_default(var + 1, NULL, false);
913 /* case var Boolean True */
914 set_default(var, NULL, true);
919 ldap_value_free_len(bv);
925 * Build an LDAP timefilter.
927 * Stores a filter in the buffer that makes sure only entries
928 * are selected that have a sudoNotBefore in the past and a
929 * sudoNotAfter in the future, i.e. a filter of the following
930 * structure (spaced out a little more for better readability:
934 * (!(sudoNotAfter=*))
935 * (sudoNotAfter>__now__)
938 * (!(sudoNotBefore=*))
939 * (sudoNotBefore<__now__)
943 * If either the sudoNotAfter or sudoNotBefore attributes are missing,
944 * no time restriction shall be imposed.
947 sudo_ldap_timefilter(char *buffer, size_t buffersize)
953 debug_decl(sudo_ldap_timefilter, SUDO_DEBUG_LDAP)
955 /* Make sure we have a formatted timestamp for __now__. */
957 if ((tp = gmtime(&now)) == NULL) {
958 warning(_("unable to get GMT time"));
962 /* Format the timestamp according to the RFC. */
963 if (strftime(timebuffer, sizeof(timebuffer), "%Y%m%d%H%M%SZ", tp) == 0) {
964 warning(_("unable to format timestamp"));
969 bytes = snprintf(buffer, buffersize, "(&(|(!(sudoNotAfter=*))(sudoNotAfter>=%s))(|(!(sudoNotBefore=*))(sudoNotBefore<=%s)))",
970 timebuffer, timebuffer);
971 if (bytes < 0 || bytes >= buffersize) {
972 warning(_("unable to build time filter"));
977 debug_return_int(bytes);
981 * Builds up a filter to search for default settings
984 sudo_ldap_build_default_filter(void)
987 debug_decl(sudo_ldap_build_default_filter, SUDO_DEBUG_LDAP)
989 if (ldap_conf.search_filter)
990 easprintf(&filt, "(&%s(cn=defaults))", ldap_conf.search_filter);
992 filt = estrdup("cn=defaults");
993 debug_return_str(filt);
997 * Determine length of query value after escaping characters
1001 sudo_ldap_value_len(const char *value)
1006 for (s = value; *s != '\0'; s++) {
1016 len += (size_t)(s - value);
1021 * Like strlcat() but escapes characters as per RFC 4515.
1024 sudo_ldap_value_cat(char *dst, const char *src, size_t size)
1027 const char *s = src;
1031 /* Find the end of dst and adjust bytes left but don't go past end */
1032 while (n-- != 0 && *d != '\0')
1038 return dlen + strlen(s);
1039 while (*s != '\0') {
1086 return dlen + (s - src); /* count does not include NUL */
1090 * Builds up a filter to check against LDAP.
1093 sudo_ldap_build_pass1(struct passwd *pw)
1096 char *buf, timebuffer[TIMEFILTER_LENGTH], gidbuf[MAX_UID_T_LEN];
1097 struct group_list *grlist;
1100 debug_decl(sudo_ldap_build_pass1, SUDO_DEBUG_LDAP)
1102 /* Start with LDAP search filter length + 3 */
1103 if (ldap_conf.search_filter)
1104 sz += strlen(ldap_conf.search_filter) + 3;
1106 /* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
1107 sz += 29 + sudo_ldap_value_len(pw->pw_name);
1109 /* Add space for primary and supplementary groups and gids */
1110 if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
1111 sz += 12 + sudo_ldap_value_len(grp->gr_name);
1113 sz += 13 + MAX_UID_T_LEN;
1114 if ((grlist = get_group_list(pw)) != NULL) {
1115 for (i = 0; i < grlist->ngroups; i++) {
1116 if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0)
1118 sz += 12 + sudo_ldap_value_len(grlist->groups[i]);
1120 for (i = 0; i < grlist->ngids; i++) {
1121 if (pw->pw_gid == grlist->gids[i])
1123 sz += 13 + MAX_UID_T_LEN;
1127 /* If timed, add space for time limits. */
1128 if (ldap_conf.timed)
1129 sz += TIMEFILTER_LENGTH;
1134 * If timed or using a search filter, start a global AND clause to
1135 * contain the search filter, search criteria, and time restriction.
1137 if (ldap_conf.timed || ldap_conf.search_filter)
1138 (void) strlcpy(buf, "(&", sz);
1140 if (ldap_conf.search_filter)
1141 (void) strlcat(buf, ldap_conf.search_filter, sz);
1143 /* Global OR + sudoUser=user_name filter */
1144 (void) strlcat(buf, "(|(sudoUser=", sz);
1145 (void) sudo_ldap_value_cat(buf, pw->pw_name, sz);
1146 (void) strlcat(buf, ")", sz);
1148 /* Append primary group and gid */
1150 (void) strlcat(buf, "(sudoUser=%", sz);
1151 (void) sudo_ldap_value_cat(buf, grp->gr_name, sz);
1152 (void) strlcat(buf, ")", sz);
1154 (void) snprintf(gidbuf, sizeof(gidbuf), "%u", (unsigned int)pw->pw_gid);
1155 (void) strlcat(buf, "(sudoUser=%#", sz);
1156 (void) strlcat(buf, gidbuf, sz);
1157 (void) strlcat(buf, ")", sz);
1159 /* Append supplementary groups and gids */
1160 if (grlist != NULL) {
1161 for (i = 0; i < grlist->ngroups; i++) {
1162 if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0)
1164 (void) strlcat(buf, "(sudoUser=%", sz);
1165 (void) sudo_ldap_value_cat(buf, grlist->groups[i], sz);
1166 (void) strlcat(buf, ")", sz);
1168 for (i = 0; i < grlist->ngids; i++) {
1169 if (pw->pw_gid == grlist->gids[i])
1171 (void) snprintf(gidbuf, sizeof(gidbuf), "%u",
1172 (unsigned int)grlist->gids[i]);
1173 (void) strlcat(buf, "(sudoUser=%#", sz);
1174 (void) strlcat(buf, gidbuf, sz);
1175 (void) strlcat(buf, ")", sz);
1179 /* Done with groups. */
1181 grlist_delref(grlist);
1185 /* Add ALL to list and end the global OR */
1186 if (strlcat(buf, "(sudoUser=ALL)", sz) >= sz)
1187 errorx(1, _("sudo_ldap_build_pass1 allocation mismatch"));
1189 /* Add the time restriction, or simply end the global OR. */
1190 if (ldap_conf.timed) {
1191 strlcat(buf, ")", sz); /* closes the global OR */
1192 sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
1193 strlcat(buf, timebuffer, sz);
1194 } else if (ldap_conf.search_filter) {
1195 strlcat(buf, ")", sz); /* closes the global OR */
1197 strlcat(buf, ")", sz); /* closes the global OR or the global AND */
1199 debug_return_str(buf);
1203 * Builds up a filter to check against netgroup entries in LDAP.
1206 sudo_ldap_build_pass2(void)
1208 char *filt, timebuffer[TIMEFILTER_LENGTH];
1209 debug_decl(sudo_ldap_build_pass2, SUDO_DEBUG_LDAP)
1211 if (ldap_conf.timed)
1212 sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
1215 * Match all sudoUsers beginning with a '+'.
1216 * If a search filter or time restriction is specified,
1217 * those get ANDed in to the expression.
1219 easprintf(&filt, "%s%s(sudoUser=+*)%s%s",
1220 (ldap_conf.timed || ldap_conf.search_filter) ? "(&" : "",
1221 ldap_conf.search_filter ? ldap_conf.search_filter : "",
1222 ldap_conf.timed ? timebuffer : "",
1223 (ldap_conf.timed || ldap_conf.search_filter) ? ")" : "");
1225 debug_return_str(filt);
1229 sudo_ldap_read_secret(const char *path)
1232 char buf[LINE_MAX], *cp;
1233 debug_decl(sudo_ldap_read_secret, SUDO_DEBUG_LDAP)
1235 if ((fp = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
1236 if (fgets(buf, sizeof(buf), fp) != NULL) {
1237 if ((cp = strchr(buf, '\n')) != NULL)
1239 /* copy to bindpw and binddn */
1240 efree(ldap_conf.bindpw);
1241 ldap_conf.bindpw = estrdup(buf);
1242 efree(ldap_conf.binddn);
1243 ldap_conf.binddn = ldap_conf.rootbinddn;
1244 ldap_conf.rootbinddn = NULL;
1252 sudo_ldap_read_config(void)
1255 char *cp, *keyword, *value;
1256 struct ldap_config_table *cur;
1257 debug_decl(sudo_ldap_read_config, SUDO_DEBUG_LDAP)
1260 ldap_conf.version = 3;
1261 ldap_conf.port = -1;
1262 ldap_conf.tls_checkpeer = -1;
1263 ldap_conf.timelimit = -1;
1264 ldap_conf.timeout = -1;
1265 ldap_conf.bind_timelimit = -1;
1266 ldap_conf.use_sasl = -1;
1267 ldap_conf.rootuse_sasl = -1;
1268 ldap_conf.deref = -1;
1270 if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL)
1271 debug_return_bool(false);
1273 while ((cp = sudo_parseln(fp)) != NULL) {
1275 continue; /* skip empty line */
1277 /* split into keyword and value */
1279 while (*cp && !isblank((unsigned char) *cp))
1282 *cp++ = '\0'; /* terminate keyword */
1284 /* skip whitespace before value */
1285 while (isblank((unsigned char) *cp))
1289 /* Look up keyword in config table. */
1290 for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
1291 if (strcasecmp(keyword, cur->conf_str) == 0) {
1292 switch (cur->type) {
1293 case CONF_DEREF_VAL:
1294 if (strcasecmp(value, "searching") == 0)
1295 *(int *)(cur->valp) = LDAP_DEREF_SEARCHING;
1296 else if (strcasecmp(value, "finding") == 0)
1297 *(int *)(cur->valp) = LDAP_DEREF_FINDING;
1298 else if (strcasecmp(value, "always") == 0)
1299 *(int *)(cur->valp) = LDAP_DEREF_ALWAYS;
1301 *(int *)(cur->valp) = LDAP_DEREF_NEVER;
1304 *(int *)(cur->valp) = atobool(value) == true;
1307 *(int *)(cur->valp) = atoi(value);
1310 efree(*(char **)(cur->valp));
1311 *(char **)(cur->valp) = estrdup(value);
1315 struct ldap_config_list_str **p;
1316 size_t len = strlen(value);
1319 p = (struct ldap_config_list_str **)cur->valp;
1322 *p = emalloc(sizeof(struct ldap_config_list_str) + len);
1323 memcpy((*p)->val, value, len + 1);
1335 if (!ldap_conf.host)
1336 ldap_conf.host = estrdup("localhost");
1338 if (ldap_conf.debug > 1) {
1339 sudo_printf(SUDO_CONV_ERROR_MSG, "LDAP Config Summary\n");
1340 sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n");
1341 if (ldap_conf.uri) {
1342 struct ldap_config_list_str *uri = ldap_conf.uri;
1345 sudo_printf(SUDO_CONV_ERROR_MSG, "uri %s\n",
1347 } while ((uri = uri->next) != NULL);
1349 sudo_printf(SUDO_CONV_ERROR_MSG, "host %s\n",
1350 ldap_conf.host ? ldap_conf.host : "(NONE)");
1351 sudo_printf(SUDO_CONV_ERROR_MSG, "port %d\n",
1354 sudo_printf(SUDO_CONV_ERROR_MSG, "ldap_version %d\n",
1357 if (ldap_conf.base) {
1358 struct ldap_config_list_str *base = ldap_conf.base;
1360 sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base %s\n",
1362 } while ((base = base->next) != NULL);
1364 sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base %s\n",
1365 "(NONE: LDAP disabled)");
1367 if (ldap_conf.search_filter) {
1368 sudo_printf(SUDO_CONV_ERROR_MSG, "search_filter %s\n",
1369 ldap_conf.search_filter);
1371 sudo_printf(SUDO_CONV_ERROR_MSG, "binddn %s\n",
1372 ldap_conf.binddn ? ldap_conf.binddn : "(anonymous)");
1373 sudo_printf(SUDO_CONV_ERROR_MSG, "bindpw %s\n",
1374 ldap_conf.bindpw ? ldap_conf.bindpw : "(anonymous)");
1375 if (ldap_conf.bind_timelimit > 0) {
1376 sudo_printf(SUDO_CONV_ERROR_MSG, "bind_timelimit %d\n",
1377 ldap_conf.bind_timelimit);
1379 if (ldap_conf.timelimit > 0) {
1380 sudo_printf(SUDO_CONV_ERROR_MSG, "timelimit %d\n",
1381 ldap_conf.timelimit);
1383 if (ldap_conf.deref != -1) {
1384 sudo_printf(SUDO_CONV_ERROR_MSG, "deref %d\n",
1387 sudo_printf(SUDO_CONV_ERROR_MSG, "ssl %s\n",
1388 ldap_conf.ssl ? ldap_conf.ssl : "(no)");
1389 if (ldap_conf.tls_checkpeer != -1) {
1390 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_checkpeer %s\n",
1391 ldap_conf.tls_checkpeer ? "(yes)" : "(no)");
1393 if (ldap_conf.tls_cacertfile != NULL) {
1394 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cacertfile %s\n",
1395 ldap_conf.tls_cacertfile);
1397 if (ldap_conf.tls_cacertdir != NULL) {
1398 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cacertdir %s\n",
1399 ldap_conf.tls_cacertdir);
1401 if (ldap_conf.tls_random_file != NULL) {
1402 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_random_file %s\n",
1403 ldap_conf.tls_random_file);
1405 if (ldap_conf.tls_cipher_suite != NULL) {
1406 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cipher_suite %s\n",
1407 ldap_conf.tls_cipher_suite);
1409 if (ldap_conf.tls_certfile != NULL) {
1410 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_certfile %s\n",
1411 ldap_conf.tls_certfile);
1413 if (ldap_conf.tls_keyfile != NULL) {
1414 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_keyfile %s\n",
1415 ldap_conf.tls_keyfile);
1417 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1418 if (ldap_conf.use_sasl != -1) {
1419 sudo_printf(SUDO_CONV_ERROR_MSG, "use_sasl %s\n",
1420 ldap_conf.use_sasl ? "yes" : "no");
1421 sudo_printf(SUDO_CONV_ERROR_MSG, "sasl_auth_id %s\n",
1422 ldap_conf.sasl_auth_id ? ldap_conf.sasl_auth_id : "(NONE)");
1423 sudo_printf(SUDO_CONV_ERROR_MSG, "rootuse_sasl %d\n",
1424 ldap_conf.rootuse_sasl);
1425 sudo_printf(SUDO_CONV_ERROR_MSG, "rootsasl_auth_id %s\n",
1426 ldap_conf.rootsasl_auth_id ? ldap_conf.rootsasl_auth_id : "(NONE)");
1427 sudo_printf(SUDO_CONV_ERROR_MSG, "sasl_secprops %s\n",
1428 ldap_conf.sasl_secprops ? ldap_conf.sasl_secprops : "(NONE)");
1429 sudo_printf(SUDO_CONV_ERROR_MSG, "krb5_ccname %s\n",
1430 ldap_conf.krb5_ccname ? ldap_conf.krb5_ccname : "(NONE)");
1433 sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n");
1435 if (!ldap_conf.base)
1436 debug_return_bool(false); /* if no base is defined, ignore LDAP */
1438 if (ldap_conf.bind_timelimit > 0)
1439 ldap_conf.bind_timelimit *= 1000; /* convert to ms */
1442 * Interpret SSL option
1444 if (ldap_conf.ssl != NULL) {
1445 if (strcasecmp(ldap_conf.ssl, "start_tls") == 0)
1446 ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS;
1447 else if (atobool(ldap_conf.ssl) == true)
1448 ldap_conf.ssl_mode = SUDO_LDAP_SSL;
1451 #if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
1452 if (ldap_conf.tls_checkpeer != -1) {
1453 ldapssl_set_strength(NULL,
1454 ldap_conf.tls_checkpeer ? LDAPSSL_AUTH_CERT : LDAPSSL_AUTH_WEAK);
1458 #ifndef HAVE_LDAP_INITIALIZE
1459 /* Convert uri list to host list if no ldap_initialize(). */
1460 if (ldap_conf.uri) {
1461 struct ldap_config_list_str *uri = ldap_conf.uri;
1462 if (sudo_ldap_parse_uri(uri) != 0)
1463 debug_return_bool(false);
1465 ldap_conf.uri = uri->next;
1467 } while ((uri = ldap_conf.uri));
1468 ldap_conf.port = LDAP_PORT;
1472 if (!ldap_conf.uri) {
1473 /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
1474 if (ldap_conf.port < 0)
1476 ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
1478 #ifdef HAVE_LDAP_CREATE
1480 * Cannot specify port directly to ldap_create(), each host must
1481 * include :port to override the default.
1483 if (ldap_conf.port != LDAP_PORT)
1484 sudo_ldap_conf_add_ports();
1488 /* If search filter is not parenthesized, make it so. */
1489 if (ldap_conf.search_filter && ldap_conf.search_filter[0] != '(') {
1490 size_t len = strlen(ldap_conf.search_filter);
1491 cp = ldap_conf.search_filter;
1492 ldap_conf.search_filter = emalloc(len + 3);
1493 ldap_conf.search_filter[0] = '(';
1494 memcpy(ldap_conf.search_filter + 1, cp, len);
1495 ldap_conf.search_filter[len + 1] = ')';
1496 ldap_conf.search_filter[len + 2] = '\0';
1500 /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
1501 if (ldap_conf.rootbinddn)
1502 sudo_ldap_read_secret(_PATH_LDAP_SECRET);
1504 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1506 * Make sure we can open the file specified by krb5_ccname.
1508 if (ldap_conf.krb5_ccname != NULL) {
1509 if (strncasecmp(ldap_conf.krb5_ccname, "FILE:", 5) == 0 ||
1510 strncasecmp(ldap_conf.krb5_ccname, "WRFILE:", 7) == 0) {
1511 value = ldap_conf.krb5_ccname +
1512 (ldap_conf.krb5_ccname[4] == ':' ? 5 : 7);
1513 if ((fp = fopen(value, "r")) != NULL) {
1514 DPRINTF(("using krb5 credential cache: %s", value), 1);
1517 /* Can't open it, just ignore the entry. */
1518 DPRINTF(("unable to open krb5 credential cache: %s", value), 1);
1519 efree(ldap_conf.krb5_ccname);
1520 ldap_conf.krb5_ccname = NULL;
1525 debug_return_bool(true);
1529 * Extract the dn from an entry and return the first rdn from it.
1532 sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry)
1534 #ifdef HAVE_LDAP_STR2DN
1535 char *dn, *rdn = NULL;
1537 debug_decl(sudo_ldap_get_first_rdn, SUDO_DEBUG_LDAP)
1539 if ((dn = ldap_get_dn(ld, entry)) == NULL)
1540 debug_return_str(NULL);
1541 if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) {
1542 ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN);
1546 debug_return_str(rdn);
1549 debug_decl(sudo_ldap_get_first_rdn, SUDO_DEBUG_LDAP)
1551 if ((dn = ldap_get_dn(ld, entry)) == NULL)
1553 edn = ldap_explode_dn(dn, 1);
1555 debug_return_str(edn ? edn[0] : NULL);
1560 * Fetch and display the global Options.
1563 sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
1566 struct berval **bv, **p;
1567 struct timeval tv, *tvp = NULL;
1568 struct ldap_config_list_str *base;
1569 struct sudo_ldap_handle *handle = nss->handle;
1571 LDAPMessage *entry, *result;
1572 char *prefix, *filt;
1574 debug_decl(sudo_ldap_display_defaults, SUDO_DEBUG_LDAP)
1576 if (handle == NULL || handle->ld == NULL)
1580 filt = sudo_ldap_build_default_filter();
1581 for (base = ldap_conf.base; base != NULL; base = base->next) {
1582 if (ldap_conf.timeout > 0) {
1583 tv.tv_sec = ldap_conf.timeout;
1588 rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
1589 filt, NULL, 0, NULL, NULL, tvp, 0, &result);
1590 if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
1591 bv = ldap_get_values_len(ld, entry, "sudoOption");
1593 if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
1597 for (p = bv; *p != NULL; p++) {
1598 lbuf_append(lbuf, "%s%s", prefix, (*p)->bv_val);
1602 ldap_value_free_len(bv);
1606 ldap_msgfree(result);
1610 debug_return_int(count);
1617 sudo_ldap_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
1620 debug_decl(sudo_ldap_display_bound_defaults, SUDO_DEBUG_LDAP)
1621 debug_return_int(0);
1625 * Print a record in the short form, ala file sudoers.
1628 sudo_ldap_display_entry_short(LDAP *ld, LDAPMessage *entry, struct lbuf *lbuf)
1630 struct berval **bv, **p;
1632 debug_decl(sudo_ldap_display_entry_short, SUDO_DEBUG_LDAP)
1634 lbuf_append(lbuf, " (");
1636 /* get the RunAsUser Values from the entry */
1637 bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
1639 bv = ldap_get_values_len(ld, entry, "sudoRunAs");
1641 for (p = bv; *p != NULL; p++) {
1642 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1644 ldap_value_free_len(bv);
1646 lbuf_append(lbuf, "%s", def_runas_default);
1648 /* get the RunAsGroup Values from the entry */
1649 bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
1651 lbuf_append(lbuf, " : ");
1652 for (p = bv; *p != NULL; p++) {
1653 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1655 ldap_value_free_len(bv);
1657 lbuf_append(lbuf, ") ");
1659 /* get the Option Values from the entry */
1660 bv = ldap_get_values_len(ld, entry, "sudoOption");
1662 for (p = bv; *p != NULL; p++) {
1663 char *cp = (*p)->bv_val;
1666 if (strcmp(cp, "authenticate") == 0)
1667 lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
1668 "NOPASSWD: " : "PASSWD: ");
1669 else if (strcmp(cp, "noexec") == 0)
1670 lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
1671 "EXEC: " : "NOEXEC: ");
1672 else if (strcmp(cp, "setenv") == 0)
1673 lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
1674 "NOSETENV: " : "SETENV: ");
1676 ldap_value_free_len(bv);
1679 /* get the Command Values from the entry */
1680 bv = ldap_get_values_len(ld, entry, "sudoCommand");
1682 for (p = bv; *p != NULL; p++) {
1683 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1686 ldap_value_free_len(bv);
1688 lbuf_append(lbuf, "\n");
1690 debug_return_int(count);
1694 * Print a record in the long form.
1697 sudo_ldap_display_entry_long(LDAP *ld, LDAPMessage *entry, struct lbuf *lbuf)
1699 struct berval **bv, **p;
1702 debug_decl(sudo_ldap_display_entry_long, SUDO_DEBUG_LDAP)
1704 /* extract the dn, only show the first rdn */
1705 rdn = sudo_ldap_get_first_rdn(ld, entry);
1707 lbuf_append(lbuf, _("\nLDAP Role: %s\n"), rdn);
1709 lbuf_append(lbuf, _("\nLDAP Role: UNKNOWN\n"));
1713 /* get the RunAsUser Values from the entry */
1714 lbuf_append(lbuf, " RunAsUsers: ");
1715 bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
1717 bv = ldap_get_values_len(ld, entry, "sudoRunAs");
1719 for (p = bv; *p != NULL; p++) {
1720 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1722 ldap_value_free_len(bv);
1724 lbuf_append(lbuf, "%s", def_runas_default);
1725 lbuf_append(lbuf, "\n");
1727 /* get the RunAsGroup Values from the entry */
1728 bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
1730 lbuf_append(lbuf, " RunAsGroups: ");
1731 for (p = bv; *p != NULL; p++) {
1732 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1734 ldap_value_free_len(bv);
1735 lbuf_append(lbuf, "\n");
1738 /* get the Option Values from the entry */
1739 bv = ldap_get_values_len(ld, entry, "sudoOption");
1741 lbuf_append(lbuf, " Options: ");
1742 for (p = bv; *p != NULL; p++) {
1743 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1745 ldap_value_free_len(bv);
1746 lbuf_append(lbuf, "\n");
1750 * Display order attribute if present. This attribute is single valued,
1751 * so there is no need for a loop.
1753 bv = ldap_get_values_len(ld, entry, "sudoOrder");
1756 lbuf_append(lbuf, _(" Order: %s\n"), (*bv)->bv_val);
1758 ldap_value_free_len(bv);
1761 /* Get the command values from the entry. */
1762 bv = ldap_get_values_len(ld, entry, "sudoCommand");
1764 lbuf_append(lbuf, _(" Commands:\n"));
1765 for (p = bv; *p != NULL; p++) {
1766 lbuf_append(lbuf, "\t%s\n", (*p)->bv_val);
1769 ldap_value_free_len(bv);
1772 debug_return_int(count);
1776 * Like sudo_ldap_lookup(), except we just print entries.
1779 sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
1782 struct sudo_ldap_handle *handle = nss->handle;
1784 struct ldap_result *lres;
1787 debug_decl(sudo_ldap_display_privs, SUDO_DEBUG_LDAP)
1789 if (handle == NULL || handle->ld == NULL)
1793 DPRINTF(("ldap search for command list"), 1);
1794 lres = sudo_ldap_result_get(nss, pw);
1796 /* Display all matching entries. */
1797 for (i = 0; i < lres->nentries; i++) {
1798 entry = lres->entries[i].entry;
1800 count += sudo_ldap_display_entry_long(ld, entry, lbuf);
1802 count += sudo_ldap_display_entry_short(ld, entry, lbuf);
1806 debug_return_int(count);
1810 sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
1812 struct sudo_ldap_handle *handle = nss->handle;
1814 struct ldap_result *lres;
1818 debug_decl(sudo_ldap_display_cmnd, SUDO_DEBUG_LDAP)
1820 if (handle == NULL || handle->ld == NULL)
1825 * The sudo_ldap_result_get() function returns all nodes that match
1826 * the user and the host.
1828 DPRINTF(("ldap search for command list"), 1);
1829 lres = sudo_ldap_result_get(nss, pw);
1830 for (i = 0; i < lres->nentries; i++) {
1831 entry = lres->entries[i].entry;
1832 if (sudo_ldap_check_command(ld, entry, NULL) &&
1833 sudo_ldap_check_runas(ld, entry)) {
1841 printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
1842 user_args ? " " : "", user_args ? user_args : "");
1843 debug_return_bool(!found);
1846 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1848 sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags, void *_auth_id,
1851 char *auth_id = (char *)_auth_id;
1852 sasl_interact_t *interact = (sasl_interact_t *)_interact;
1853 debug_decl(sudo_ldap_sasl_interact, SUDO_DEBUG_LDAP)
1855 for (; interact->id != SASL_CB_LIST_END; interact++) {
1856 if (interact->id != SASL_CB_USER)
1857 debug_return_int(LDAP_PARAM_ERROR);
1859 if (auth_id != NULL)
1860 interact->result = auth_id;
1861 else if (interact->defresult != NULL)
1862 interact->result = interact->defresult;
1864 interact->result = "";
1866 interact->len = strlen(interact->result);
1867 #if SASL_VERSION_MAJOR < 2
1868 interact->result = estrdup(interact->result);
1869 #endif /* SASL_VERSION_MAJOR < 2 */
1871 debug_return_int(LDAP_SUCCESS);
1873 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
1876 * Set LDAP options based on the config table.
1879 sudo_ldap_set_options(LDAP *ld)
1881 struct ldap_config_table *cur;
1883 debug_decl(sudo_ldap_set_options, SUDO_DEBUG_LDAP)
1885 /* Set ber options */
1886 #ifdef LBER_OPT_DEBUG_LEVEL
1887 if (ldap_conf.ldap_debug)
1888 ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug);
1891 /* Set simple LDAP options */
1892 for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
1897 if (cur->opt_val == -1)
1900 conn = cur->connected ? ld : NULL;
1901 switch (cur->type) {
1904 ival = *(int *)(cur->valp);
1906 rc = ldap_set_option(conn, cur->opt_val, &ival);
1907 if (rc != LDAP_OPT_SUCCESS) {
1908 warningx("ldap_set_option: %s -> %d: %s",
1909 cur->conf_str, ival, ldap_err2string(rc));
1910 debug_return_int(-1);
1912 DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
1916 sval = *(char **)(cur->valp);
1918 rc = ldap_set_option(conn, cur->opt_val, sval);
1919 if (rc != LDAP_OPT_SUCCESS) {
1920 warningx("ldap_set_option: %s -> %s: %s",
1921 cur->conf_str, sval, ldap_err2string(rc));
1922 debug_return_int(-1);
1924 DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
1930 #ifdef LDAP_OPT_TIMEOUT
1931 /* Convert timeout to a timeval */
1932 if (ldap_conf.timeout > 0) {
1934 tv.tv_sec = ldap_conf.timeout;
1936 rc = ldap_set_option(ld, LDAP_OPT_TIMEOUT, &tv);
1937 if (rc != LDAP_OPT_SUCCESS) {
1938 warningx("ldap_set_option(TIMEOUT, %ld): %s",
1939 (long)tv.tv_sec, ldap_err2string(rc));
1940 debug_return_int(-1);
1942 DPRINTF(("ldap_set_option(LDAP_OPT_TIMEOUT, %ld)",
1943 (long)tv.tv_sec), 1);
1946 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1947 /* Convert bind_timelimit to a timeval */
1948 if (ldap_conf.bind_timelimit > 0) {
1950 tv.tv_sec = ldap_conf.bind_timelimit / 1000;
1952 rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
1953 if (rc != LDAP_OPT_SUCCESS) {
1954 warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
1955 (long)tv.tv_sec, ldap_err2string(rc));
1956 debug_return_int(-1);
1958 DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)",
1959 (long)tv.tv_sec), 1);
1963 #if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT)
1964 if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
1965 int val = LDAP_OPT_X_TLS_HARD;
1966 rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
1967 if (rc != LDAP_SUCCESS) {
1968 warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
1969 ldap_err2string(rc));
1970 debug_return_int(-1);
1972 DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)"), 1);
1975 debug_return_int(0);
1979 * Create a new sudo_ldap_result structure.
1981 static struct ldap_result *
1982 sudo_ldap_result_alloc(void)
1984 struct ldap_result *result;
1985 debug_decl(sudo_ldap_result_alloc, SUDO_DEBUG_LDAP)
1987 result = emalloc(sizeof(*result));
1988 result->searches = NULL;
1989 result->nentries = 0;
1990 result->entries = NULL;
1991 result->allocated_entries = 0;
1992 result->user_matches = false;
1993 result->host_matches = false;
1994 debug_return_ptr(result);
1998 * Free the ldap result structure
2001 sudo_ldap_result_free(struct ldap_result *lres)
2003 struct ldap_search_list *s;
2004 debug_decl(sudo_ldap_result_free, SUDO_DEBUG_LDAP)
2007 if (lres->nentries) {
2008 efree(lres->entries);
2009 lres->entries = NULL;
2011 if (lres->searches) {
2012 while ((s = lres->searches) != NULL) {
2013 ldap_msgfree(s->searchresult);
2014 lres->searches = s->next;
2024 * Add a search result to the ldap_result structure.
2026 static struct ldap_search_list *
2027 sudo_ldap_result_add_search(struct ldap_result *lres, LDAP *ldap,
2028 LDAPMessage *searchresult)
2030 struct ldap_search_list *s, *news;
2031 debug_decl(sudo_ldap_result_add_search, SUDO_DEBUG_LDAP)
2033 news = emalloc(sizeof(struct ldap_search_list));
2036 news->searchresult = searchresult;
2038 /* Add entry to the end of the chain (XXX - tailq instead?). */
2039 if (lres->searches) {
2040 for (s = lres->searches; s->next != NULL; s = s->next)
2044 lres->searches = news;
2046 debug_return_ptr(news);
2050 * Connect to the LDAP server specified by ld
2053 sudo_ldap_bind_s(LDAP *ld)
2056 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
2057 const char *old_ccname = user_ccname;
2058 # ifdef HAVE_GSS_KRB5_CCACHE_NAME
2059 unsigned int status;
2062 debug_decl(sudo_ldap_bind_s, SUDO_DEBUG_LDAP)
2064 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
2065 if (ldap_conf.rootuse_sasl == true ||
2066 (ldap_conf.rootuse_sasl != false && ldap_conf.use_sasl == true)) {
2067 void *auth_id = ldap_conf.rootsasl_auth_id ?
2068 ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id;
2070 if (ldap_conf.krb5_ccname != NULL) {
2071 # ifdef HAVE_GSS_KRB5_CCACHE_NAME
2072 if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname)
2073 != GSS_S_COMPLETE) {
2075 DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
2078 setenv("KRB5CCNAME", ldap_conf.krb5_ccname, true);
2081 rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI",
2082 NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id);
2083 if (ldap_conf.krb5_ccname != NULL) {
2084 # ifdef HAVE_GSS_KRB5_CCACHE_NAME
2085 if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE)
2086 DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
2088 if (old_ccname != NULL)
2089 setenv("KRB5CCNAME", old_ccname, true);
2091 unsetenv("KRB5CCNAME");
2094 if (rc != LDAP_SUCCESS) {
2095 warningx("ldap_sasl_interactive_bind_s(): %s",
2096 ldap_err2string(rc));
2097 debug_return_int(-1);
2099 DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1);
2101 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
2102 #ifdef HAVE_LDAP_SASL_BIND_S
2106 bv.bv_val = ldap_conf.bindpw ? ldap_conf.bindpw : "";
2107 bv.bv_len = strlen(bv.bv_val);
2109 rc = ldap_sasl_bind_s(ld, ldap_conf.binddn, LDAP_SASL_SIMPLE, &bv,
2111 if (rc != LDAP_SUCCESS) {
2112 warningx("ldap_sasl_bind_s(): %s", ldap_err2string(rc));
2113 debug_return_int(-1);
2115 DPRINTF(("ldap_sasl_bind_s() ok"), 1);
2119 rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw);
2120 if (rc != LDAP_SUCCESS) {
2121 warningx("ldap_simple_bind_s(): %s", ldap_err2string(rc));
2122 debug_return_int(-1);
2124 DPRINTF(("ldap_simple_bind_s() ok"), 1);
2127 debug_return_int(0);
2131 * Open a connection to the LDAP server.
2132 * Returns 0 on success and non-zero on failure.
2135 sudo_ldap_open(struct sudo_nss *nss)
2139 bool ldapnoinit = false;
2140 struct sudo_ldap_handle *handle;
2141 debug_decl(sudo_ldap_open, SUDO_DEBUG_LDAP)
2143 if (!sudo_ldap_read_config())
2144 debug_return_int(-1);
2146 /* Prevent reading of user ldaprc and system defaults. */
2147 if (getenv("LDAPNOINIT") == NULL) {
2149 setenv("LDAPNOINIT", "1", true);
2152 /* Connect to LDAP server */
2153 #ifdef HAVE_LDAP_INITIALIZE
2154 if (ldap_conf.uri != NULL) {
2155 char *buf = sudo_ldap_join_uri(ldap_conf.uri);
2156 DPRINTF(("ldap_initialize(ld, %s)", buf), 2);
2157 rc = ldap_initialize(&ld, buf);
2161 rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);
2162 if (rc != LDAP_SUCCESS) {
2163 warningx(_("unable to initialize LDAP: %s"), ldap_err2string(rc));
2164 debug_return_int(-1);
2168 unsetenv("LDAPNOINIT");
2170 /* Set LDAP options */
2171 if (sudo_ldap_set_options(ld) < 0)
2172 debug_return_int(-1);
2174 if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
2175 #if defined(HAVE_LDAP_START_TLS_S)
2176 rc = ldap_start_tls_s(ld, NULL, NULL);
2177 if (rc != LDAP_SUCCESS) {
2178 warningx("ldap_start_tls_s(): %s", ldap_err2string(rc));
2179 debug_return_int(-1);
2181 DPRINTF(("ldap_start_tls_s() ok"), 1);
2182 #elif defined(HAVE_LDAP_SSL_CLIENT_INIT) && defined(HAVE_LDAP_START_TLS_S_NP)
2183 if (ldap_ssl_client_init(NULL, NULL, 0, &rc) != LDAP_SUCCESS) {
2184 warningx("ldap_ssl_client_init(): %s", ldap_err2string(rc));
2185 debug_return_int(-1);
2187 rc = ldap_start_tls_s_np(ld, NULL);
2188 if (rc != LDAP_SUCCESS) {
2189 warningx("ldap_start_tls_s_np(): %s", ldap_err2string(rc));
2190 debug_return_int(-1);
2192 DPRINTF(("ldap_start_tls_s_np() ok"), 1);
2194 warningx(_("start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()"));
2195 #endif /* !HAVE_LDAP_START_TLS_S && !HAVE_LDAP_START_TLS_S_NP */
2198 /* Actually connect */
2199 if (sudo_ldap_bind_s(ld) != 0)
2200 debug_return_int(-1);
2202 /* Create a handle container. */
2203 handle = emalloc(sizeof(struct sudo_ldap_handle));
2205 handle->result = NULL;
2206 handle->username = NULL;
2207 handle->grlist = NULL;
2208 nss->handle = handle;
2210 debug_return_int(0);
2214 sudo_ldap_setdefs(struct sudo_nss *nss)
2216 struct ldap_config_list_str *base;
2217 struct sudo_ldap_handle *handle = nss->handle;
2218 struct timeval tv, *tvp = NULL;
2220 LDAPMessage *entry, *result;
2223 debug_decl(sudo_ldap_setdefs, SUDO_DEBUG_LDAP)
2225 if (handle == NULL || handle->ld == NULL)
2226 debug_return_int(-1);
2229 filt = sudo_ldap_build_default_filter();
2230 DPRINTF(("Looking for cn=defaults: %s", filt), 1);
2232 for (base = ldap_conf.base; base != NULL; base = base->next) {
2233 if (ldap_conf.timeout > 0) {
2234 tv.tv_sec = ldap_conf.timeout;
2239 rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
2240 filt, NULL, 0, NULL, NULL, tvp, 0, &result);
2241 if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
2242 DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
2243 sudo_ldap_parse_options(ld, entry);
2245 DPRINTF(("no default options found in %s", base->val), 1);
2248 ldap_msgfree(result);
2252 debug_return_int(0);
2256 * like sudoers_lookup() - only LDAP style
2259 sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
2261 struct sudo_ldap_handle *handle = nss->handle;
2264 int i, rc, setenv_implied;
2265 struct ldap_result *lres = NULL;
2266 debug_decl(sudo_ldap_lookup, SUDO_DEBUG_LDAP)
2268 if (handle == NULL || handle->ld == NULL)
2269 debug_return_int(ret);
2272 /* Fetch list of sudoRole entries that match user and host. */
2273 lres = sudo_ldap_result_get(nss, sudo_user.pw);
2276 * The following queries are only determine whether or not a
2277 * password is required, so the order of the entries doesn't matter.
2280 int doauth = UNSPEC;
2281 int matched = UNSPEC;
2282 enum def_tuple pwcheck =
2283 (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
2285 DPRINTF(("perform search for pwflag %d", pwflag), 1);
2286 for (i = 0; i < lres->nentries; i++) {
2287 entry = lres->entries[i].entry;
2288 if ((pwcheck == any && doauth != false) ||
2289 (pwcheck == all && doauth == false)) {
2290 doauth = sudo_ldap_check_bool(ld, entry, "authenticate");
2292 /* Only check the command when listing another user. */
2293 if (user_uid == 0 || list_pw == NULL ||
2294 user_uid == list_pw->pw_uid ||
2295 sudo_ldap_check_command(ld, entry, NULL)) {
2300 if (matched || user_uid == 0) {
2301 SET(ret, VALIDATE_OK);
2302 CLR(ret, VALIDATE_NOT_OK);
2303 if (def_authenticate) {
2306 SET(ret, FLAG_CHECK_USER);
2310 if (doauth == false)
2311 def_authenticate = false;
2314 def_authenticate = false;
2324 DPRINTF(("searching LDAP for sudoers entries"), 1);
2326 setenv_implied = false;
2327 for (i = 0; i < lres->nentries; i++) {
2328 entry = lres->entries[i].entry;
2329 if (!sudo_ldap_check_runas(ld, entry))
2331 rc = sudo_ldap_check_command(ld, entry, &setenv_implied);
2333 /* We have a match. */
2334 DPRINTF(("Command %sallowed", rc == true ? "" : "NOT "), 1);
2336 DPRINTF(("LDAP entry: %p", entry), 1);
2337 /* Apply entry-specific options. */
2340 sudo_ldap_parse_options(ld, entry);
2342 /* Set role and type if not specified on command line. */
2343 if (user_role == NULL)
2344 user_role = def_role;
2345 if (user_type == NULL)
2346 user_type = def_type;
2347 #endif /* HAVE_SELINUX */
2348 SET(ret, VALIDATE_OK);
2349 CLR(ret, VALIDATE_NOT_OK);
2351 SET(ret, VALIDATE_NOT_OK);
2352 CLR(ret, VALIDATE_OK);
2359 DPRINTF(("done with LDAP searches"), 1);
2360 DPRINTF(("user_matches=%d", lres->user_matches), 1);
2361 DPRINTF(("host_matches=%d", lres->host_matches), 1);
2363 if (!ISSET(ret, VALIDATE_OK)) {
2364 /* No matching entries. */
2365 if (pwflag && list_pw == NULL)
2366 SET(ret, FLAG_NO_CHECK);
2368 if (lres->user_matches)
2369 CLR(ret, FLAG_NO_USER);
2370 if (lres->host_matches)
2371 CLR(ret, FLAG_NO_HOST);
2372 DPRINTF(("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret), 1);
2374 debug_return_int(ret);
2378 * Comparison function for ldap_entry_wrapper structures, descending order.
2381 ldap_entry_compare(const void *a, const void *b)
2383 const struct ldap_entry_wrapper *aw = a;
2384 const struct ldap_entry_wrapper *bw = b;
2385 debug_decl(ldap_entry_compare, SUDO_DEBUG_LDAP)
2387 debug_return_int(bw->order < aw->order ? -1 :
2388 (bw->order > aw->order ? 1 : 0));
2392 * Find the last entry in the list of searches, usually the
2393 * one currently being used to add entries.
2394 * XXX - use a tailq instead?
2396 static struct ldap_search_list *
2397 sudo_ldap_result_last_search(struct ldap_result *lres)
2399 struct ldap_search_list *result = lres->searches;
2400 debug_decl(sudo_ldap_result_last_search, SUDO_DEBUG_LDAP)
2403 while (result->next)
2404 result = result->next;
2406 debug_return_ptr(result);
2410 * Add an entry to the result structure.
2412 static struct ldap_entry_wrapper *
2413 sudo_ldap_result_add_entry(struct ldap_result *lres, LDAPMessage *entry)
2415 struct ldap_search_list *last;
2419 debug_decl(sudo_ldap_result_add_entry, SUDO_DEBUG_LDAP)
2421 /* Determine whether the entry has the sudoOrder attribute. */
2422 last = sudo_ldap_result_last_search(lres);
2423 bv = ldap_get_values_len(last->ldap, entry, "sudoOrder");
2425 if (ldap_count_values_len(bv) > 0) {
2426 /* Get the value of this attribute, 0 if not present. */
2427 DPRINTF(("order attribute raw: %s", (*bv)->bv_val), 1);
2428 order = strtod((*bv)->bv_val, &ep);
2429 if (ep == (*bv)->bv_val || *ep != '\0') {
2430 warningx(_("invalid sudoOrder attribute: %s"), (*bv)->bv_val);
2433 DPRINTF(("order attribute: %f", order), 1);
2435 ldap_value_free_len(bv);
2439 * Enlarge the array of entry wrappers as needed, preallocating blocks
2440 * of 100 entries to save on allocation time.
2442 if (++lres->nentries > lres->allocated_entries) {
2443 lres->allocated_entries += ALLOCATION_INCREMENT;
2444 lres->entries = erealloc3(lres->entries, lres->allocated_entries,
2445 sizeof(lres->entries[0]));
2448 /* Fill in the new entry and return it. */
2449 lres->entries[lres->nentries - 1].entry = entry;
2450 lres->entries[lres->nentries - 1].order = order;
2452 debug_return_ptr(&lres->entries[lres->nentries - 1]);
2456 * Free the ldap result structure in the sudo_nss handle.
2459 sudo_ldap_result_free_nss(struct sudo_nss *nss)
2461 struct sudo_ldap_handle *handle = nss->handle;
2462 debug_decl(sudo_ldap_result_free_nss, SUDO_DEBUG_LDAP)
2464 if (handle->result != NULL) {
2465 DPRINTF(("removing reusable search result"), 1);
2466 sudo_ldap_result_free(handle->result);
2467 if (handle->username) {
2468 efree(handle->username);
2469 handle->username = NULL;
2471 handle->grlist = NULL;
2472 handle->result = NULL;
2478 * Perform the LDAP query for the user or return a cached query if
2479 * there is one for this user.
2481 static struct ldap_result *
2482 sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
2484 struct sudo_ldap_handle *handle = nss->handle;
2485 struct ldap_config_list_str *base;
2486 struct ldap_result *lres;
2487 struct timeval tv, *tvp = NULL;
2488 LDAPMessage *entry, *result;
2489 LDAP *ld = handle->ld;
2492 debug_decl(sudo_ldap_result_get, SUDO_DEBUG_LDAP)
2495 * If we already have a cached result, return it so we don't have to
2496 * have to contact the LDAP server again.
2498 if (handle->result) {
2499 if (handle->grlist == user_group_list &&
2500 strcmp(pw->pw_name, handle->username) == 0) {
2501 DPRINTF(("reusing previous result (user %s) with %d entries",
2502 handle->username, handle->result->nentries), 1);
2503 debug_return_ptr(handle->result);
2505 /* User mismatch, cached result cannot be used. */
2506 DPRINTF(("removing result (user %s), new search (user %s)",
2507 handle->username, pw->pw_name), 1);
2508 sudo_ldap_result_free_nss(nss);
2512 * Okay - time to search for anything that matches this user
2513 * Lets limit it to only two queries of the LDAP server
2515 * The first pass will look by the username, groups, and
2516 * the keyword ALL. We will then inspect the results that
2517 * came back from the query. We don't need to inspect the
2518 * sudoUser in this pass since the LDAP server already scanned
2521 * The second pass will return all the entries that contain
2522 * user netgroups. Then we take the netgroups returned and
2523 * try to match them against the username.
2525 * Since we have to sort the possible entries before we make a
2526 * decision, we perform the queries and store all of the results in
2527 * an ldap_result object. The results are then sorted by sudoOrder.
2529 lres = sudo_ldap_result_alloc();
2530 for (do_netgr = 0; do_netgr < 2; do_netgr++) {
2531 filt = do_netgr ? sudo_ldap_build_pass2() : sudo_ldap_build_pass1(pw);
2532 DPRINTF(("ldap search '%s'", filt), 1);
2533 for (base = ldap_conf.base; base != NULL; base = base->next) {
2534 DPRINTF(("searching from base '%s'", base->val), 1);
2535 if (ldap_conf.timeout > 0) {
2536 tv.tv_sec = ldap_conf.timeout;
2541 rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt,
2542 NULL, 0, NULL, NULL, tvp, 0, &result);
2543 if (rc != LDAP_SUCCESS) {
2544 DPRINTF(("nothing found for '%s'", filt), 1);
2547 lres->user_matches = true;
2549 /* Add the seach result to list of search results. */
2550 DPRINTF(("adding search result"), 1);
2551 sudo_ldap_result_add_search(lres, ld, result);
2552 LDAP_FOREACH(entry, ld, result) {
2554 sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
2555 sudo_ldap_check_host(ld, entry)) {
2556 lres->host_matches = true;
2557 sudo_ldap_result_add_entry(lres, entry);
2560 DPRINTF(("result now has %d entries", lres->nentries), 1);
2565 /* Sort the entries by the sudoOrder attribute. */
2566 DPRINTF(("sorting remaining %d entries", lres->nentries), 1);
2567 qsort(lres->entries, lres->nentries, sizeof(lres->entries[0]),
2568 ldap_entry_compare);
2570 /* Store everything in the sudo_nss handle. */
2571 handle->result = lres;
2572 handle->username = estrdup(pw->pw_name);
2573 handle->grlist = user_group_list;
2575 debug_return_ptr(lres);
2579 * Shut down the LDAP connection.
2582 sudo_ldap_close(struct sudo_nss *nss)
2584 struct sudo_ldap_handle *handle = nss->handle;
2585 debug_decl(sudo_ldap_close, SUDO_DEBUG_LDAP)
2587 if (handle != NULL) {
2588 /* Free the result before unbinding; it may use the LDAP connection. */
2589 sudo_ldap_result_free_nss(nss);
2591 /* Unbind and close the LDAP connection. */
2592 if (handle->ld != NULL) {
2593 ldap_unbind_ext_s(handle->ld, NULL, NULL);
2597 /* Free the handle container. */
2601 debug_return_int(0);
2608 sudo_ldap_parse(struct sudo_nss *nss)
2615 * Create an ldap_result from an LDAP search result.
2617 * This function is currently not used anywhere, it is left here as
2618 * an example of how to use the cached searches.
2620 static struct ldap_result *
2621 sudo_ldap_result_from_search(LDAP *ldap, LDAPMessage *searchresult)
2624 * An ldap_result is built from several search results, which are
2625 * organized in a list. The head of the list is maintained in the
2626 * ldap_result structure, together with the wrappers that point
2627 * to individual entries, this has to be initialized first.
2629 struct ldap_result *result = sudo_ldap_result_alloc();
2632 * Build a new list node for the search result, this creates the
2635 struct ldap_search_list *last = sudo_ldap_result_add_search(result,
2636 ldap, searchresult);
2639 * Now add each entry in the search result to the array of of entries
2640 * in the ldap_result object.
2643 LDAP_FOREACH(entry, last->ldap, last->searchresult) {
2644 sudo_ldap_result_add_entry(result, entry);
2646 DPRINTF(("sudo_ldap_result_from_search: %d entries found",
2647 result->nentries), 2);