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_CLEAR 0
128 #define SUDO_LDAP_SSL 1
129 #define SUDO_LDAP_STARTTLS 2
131 /* The TIMEFILTER_LENGTH includes the filter itself plus the global AND
132 wrapped around the user filter and the time filter when timed entries
133 are used. The length is computed as follows:
135 + 2 * 13 for the now timestamp
136 + 3 for the global AND
138 #define TIMEFILTER_LENGTH 114
141 * The ldap_search structure implements a linked list of ldap and
142 * search result pointers, which allows us to remove them after
143 * all search results have been combined in memory.
144 * XXX - should probably be a tailq since we do appends
146 struct ldap_search_list {
148 LDAPMessage *searchresult;
149 struct ldap_search_list *next;
153 * The ldap_entry_wrapper structure is used to implement sorted result entries.
154 * A double is used for the order to allow for insertion of new entries
155 * without having to renumber everything.
156 * Note: there is no standard floating point type in LDAP.
157 * As a result, some LDAP servers will only allow an integer.
159 struct ldap_entry_wrapper {
165 * The ldap_result structure contains the list of matching searches as
166 * well as an array of all result entries sorted by the sudoOrder attribute.
169 struct ldap_search_list *searches;
170 struct ldap_entry_wrapper *entries;
171 int allocated_entries;
176 #define ALLOCATION_INCREMENT 100
178 struct ldap_config_table {
179 const char *conf_str; /* config file string */
180 int type; /* CONF_BOOL, CONF_INT, CONF_STR */
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_global[] = {
226 { "sudoers_debug", CONF_INT, -1, &ldap_conf.debug },
227 { "host", CONF_STR, -1, &ldap_conf.host },
228 { "port", CONF_INT, -1, &ldap_conf.port },
229 { "ssl", CONF_STR, -1, &ldap_conf.ssl },
230 { "sslpath", CONF_STR, -1, &ldap_conf.tls_certfile },
231 { "uri", CONF_LIST_STR, -1, &ldap_conf.uri },
232 #ifdef LDAP_OPT_DEBUG_LEVEL
233 { "debug", CONF_INT, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
235 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
236 { "tls_checkpeer", CONF_BOOL, LDAP_OPT_X_TLS_REQUIRE_CERT,
237 &ldap_conf.tls_checkpeer },
239 { "tls_checkpeer", CONF_BOOL, -1, &ldap_conf.tls_checkpeer },
241 #ifdef LDAP_OPT_X_TLS_CACERTFILE
242 { "tls_cacertfile", CONF_STR, LDAP_OPT_X_TLS_CACERTFILE,
243 &ldap_conf.tls_cacertfile },
244 { "tls_cacert", CONF_STR, LDAP_OPT_X_TLS_CACERTFILE,
245 &ldap_conf.tls_cacertfile },
247 #ifdef LDAP_OPT_X_TLS_CACERTDIR
248 { "tls_cacertdir", CONF_STR, LDAP_OPT_X_TLS_CACERTDIR,
249 &ldap_conf.tls_cacertdir },
251 #ifdef LDAP_OPT_X_TLS_RANDOM_FILE
252 { "tls_randfile", CONF_STR, LDAP_OPT_X_TLS_RANDOM_FILE,
253 &ldap_conf.tls_random_file },
255 #ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
256 { "tls_ciphers", CONF_STR, LDAP_OPT_X_TLS_CIPHER_SUITE,
257 &ldap_conf.tls_cipher_suite },
259 #ifdef LDAP_OPT_X_TLS_CERTFILE
260 { "tls_cert", CONF_STR, LDAP_OPT_X_TLS_CERTFILE,
261 &ldap_conf.tls_certfile },
263 { "tls_cert", CONF_STR, -1, &ldap_conf.tls_certfile },
265 #ifdef LDAP_OPT_X_TLS_KEYFILE
266 { "tls_key", CONF_STR, LDAP_OPT_X_TLS_KEYFILE,
267 &ldap_conf.tls_keyfile },
269 { "tls_key", CONF_STR, -1, &ldap_conf.tls_keyfile },
271 { "binddn", CONF_STR, -1, &ldap_conf.binddn },
272 { "bindpw", CONF_STR, -1, &ldap_conf.bindpw },
273 { "rootbinddn", CONF_STR, -1, &ldap_conf.rootbinddn },
274 { "sudoers_base", CONF_LIST_STR, -1, &ldap_conf.base },
275 { "sudoers_timed", CONF_BOOL, -1, &ldap_conf.timed },
276 { "sudoers_search_filter", CONF_STR, -1, &ldap_conf.search_filter },
277 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
278 { "use_sasl", CONF_BOOL, -1, &ldap_conf.use_sasl },
279 { "sasl_auth_id", CONF_STR, -1, &ldap_conf.sasl_auth_id },
280 { "rootuse_sasl", CONF_BOOL, -1, &ldap_conf.rootuse_sasl },
281 { "rootsasl_auth_id", CONF_STR, -1, &ldap_conf.rootsasl_auth_id },
282 { "krb5_ccname", CONF_STR, -1, &ldap_conf.krb5_ccname },
283 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
287 static struct ldap_config_table ldap_conf_conn[] = {
288 #ifdef LDAP_OPT_PROTOCOL_VERSION
289 { "ldap_version", CONF_INT, LDAP_OPT_PROTOCOL_VERSION,
290 &ldap_conf.version },
292 #ifdef LDAP_OPT_NETWORK_TIMEOUT
293 { "bind_timelimit", CONF_INT, -1 /* needs timeval, set manually */,
294 &ldap_conf.bind_timelimit },
295 { "network_timeout", CONF_INT, -1 /* needs timeval, set manually */,
296 &ldap_conf.bind_timelimit },
297 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
298 { "bind_timelimit", CONF_INT, LDAP_X_OPT_CONNECT_TIMEOUT,
299 &ldap_conf.bind_timelimit },
300 { "network_timeout", CONF_INT, LDAP_X_OPT_CONNECT_TIMEOUT,
301 &ldap_conf.bind_timelimit },
303 { "timelimit", CONF_INT, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit },
304 #ifdef LDAP_OPT_TIMEOUT
305 { "timeout", CONF_INT, -1 /* needs timeval, set manually */,
306 &ldap_conf.timeout },
308 #ifdef LDAP_OPT_DEREF
309 { "deref", CONF_DEREF_VAL, LDAP_OPT_DEREF, &ldap_conf.deref },
311 #ifdef LDAP_OPT_X_SASL_SECPROPS
312 { "sasl_secprops", CONF_STR, LDAP_OPT_X_SASL_SECPROPS,
313 &ldap_conf.sasl_secprops },
318 /* sudo_nss implementation */
319 static int sudo_ldap_open(struct sudo_nss *nss);
320 static int sudo_ldap_close(struct sudo_nss *nss);
321 static int sudo_ldap_parse(struct sudo_nss *nss);
322 static int sudo_ldap_setdefs(struct sudo_nss *nss);
323 static int sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag);
324 static int sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
325 static int sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
327 static int sudo_ldap_display_bound_defaults(struct sudo_nss *nss,
328 struct passwd *pw, struct lbuf *lbuf);
329 static int sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
331 static struct ldap_result *sudo_ldap_result_get(struct sudo_nss *nss,
335 * LDAP sudo_nss handle.
336 * We store the connection to the LDAP server, the cached ldap_result object
337 * (if any), and the name of the user the query was performed for.
338 * If a new query is launched with sudo_ldap_result_get() that specifies a
339 * different user, the old cached result is freed before the new query is run.
341 struct sudo_ldap_handle {
343 struct ldap_result *result;
345 struct group_list *grlist;
348 struct sudo_nss sudo_nss_ldap = {
356 sudo_ldap_display_cmnd,
357 sudo_ldap_display_defaults,
358 sudo_ldap_display_bound_defaults,
359 sudo_ldap_display_privs
362 #ifdef HAVE_LDAP_CREATE
364 * Rebuild the hosts list and include a specific port for each host.
365 * ldap_create() does not take a default port parameter so we must
366 * append one if we want something other than LDAP_PORT.
369 sudo_ldap_conf_add_ports(void)
372 char *host, *port, defport[13];
373 char hostbuf[LINE_MAX * 2];
374 debug_decl(sudo_ldap_conf_add_ports, SUDO_DEBUG_LDAP)
377 if (snprintf(defport, sizeof(defport), ":%d", ldap_conf.port) >= sizeof(defport))
378 errorx(1, _("sudo_ldap_conf_add_ports: port too large"));
380 for ((host = strtok(ldap_conf.host, " \t")); host; (host = strtok(NULL, " \t"))) {
381 if (hostbuf[0] != '\0') {
382 if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
386 if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
388 /* Append port if there is not one already. */
389 if ((port = strrchr(host, ':')) == NULL ||
390 !isdigit((unsigned char)port[1])) {
391 if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf))
396 efree(ldap_conf.host);
397 ldap_conf.host = estrdup(hostbuf);
401 errorx(1, _("sudo_ldap_conf_add_ports: out of space expanding hostbuf"));
405 #ifndef HAVE_LDAP_INITIALIZE
407 * For each uri, convert to host:port pairs. For ldaps:// enable SSL
408 * Accepts: uris of the form ldap:/// or ldap://hostname:portnum/
409 * where the trailing slash is optional.
412 sudo_ldap_parse_uri(const struct ldap_config_list_str *uri_list)
414 char *buf, *uri, *host, *cp, *port;
415 char hostbuf[LINE_MAX];
416 int nldap = 0, nldaps = 0;
418 debug_decl(sudo_ldap_parse_uri, SUDO_DEBUG_LDAP)
421 buf = estrdup(uri_list->val);
423 for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
424 if (strncasecmp(uri, "ldap://", 7) == 0) {
427 } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
431 warningx(_("unsupported LDAP uri type: %s"), uri);
435 /* trim optional trailing slash */
436 if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
440 if (hostbuf[0] != '\0') {
441 if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
446 host = "localhost"; /* no host specified, use localhost */
448 if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
451 /* If using SSL and no port specified, add port 636 */
453 if ((port = strrchr(host, ':')) == NULL ||
454 !isdigit((unsigned char)port[1]))
455 if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
459 if (hostbuf[0] == '\0') {
460 warningx(_("invalid uri: %s"), uri_list->val);
466 warningx(_("unable to mix ldap and ldaps URIs"));
469 if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
470 warningx(_("unable to mix ldaps and starttls"));
473 ldap_conf.ssl_mode = SUDO_LDAP_SSL;
476 efree(ldap_conf.host);
477 ldap_conf.host = estrdup(hostbuf);
479 } while ((uri_list = uri_list->next));
486 debug_return_int(rc);
489 errorx(1, _("sudo_ldap_parse_uri: out of space building hostbuf"));
493 sudo_ldap_join_uri(struct ldap_config_list_str *uri_list)
495 struct ldap_config_list_str *uri;
498 debug_decl(sudo_ldap_join_uri, SUDO_DEBUG_LDAP)
500 /* Usually just a single entry. */
501 if (uri_list->next == NULL)
502 debug_return_str(estrdup(uri_list->val));
504 for (uri = uri_list; uri != NULL; uri = uri->next) {
505 len += strlen(uri->val) + 1;
507 buf = cp = emalloc(len);
509 for (uri = uri_list; uri != NULL; uri = uri->next) {
510 cp += strlcpy(cp, uri->val, len - (cp - buf));
514 debug_return_str(buf);
516 #endif /* HAVE_LDAP_INITIALIZE */
519 sudo_ldap_init(LDAP **ldp, const char *host, int port)
522 int rc = LDAP_CONNECT_ERROR;
523 debug_decl(sudo_ldap_init, SUDO_DEBUG_LDAP)
525 #ifdef HAVE_LDAPSSL_INIT
526 if (ldap_conf.ssl_mode != SUDO_LDAP_CLEAR) {
527 const int defsecure = ldap_conf.ssl_mode == SUDO_LDAP_SSL;
528 DPRINTF(("ldapssl_clientauth_init(%s, %s)",
529 ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
530 ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
531 rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
532 ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
534 * Starting with version 5.0, Mozilla-derived LDAP SDKs require
535 * the cert and key paths to be a directory, not a file.
536 * If the user specified a file and it fails, try the parent dir.
538 if (rc != LDAP_SUCCESS) {
540 if (ldap_conf.tls_certfile != NULL) {
541 char *cp = strrchr(ldap_conf.tls_certfile, '/');
542 if (cp != NULL && strncmp(cp + 1, "cert", 4) == 0) {
547 if (ldap_conf.tls_keyfile != NULL) {
548 char *cp = strrchr(ldap_conf.tls_keyfile, '/');
549 if (cp != NULL && strncmp(cp + 1, "key", 3) == 0) {
555 DPRINTF(("ldapssl_clientauth_init(%s, %s)",
556 ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
557 ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
558 rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
559 ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
562 if (rc != LDAP_SUCCESS) {
563 warningx(_("unable to initialize SSL cert and key db: %s"),
564 ldapssl_err2string(rc));
565 if (ldap_conf.tls_certfile == NULL)
566 warningx(_("you must set TLS_CERT in %s to use SSL"),
571 DPRINTF(("ldapssl_init(%s, %d, %d)", host, port, defsecure), 2);
572 if ((ld = ldapssl_init(host, port, defsecure)) != NULL)
577 #ifdef HAVE_LDAP_CREATE
578 DPRINTF(("ldap_create()"), 2);
579 if ((rc = ldap_create(&ld)) != LDAP_SUCCESS)
581 DPRINTF(("ldap_set_option(LDAP_OPT_HOST_NAME, %s)", host), 2);
582 rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, host);
584 DPRINTF(("ldap_init(%s, %d)", host, port), 2);
585 if ((ld = ldap_init(host, port)) != NULL)
592 debug_return_int(rc);
596 * Walk through search results and return true if we have a matching
597 * netgroup, else false.
600 sudo_ldap_check_user_netgroup(LDAP *ld, LDAPMessage *entry, char *user)
602 struct berval **bv, **p;
605 debug_decl(sudo_ldap_check_user_netgroup, SUDO_DEBUG_LDAP)
608 debug_return_bool(ret);
610 /* get the values from the entry */
611 bv = ldap_get_values_len(ld, entry, "sudoUser");
613 debug_return_bool(ret);
615 /* walk through values */
616 for (p = bv; *p != NULL && !ret; p++) {
619 if (netgr_matches(val, NULL, NULL, user))
621 DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val,
622 ret ? "MATCH!" : "not"), 2 + ((ret) ? 0 : 1));
625 ldap_value_free_len(bv); /* cleanup */
627 debug_return_bool(ret);
631 * Walk through search results and return true if we have a
632 * host match, else false.
635 sudo_ldap_check_host(LDAP *ld, LDAPMessage *entry)
637 struct berval **bv, **p;
640 debug_decl(sudo_ldap_check_host, SUDO_DEBUG_LDAP)
643 debug_return_bool(ret);
645 /* get the values from the entry */
646 bv = ldap_get_values_len(ld, entry, "sudoHost");
648 debug_return_bool(ret);
650 /* walk through values */
651 for (p = bv; *p != NULL && !ret; p++) {
653 /* match any or address or netgroup or hostname */
654 if (!strcmp(val, "ALL") || addr_matches(val) ||
655 netgr_matches(val, user_host, user_shost, NULL) ||
656 hostname_matches(user_shost, user_host, val))
658 DPRINTF(("ldap sudoHost '%s' ... %s", val,
659 ret ? "MATCH!" : "not"), 2);
662 ldap_value_free_len(bv); /* cleanup */
664 debug_return_bool(ret);
668 sudo_ldap_check_runas_user(LDAP *ld, LDAPMessage *entry)
670 struct berval **bv, **p;
673 debug_decl(sudo_ldap_check_runas_user, SUDO_DEBUG_LDAP)
676 debug_return_bool(UNSPEC);
678 /* get the runas user from the entry */
679 bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
681 bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */
686 * if runas is not specified on the command line, the only information
687 * as to which user to run as is in the runas_default option. We should
688 * check to see if we have the local option present. Unfortunately we
689 * don't parse these options until after this routine says yes or no.
690 * The query has already returned, so we could peek at the attribute
691 * values here though.
693 * For now just require users to always use -u option unless its set
694 * in the global defaults. This behaviour is no different than the global
697 * Sigh - maybe add this feature later
701 * If there are no runas entries, match runas_default against
702 * what the user specified on the command line.
705 debug_return_bool(!strcasecmp(runas_pw->pw_name, def_runas_default));
707 /* walk through values returned, looking for a match */
708 for (p = bv; *p != NULL && !ret; p++) {
712 if (netgr_matches(val, NULL, NULL, runas_pw->pw_name))
716 if (usergr_matches(val, runas_pw->pw_name, runas_pw))
720 if (strcmp(val, "ALL") == 0) {
726 if (strcasecmp(val, runas_pw->pw_name) == 0)
730 DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val,
731 ret ? "MATCH!" : "not"), 2);
734 ldap_value_free_len(bv); /* cleanup */
736 debug_return_bool(ret);
740 sudo_ldap_check_runas_group(LDAP *ld, LDAPMessage *entry)
742 struct berval **bv, **p;
745 debug_decl(sudo_ldap_check_runas_group, SUDO_DEBUG_LDAP)
747 /* runas_gr is only set if the user specified the -g flag */
749 debug_return_bool(UNSPEC);
751 /* get the values from the entry */
752 bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
754 debug_return_bool(ret);
756 /* walk through values returned, looking for a match */
757 for (p = bv; *p != NULL && !ret; p++) {
759 if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
761 DPRINTF(("ldap sudoRunAsGroup '%s' ... %s", val,
762 ret ? "MATCH!" : "not"), 2);
765 ldap_value_free_len(bv); /* cleanup */
767 debug_return_bool(ret);
771 * Walk through search results and return true if we have a runas match,
772 * else false. RunAs info is optional.
775 sudo_ldap_check_runas(LDAP *ld, LDAPMessage *entry)
778 debug_decl(sudo_ldap_check_runas, SUDO_DEBUG_LDAP)
781 debug_return_bool(false);
783 ret = sudo_ldap_check_runas_user(ld, entry) != false &&
784 sudo_ldap_check_runas_group(ld, entry) != false;
786 debug_return_bool(ret);
790 * Walk through search results and return true if we have a command match,
791 * false if disallowed and UNSPEC if not matched.
794 sudo_ldap_check_command(LDAP *ld, LDAPMessage *entry, int *setenv_implied)
796 struct berval **bv, **p;
797 char *allowed_cmnd, *allowed_args, *val;
800 debug_decl(sudo_ldap_check_command, SUDO_DEBUG_LDAP)
803 debug_return_bool(ret);
805 bv = ldap_get_values_len(ld, entry, "sudoCommand");
807 debug_return_bool(ret);
809 for (p = bv; *p != NULL && ret != false; p++) {
811 /* Match against ALL ? */
812 if (!strcmp(val, "ALL")) {
814 if (setenv_implied != NULL)
815 *setenv_implied = true;
816 DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2);
820 /* check for !command */
823 allowed_cmnd = estrdup(1 + val); /* !command */
826 allowed_cmnd = estrdup(val); /* command */
829 /* split optional args away from command */
830 allowed_args = strchr(allowed_cmnd, ' ');
832 *allowed_args++ = '\0';
834 /* check the command like normal */
835 if (command_matches(allowed_cmnd, allowed_args)) {
837 * If allowed (no bang) set ret but keep on checking.
838 * If disallowed (bang), exit loop.
840 ret = foundbang ? false : true;
842 DPRINTF(("ldap sudoCommand '%s' ... %s", val,
843 ret == true ? "MATCH!" : "not"), 2);
845 efree(allowed_cmnd); /* cleanup */
848 ldap_value_free_len(bv); /* more cleanup */
850 debug_return_bool(ret);
854 * Search for boolean "option" in sudoOption.
855 * Returns true if found and allowed, false if negated, else UNSPEC.
858 sudo_ldap_check_bool(LDAP *ld, LDAPMessage *entry, char *option)
860 struct berval **bv, **p;
863 debug_decl(sudo_ldap_check_bool, SUDO_DEBUG_LDAP)
866 debug_return_bool(ret);
868 bv = ldap_get_values_len(ld, entry, "sudoOption");
870 debug_return_bool(ret);
872 /* walk through options */
873 for (p = bv; *p != NULL; p++) {
875 DPRINTF(("ldap sudoOption: '%s'", var), 2);
877 if ((ch = *var) == '!')
879 if (strcmp(var, option) == 0)
883 ldap_value_free_len(bv);
885 debug_return_bool(ret);
889 * Read sudoOption and modify the defaults as we go. This is used once
890 * from the cn=defaults entry and also once when a final sudoRole is matched.
893 sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry)
895 struct berval **bv, **p;
897 debug_decl(sudo_ldap_parse_options, SUDO_DEBUG_LDAP)
902 bv = ldap_get_values_len(ld, entry, "sudoOption");
906 /* walk through options */
907 for (p = bv; *p != NULL; p++) {
908 var = estrdup((*p)->bv_val);
909 DPRINTF(("ldap sudoOption: '%s'", var), 2);
911 /* check for equals sign past first char */
912 val = strchr(var, '=');
914 *val++ = '\0'; /* split on = and truncate var */
915 op = *(val - 2); /* peek for += or -= cases */
916 if (op == '+' || op == '-') {
917 *(val - 2) = '\0'; /* found, remove extra char */
918 /* case var+=val or var-=val */
919 set_default(var, val, (int) op);
922 set_default(var, val, true);
924 } else if (*var == '!') {
925 /* case !var Boolean False */
926 set_default(var + 1, NULL, false);
928 /* case var Boolean True */
929 set_default(var, NULL, true);
934 ldap_value_free_len(bv);
940 * Build an LDAP timefilter.
942 * Stores a filter in the buffer that makes sure only entries
943 * are selected that have a sudoNotBefore in the past and a
944 * sudoNotAfter in the future, i.e. a filter of the following
945 * structure (spaced out a little more for better readability:
949 * (!(sudoNotAfter=*))
950 * (sudoNotAfter>__now__)
953 * (!(sudoNotBefore=*))
954 * (sudoNotBefore<__now__)
958 * If either the sudoNotAfter or sudoNotBefore attributes are missing,
959 * no time restriction shall be imposed.
962 sudo_ldap_timefilter(char *buffer, size_t buffersize)
968 debug_decl(sudo_ldap_timefilter, SUDO_DEBUG_LDAP)
970 /* Make sure we have a formatted timestamp for __now__. */
972 if ((tp = gmtime(&now)) == NULL) {
973 warning(_("unable to get GMT time"));
977 /* Format the timestamp according to the RFC. */
978 if (strftime(timebuffer, sizeof(timebuffer), "%Y%m%d%H%M%SZ", tp) == 0) {
979 warning(_("unable to format timestamp"));
984 bytes = snprintf(buffer, buffersize, "(&(|(!(sudoNotAfter=*))(sudoNotAfter>=%s))(|(!(sudoNotBefore=*))(sudoNotBefore<=%s)))",
985 timebuffer, timebuffer);
986 if (bytes < 0 || bytes >= buffersize) {
987 warning(_("unable to build time filter"));
992 debug_return_int(bytes);
996 * Builds up a filter to search for default settings
999 sudo_ldap_build_default_filter(void)
1002 debug_decl(sudo_ldap_build_default_filter, SUDO_DEBUG_LDAP)
1004 if (ldap_conf.search_filter)
1005 easprintf(&filt, "(&%s(cn=defaults))", ldap_conf.search_filter);
1007 filt = estrdup("cn=defaults");
1008 debug_return_str(filt);
1012 * Determine length of query value after escaping characters
1016 sudo_ldap_value_len(const char *value)
1021 for (s = value; *s != '\0'; s++) {
1031 len += (size_t)(s - value);
1036 * Like strlcat() but escapes characters as per RFC 4515.
1039 sudo_ldap_value_cat(char *dst, const char *src, size_t size)
1042 const char *s = src;
1046 /* Find the end of dst and adjust bytes left but don't go past end */
1047 while (n-- != 0 && *d != '\0')
1053 return dlen + strlen(s);
1054 while (*s != '\0') {
1101 return dlen + (s - src); /* count does not include NUL */
1105 * Builds up a filter to check against LDAP.
1108 sudo_ldap_build_pass1(struct passwd *pw)
1111 char *buf, timebuffer[TIMEFILTER_LENGTH], gidbuf[MAX_UID_T_LEN];
1112 struct group_list *grlist;
1115 debug_decl(sudo_ldap_build_pass1, SUDO_DEBUG_LDAP)
1117 /* Start with LDAP search filter length + 3 */
1118 if (ldap_conf.search_filter)
1119 sz += strlen(ldap_conf.search_filter) + 3;
1121 /* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
1122 sz += 29 + sudo_ldap_value_len(pw->pw_name);
1124 /* Add space for primary and supplementary groups and gids */
1125 if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
1126 sz += 12 + sudo_ldap_value_len(grp->gr_name);
1128 sz += 13 + MAX_UID_T_LEN;
1129 if ((grlist = get_group_list(pw)) != NULL) {
1130 for (i = 0; i < grlist->ngroups; i++) {
1131 if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0)
1133 sz += 12 + sudo_ldap_value_len(grlist->groups[i]);
1135 for (i = 0; i < grlist->ngids; i++) {
1136 if (pw->pw_gid == grlist->gids[i])
1138 sz += 13 + MAX_UID_T_LEN;
1142 /* If timed, add space for time limits. */
1143 if (ldap_conf.timed)
1144 sz += TIMEFILTER_LENGTH;
1149 * If timed or using a search filter, start a global AND clause to
1150 * contain the search filter, search criteria, and time restriction.
1152 if (ldap_conf.timed || ldap_conf.search_filter)
1153 (void) strlcpy(buf, "(&", sz);
1155 if (ldap_conf.search_filter)
1156 (void) strlcat(buf, ldap_conf.search_filter, sz);
1158 /* Global OR + sudoUser=user_name filter */
1159 (void) strlcat(buf, "(|(sudoUser=", sz);
1160 (void) sudo_ldap_value_cat(buf, pw->pw_name, sz);
1161 (void) strlcat(buf, ")", sz);
1163 /* Append primary group and gid */
1165 (void) strlcat(buf, "(sudoUser=%", sz);
1166 (void) sudo_ldap_value_cat(buf, grp->gr_name, sz);
1167 (void) strlcat(buf, ")", sz);
1169 (void) snprintf(gidbuf, sizeof(gidbuf), "%u", (unsigned int)pw->pw_gid);
1170 (void) strlcat(buf, "(sudoUser=%#", sz);
1171 (void) strlcat(buf, gidbuf, sz);
1172 (void) strlcat(buf, ")", sz);
1174 /* Append supplementary groups and gids */
1175 if (grlist != NULL) {
1176 for (i = 0; i < grlist->ngroups; i++) {
1177 if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0)
1179 (void) strlcat(buf, "(sudoUser=%", sz);
1180 (void) sudo_ldap_value_cat(buf, grlist->groups[i], sz);
1181 (void) strlcat(buf, ")", sz);
1183 for (i = 0; i < grlist->ngids; i++) {
1184 if (pw->pw_gid == grlist->gids[i])
1186 (void) snprintf(gidbuf, sizeof(gidbuf), "%u",
1187 (unsigned int)grlist->gids[i]);
1188 (void) strlcat(buf, "(sudoUser=%#", sz);
1189 (void) strlcat(buf, gidbuf, sz);
1190 (void) strlcat(buf, ")", sz);
1194 /* Done with groups. */
1196 grlist_delref(grlist);
1200 /* Add ALL to list and end the global OR */
1201 if (strlcat(buf, "(sudoUser=ALL)", sz) >= sz)
1202 errorx(1, _("sudo_ldap_build_pass1 allocation mismatch"));
1204 /* Add the time restriction, or simply end the global OR. */
1205 if (ldap_conf.timed) {
1206 strlcat(buf, ")", sz); /* closes the global OR */
1207 sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
1208 strlcat(buf, timebuffer, sz);
1209 } else if (ldap_conf.search_filter) {
1210 strlcat(buf, ")", sz); /* closes the global OR */
1212 strlcat(buf, ")", sz); /* closes the global OR or the global AND */
1214 debug_return_str(buf);
1218 * Builds up a filter to check against netgroup entries in LDAP.
1221 sudo_ldap_build_pass2(void)
1223 char *filt, timebuffer[TIMEFILTER_LENGTH];
1224 debug_decl(sudo_ldap_build_pass2, SUDO_DEBUG_LDAP)
1226 if (ldap_conf.timed)
1227 sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
1230 * Match all sudoUsers beginning with a '+'.
1231 * If a search filter or time restriction is specified,
1232 * those get ANDed in to the expression.
1234 easprintf(&filt, "%s%s(sudoUser=+*)%s%s",
1235 (ldap_conf.timed || ldap_conf.search_filter) ? "(&" : "",
1236 ldap_conf.search_filter ? ldap_conf.search_filter : "",
1237 ldap_conf.timed ? timebuffer : "",
1238 (ldap_conf.timed || ldap_conf.search_filter) ? ")" : "");
1240 debug_return_str(filt);
1244 sudo_ldap_read_secret(const char *path)
1247 char buf[LINE_MAX], *cp;
1248 debug_decl(sudo_ldap_read_secret, SUDO_DEBUG_LDAP)
1250 if ((fp = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
1251 if (fgets(buf, sizeof(buf), fp) != NULL) {
1252 if ((cp = strchr(buf, '\n')) != NULL)
1254 /* copy to bindpw and binddn */
1255 efree(ldap_conf.bindpw);
1256 ldap_conf.bindpw = estrdup(buf);
1257 efree(ldap_conf.binddn);
1258 ldap_conf.binddn = ldap_conf.rootbinddn;
1259 ldap_conf.rootbinddn = NULL;
1267 * Look up keyword in config tables.
1268 * Returns true if found, else false.
1271 sudo_ldap_parse_keyword(const char *keyword, const char *value,
1272 struct ldap_config_table *table)
1274 struct ldap_config_table *cur;
1275 debug_decl(sudo_ldap_parse_keyword, SUDO_DEBUG_LDAP)
1277 /* Look up keyword in config tables */
1278 for (cur = table; cur->conf_str != NULL; cur++) {
1279 if (strcasecmp(keyword, cur->conf_str) == 0) {
1280 switch (cur->type) {
1281 case CONF_DEREF_VAL:
1282 if (strcasecmp(value, "searching") == 0)
1283 *(int *)(cur->valp) = LDAP_DEREF_SEARCHING;
1284 else if (strcasecmp(value, "finding") == 0)
1285 *(int *)(cur->valp) = LDAP_DEREF_FINDING;
1286 else if (strcasecmp(value, "always") == 0)
1287 *(int *)(cur->valp) = LDAP_DEREF_ALWAYS;
1289 *(int *)(cur->valp) = LDAP_DEREF_NEVER;
1292 *(int *)(cur->valp) = atobool(value) == true;
1295 *(int *)(cur->valp) = atoi(value);
1298 efree(*(char **)(cur->valp));
1299 *(char **)(cur->valp) = estrdup(value);
1303 struct ldap_config_list_str **p;
1304 size_t len = strlen(value);
1307 p = (struct ldap_config_list_str **)cur->valp;
1310 *p = emalloc(sizeof(struct ldap_config_list_str) + len);
1311 memcpy((*p)->val, value, len + 1);
1317 debug_return_bool(true);
1320 debug_return_bool(false);
1324 sudo_ldap_read_config(void)
1327 char *cp, *keyword, *value;
1328 debug_decl(sudo_ldap_read_config, SUDO_DEBUG_LDAP)
1331 ldap_conf.version = 3;
1332 ldap_conf.port = -1;
1333 ldap_conf.tls_checkpeer = -1;
1334 ldap_conf.timelimit = -1;
1335 ldap_conf.timeout = -1;
1336 ldap_conf.bind_timelimit = -1;
1337 ldap_conf.use_sasl = -1;
1338 ldap_conf.rootuse_sasl = -1;
1339 ldap_conf.deref = -1;
1341 if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL)
1342 debug_return_bool(false);
1344 while ((cp = sudo_parseln(fp)) != NULL) {
1346 continue; /* skip empty line */
1348 /* split into keyword and value */
1350 while (*cp && !isblank((unsigned char) *cp))
1353 *cp++ = '\0'; /* terminate keyword */
1355 /* skip whitespace before value */
1356 while (isblank((unsigned char) *cp))
1360 /* Look up keyword in config tables */
1361 if (!sudo_ldap_parse_keyword(keyword, value, ldap_conf_global))
1362 sudo_ldap_parse_keyword(keyword, value, ldap_conf_conn);
1366 if (!ldap_conf.host)
1367 ldap_conf.host = estrdup("localhost");
1369 if (ldap_conf.debug > 1) {
1370 sudo_printf(SUDO_CONV_ERROR_MSG, "LDAP Config Summary\n");
1371 sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n");
1372 if (ldap_conf.uri) {
1373 struct ldap_config_list_str *uri = ldap_conf.uri;
1376 sudo_printf(SUDO_CONV_ERROR_MSG, "uri %s\n",
1378 } while ((uri = uri->next) != NULL);
1380 sudo_printf(SUDO_CONV_ERROR_MSG, "host %s\n",
1381 ldap_conf.host ? ldap_conf.host : "(NONE)");
1382 sudo_printf(SUDO_CONV_ERROR_MSG, "port %d\n",
1385 sudo_printf(SUDO_CONV_ERROR_MSG, "ldap_version %d\n",
1388 if (ldap_conf.base) {
1389 struct ldap_config_list_str *base = ldap_conf.base;
1391 sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base %s\n",
1393 } while ((base = base->next) != NULL);
1395 sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base %s\n",
1396 "(NONE: LDAP disabled)");
1398 if (ldap_conf.search_filter) {
1399 sudo_printf(SUDO_CONV_ERROR_MSG, "search_filter %s\n",
1400 ldap_conf.search_filter);
1402 sudo_printf(SUDO_CONV_ERROR_MSG, "binddn %s\n",
1403 ldap_conf.binddn ? ldap_conf.binddn : "(anonymous)");
1404 sudo_printf(SUDO_CONV_ERROR_MSG, "bindpw %s\n",
1405 ldap_conf.bindpw ? ldap_conf.bindpw : "(anonymous)");
1406 if (ldap_conf.bind_timelimit > 0) {
1407 sudo_printf(SUDO_CONV_ERROR_MSG, "bind_timelimit %d\n",
1408 ldap_conf.bind_timelimit);
1410 if (ldap_conf.timelimit > 0) {
1411 sudo_printf(SUDO_CONV_ERROR_MSG, "timelimit %d\n",
1412 ldap_conf.timelimit);
1414 if (ldap_conf.deref != -1) {
1415 sudo_printf(SUDO_CONV_ERROR_MSG, "deref %d\n",
1418 sudo_printf(SUDO_CONV_ERROR_MSG, "ssl %s\n",
1419 ldap_conf.ssl ? ldap_conf.ssl : "(no)");
1420 if (ldap_conf.tls_checkpeer != -1) {
1421 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_checkpeer %s\n",
1422 ldap_conf.tls_checkpeer ? "(yes)" : "(no)");
1424 if (ldap_conf.tls_cacertfile != NULL) {
1425 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cacertfile %s\n",
1426 ldap_conf.tls_cacertfile);
1428 if (ldap_conf.tls_cacertdir != NULL) {
1429 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cacertdir %s\n",
1430 ldap_conf.tls_cacertdir);
1432 if (ldap_conf.tls_random_file != NULL) {
1433 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_random_file %s\n",
1434 ldap_conf.tls_random_file);
1436 if (ldap_conf.tls_cipher_suite != NULL) {
1437 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cipher_suite %s\n",
1438 ldap_conf.tls_cipher_suite);
1440 if (ldap_conf.tls_certfile != NULL) {
1441 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_certfile %s\n",
1442 ldap_conf.tls_certfile);
1444 if (ldap_conf.tls_keyfile != NULL) {
1445 sudo_printf(SUDO_CONV_ERROR_MSG, "tls_keyfile %s\n",
1446 ldap_conf.tls_keyfile);
1448 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1449 if (ldap_conf.use_sasl != -1) {
1450 sudo_printf(SUDO_CONV_ERROR_MSG, "use_sasl %s\n",
1451 ldap_conf.use_sasl ? "yes" : "no");
1452 sudo_printf(SUDO_CONV_ERROR_MSG, "sasl_auth_id %s\n",
1453 ldap_conf.sasl_auth_id ? ldap_conf.sasl_auth_id : "(NONE)");
1454 sudo_printf(SUDO_CONV_ERROR_MSG, "rootuse_sasl %d\n",
1455 ldap_conf.rootuse_sasl);
1456 sudo_printf(SUDO_CONV_ERROR_MSG, "rootsasl_auth_id %s\n",
1457 ldap_conf.rootsasl_auth_id ? ldap_conf.rootsasl_auth_id : "(NONE)");
1458 sudo_printf(SUDO_CONV_ERROR_MSG, "sasl_secprops %s\n",
1459 ldap_conf.sasl_secprops ? ldap_conf.sasl_secprops : "(NONE)");
1460 sudo_printf(SUDO_CONV_ERROR_MSG, "krb5_ccname %s\n",
1461 ldap_conf.krb5_ccname ? ldap_conf.krb5_ccname : "(NONE)");
1464 sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n");
1466 if (!ldap_conf.base)
1467 debug_return_bool(false); /* if no base is defined, ignore LDAP */
1469 if (ldap_conf.bind_timelimit > 0)
1470 ldap_conf.bind_timelimit *= 1000; /* convert to ms */
1473 * Interpret SSL option
1475 if (ldap_conf.ssl != NULL) {
1476 if (strcasecmp(ldap_conf.ssl, "start_tls") == 0)
1477 ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS;
1478 else if (atobool(ldap_conf.ssl) == true)
1479 ldap_conf.ssl_mode = SUDO_LDAP_SSL;
1482 #if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
1483 if (ldap_conf.tls_checkpeer != -1) {
1484 ldapssl_set_strength(NULL,
1485 ldap_conf.tls_checkpeer ? LDAPSSL_AUTH_CERT : LDAPSSL_AUTH_WEAK);
1489 #ifndef HAVE_LDAP_INITIALIZE
1490 /* Convert uri list to host list if no ldap_initialize(). */
1491 if (ldap_conf.uri) {
1492 struct ldap_config_list_str *uri = ldap_conf.uri;
1493 if (sudo_ldap_parse_uri(uri) != 0)
1494 debug_return_bool(false);
1496 ldap_conf.uri = uri->next;
1498 } while ((uri = ldap_conf.uri));
1499 ldap_conf.port = LDAP_PORT;
1503 if (!ldap_conf.uri) {
1504 /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
1505 if (ldap_conf.port < 0)
1507 ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
1509 #ifdef HAVE_LDAP_CREATE
1511 * Cannot specify port directly to ldap_create(), each host must
1512 * include :port to override the default.
1514 if (ldap_conf.port != LDAP_PORT)
1515 sudo_ldap_conf_add_ports();
1519 /* If search filter is not parenthesized, make it so. */
1520 if (ldap_conf.search_filter && ldap_conf.search_filter[0] != '(') {
1521 size_t len = strlen(ldap_conf.search_filter);
1522 cp = ldap_conf.search_filter;
1523 ldap_conf.search_filter = emalloc(len + 3);
1524 ldap_conf.search_filter[0] = '(';
1525 memcpy(ldap_conf.search_filter + 1, cp, len);
1526 ldap_conf.search_filter[len + 1] = ')';
1527 ldap_conf.search_filter[len + 2] = '\0';
1531 /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
1532 if (ldap_conf.rootbinddn)
1533 sudo_ldap_read_secret(_PATH_LDAP_SECRET);
1535 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1537 * Make sure we can open the file specified by krb5_ccname.
1539 if (ldap_conf.krb5_ccname != NULL) {
1540 if (strncasecmp(ldap_conf.krb5_ccname, "FILE:", 5) == 0 ||
1541 strncasecmp(ldap_conf.krb5_ccname, "WRFILE:", 7) == 0) {
1542 value = ldap_conf.krb5_ccname +
1543 (ldap_conf.krb5_ccname[4] == ':' ? 5 : 7);
1544 if ((fp = fopen(value, "r")) != NULL) {
1545 DPRINTF(("using krb5 credential cache: %s", value), 1);
1548 /* Can't open it, just ignore the entry. */
1549 DPRINTF(("unable to open krb5 credential cache: %s", value), 1);
1550 efree(ldap_conf.krb5_ccname);
1551 ldap_conf.krb5_ccname = NULL;
1556 debug_return_bool(true);
1560 * Extract the dn from an entry and return the first rdn from it.
1563 sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry)
1565 #ifdef HAVE_LDAP_STR2DN
1566 char *dn, *rdn = NULL;
1568 debug_decl(sudo_ldap_get_first_rdn, SUDO_DEBUG_LDAP)
1570 if ((dn = ldap_get_dn(ld, entry)) == NULL)
1571 debug_return_str(NULL);
1572 if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) {
1573 ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN);
1577 debug_return_str(rdn);
1580 debug_decl(sudo_ldap_get_first_rdn, SUDO_DEBUG_LDAP)
1582 if ((dn = ldap_get_dn(ld, entry)) == NULL)
1584 edn = ldap_explode_dn(dn, 1);
1586 debug_return_str(edn ? edn[0] : NULL);
1591 * Fetch and display the global Options.
1594 sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
1597 struct berval **bv, **p;
1598 struct timeval tv, *tvp = NULL;
1599 struct ldap_config_list_str *base;
1600 struct sudo_ldap_handle *handle = nss->handle;
1602 LDAPMessage *entry, *result;
1603 char *prefix, *filt;
1605 debug_decl(sudo_ldap_display_defaults, SUDO_DEBUG_LDAP)
1607 if (handle == NULL || handle->ld == NULL)
1611 filt = sudo_ldap_build_default_filter();
1612 for (base = ldap_conf.base; base != NULL; base = base->next) {
1613 if (ldap_conf.timeout > 0) {
1614 tv.tv_sec = ldap_conf.timeout;
1619 rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
1620 filt, NULL, 0, NULL, NULL, tvp, 0, &result);
1621 if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
1622 bv = ldap_get_values_len(ld, entry, "sudoOption");
1624 if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
1628 for (p = bv; *p != NULL; p++) {
1629 lbuf_append(lbuf, "%s%s", prefix, (*p)->bv_val);
1633 ldap_value_free_len(bv);
1637 ldap_msgfree(result);
1641 debug_return_int(count);
1648 sudo_ldap_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
1651 debug_decl(sudo_ldap_display_bound_defaults, SUDO_DEBUG_LDAP)
1652 debug_return_int(0);
1656 * Print a record in the short form, ala file sudoers.
1659 sudo_ldap_display_entry_short(LDAP *ld, LDAPMessage *entry, struct lbuf *lbuf)
1661 struct berval **bv, **p;
1663 debug_decl(sudo_ldap_display_entry_short, SUDO_DEBUG_LDAP)
1665 lbuf_append(lbuf, " (");
1667 /* get the RunAsUser Values from the entry */
1668 bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
1670 bv = ldap_get_values_len(ld, entry, "sudoRunAs");
1672 for (p = bv; *p != NULL; p++) {
1673 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1675 ldap_value_free_len(bv);
1677 lbuf_append(lbuf, "%s", def_runas_default);
1679 /* get the RunAsGroup Values from the entry */
1680 bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
1682 lbuf_append(lbuf, " : ");
1683 for (p = bv; *p != NULL; p++) {
1684 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1686 ldap_value_free_len(bv);
1688 lbuf_append(lbuf, ") ");
1690 /* get the Option Values from the entry */
1691 bv = ldap_get_values_len(ld, entry, "sudoOption");
1693 for (p = bv; *p != NULL; p++) {
1694 char *cp = (*p)->bv_val;
1697 if (strcmp(cp, "authenticate") == 0)
1698 lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
1699 "NOPASSWD: " : "PASSWD: ");
1700 else if (strcmp(cp, "noexec") == 0)
1701 lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
1702 "EXEC: " : "NOEXEC: ");
1703 else if (strcmp(cp, "setenv") == 0)
1704 lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
1705 "NOSETENV: " : "SETENV: ");
1707 ldap_value_free_len(bv);
1710 /* get the Command Values from the entry */
1711 bv = ldap_get_values_len(ld, entry, "sudoCommand");
1713 for (p = bv; *p != NULL; p++) {
1714 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1717 ldap_value_free_len(bv);
1719 lbuf_append(lbuf, "\n");
1721 debug_return_int(count);
1725 * Print a record in the long form.
1728 sudo_ldap_display_entry_long(LDAP *ld, LDAPMessage *entry, struct lbuf *lbuf)
1730 struct berval **bv, **p;
1733 debug_decl(sudo_ldap_display_entry_long, SUDO_DEBUG_LDAP)
1735 /* extract the dn, only show the first rdn */
1736 rdn = sudo_ldap_get_first_rdn(ld, entry);
1738 lbuf_append(lbuf, _("\nLDAP Role: %s\n"), rdn);
1740 lbuf_append(lbuf, _("\nLDAP Role: UNKNOWN\n"));
1744 /* get the RunAsUser Values from the entry */
1745 lbuf_append(lbuf, " RunAsUsers: ");
1746 bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
1748 bv = ldap_get_values_len(ld, entry, "sudoRunAs");
1750 for (p = bv; *p != NULL; p++) {
1751 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1753 ldap_value_free_len(bv);
1755 lbuf_append(lbuf, "%s", def_runas_default);
1756 lbuf_append(lbuf, "\n");
1758 /* get the RunAsGroup Values from the entry */
1759 bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
1761 lbuf_append(lbuf, " RunAsGroups: ");
1762 for (p = bv; *p != NULL; p++) {
1763 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1765 ldap_value_free_len(bv);
1766 lbuf_append(lbuf, "\n");
1769 /* get the Option Values from the entry */
1770 bv = ldap_get_values_len(ld, entry, "sudoOption");
1772 lbuf_append(lbuf, " Options: ");
1773 for (p = bv; *p != NULL; p++) {
1774 lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1776 ldap_value_free_len(bv);
1777 lbuf_append(lbuf, "\n");
1781 * Display order attribute if present. This attribute is single valued,
1782 * so there is no need for a loop.
1784 bv = ldap_get_values_len(ld, entry, "sudoOrder");
1787 lbuf_append(lbuf, _(" Order: %s\n"), (*bv)->bv_val);
1789 ldap_value_free_len(bv);
1792 /* Get the command values from the entry. */
1793 bv = ldap_get_values_len(ld, entry, "sudoCommand");
1795 lbuf_append(lbuf, _(" Commands:\n"));
1796 for (p = bv; *p != NULL; p++) {
1797 lbuf_append(lbuf, "\t%s\n", (*p)->bv_val);
1800 ldap_value_free_len(bv);
1803 debug_return_int(count);
1807 * Like sudo_ldap_lookup(), except we just print entries.
1810 sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
1813 struct sudo_ldap_handle *handle = nss->handle;
1815 struct ldap_result *lres;
1818 debug_decl(sudo_ldap_display_privs, SUDO_DEBUG_LDAP)
1820 if (handle == NULL || handle->ld == NULL)
1824 DPRINTF(("ldap search for command list"), 1);
1825 lres = sudo_ldap_result_get(nss, pw);
1827 /* Display all matching entries. */
1828 for (i = 0; i < lres->nentries; i++) {
1829 entry = lres->entries[i].entry;
1831 count += sudo_ldap_display_entry_long(ld, entry, lbuf);
1833 count += sudo_ldap_display_entry_short(ld, entry, lbuf);
1837 debug_return_int(count);
1841 sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
1843 struct sudo_ldap_handle *handle = nss->handle;
1845 struct ldap_result *lres;
1849 debug_decl(sudo_ldap_display_cmnd, SUDO_DEBUG_LDAP)
1851 if (handle == NULL || handle->ld == NULL)
1856 * The sudo_ldap_result_get() function returns all nodes that match
1857 * the user and the host.
1859 DPRINTF(("ldap search for command list"), 1);
1860 lres = sudo_ldap_result_get(nss, pw);
1861 for (i = 0; i < lres->nentries; i++) {
1862 entry = lres->entries[i].entry;
1863 if (sudo_ldap_check_command(ld, entry, NULL) &&
1864 sudo_ldap_check_runas(ld, entry)) {
1872 printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
1873 user_args ? " " : "", user_args ? user_args : "");
1874 debug_return_bool(!found);
1877 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1879 sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags, void *_auth_id,
1882 char *auth_id = (char *)_auth_id;
1883 sasl_interact_t *interact = (sasl_interact_t *)_interact;
1884 debug_decl(sudo_ldap_sasl_interact, SUDO_DEBUG_LDAP)
1886 for (; interact->id != SASL_CB_LIST_END; interact++) {
1887 if (interact->id != SASL_CB_USER)
1888 debug_return_int(LDAP_PARAM_ERROR);
1890 if (auth_id != NULL)
1891 interact->result = auth_id;
1892 else if (interact->defresult != NULL)
1893 interact->result = interact->defresult;
1895 interact->result = "";
1897 interact->len = strlen(interact->result);
1898 #if SASL_VERSION_MAJOR < 2
1899 interact->result = estrdup(interact->result);
1900 #endif /* SASL_VERSION_MAJOR < 2 */
1902 debug_return_int(LDAP_SUCCESS);
1904 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
1908 * Set LDAP options from the specified options table
1911 sudo_ldap_set_options_table(LDAP *ld, struct ldap_config_table *table)
1913 struct ldap_config_table *cur;
1916 debug_decl(sudo_ldap_set_options_table, SUDO_DEBUG_LDAP)
1918 for (cur = table; cur->conf_str != NULL; cur++) {
1919 if (cur->opt_val == -1)
1922 switch (cur->type) {
1925 ival = *(int *)(cur->valp);
1927 rc = ldap_set_option(ld, cur->opt_val, &ival);
1928 if (rc != LDAP_OPT_SUCCESS) {
1929 warningx("ldap_set_option: %s -> %d: %s",
1930 cur->conf_str, ival, ldap_err2string(rc));
1931 debug_return_int(-1);
1933 DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
1937 sval = *(char **)(cur->valp);
1939 rc = ldap_set_option(ld, cur->opt_val, sval);
1940 if (rc != LDAP_OPT_SUCCESS) {
1941 warningx("ldap_set_option: %s -> %s: %s",
1942 cur->conf_str, sval, ldap_err2string(rc));
1943 debug_return_int(-1);
1945 DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
1950 debug_return_int(0);
1954 * Set LDAP options based on the global config table.
1957 sudo_ldap_set_options_global(void)
1960 debug_decl(sudo_ldap_set_options_global, SUDO_DEBUG_LDAP)
1962 /* Set ber options */
1963 #ifdef LBER_OPT_DEBUG_LEVEL
1964 if (ldap_conf.ldap_debug)
1965 ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug);
1968 /* Parse global LDAP options table. */
1969 rc = sudo_ldap_set_options_table(NULL, ldap_conf_global);
1971 debug_return_int(-1);
1972 debug_return_int(0);
1976 * Set LDAP options based on the per-connection config table.
1979 sudo_ldap_set_options_conn(LDAP *ld)
1982 debug_decl(sudo_ldap_set_options_conn, SUDO_DEBUG_LDAP)
1984 /* Parse per-connection LDAP options table. */
1985 rc = sudo_ldap_set_options_table(ld, ldap_conf_conn);
1987 debug_return_int(-1);
1989 #ifdef LDAP_OPT_TIMEOUT
1990 /* Convert timeout to a timeval */
1991 if (ldap_conf.timeout > 0) {
1993 tv.tv_sec = ldap_conf.timeout;
1995 rc = ldap_set_option(ld, LDAP_OPT_TIMEOUT, &tv);
1996 if (rc != LDAP_OPT_SUCCESS) {
1997 warningx("ldap_set_option(TIMEOUT, %ld): %s",
1998 (long)tv.tv_sec, ldap_err2string(rc));
1999 debug_return_int(-1);
2001 DPRINTF(("ldap_set_option(LDAP_OPT_TIMEOUT, %ld)",
2002 (long)tv.tv_sec), 1);
2005 #ifdef LDAP_OPT_NETWORK_TIMEOUT
2006 /* Convert bind_timelimit to a timeval */
2007 if (ldap_conf.bind_timelimit > 0) {
2009 tv.tv_sec = ldap_conf.bind_timelimit / 1000;
2011 rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
2012 if (rc != LDAP_OPT_SUCCESS) {
2013 warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
2014 (long)tv.tv_sec, ldap_err2string(rc));
2015 debug_return_int(-1);
2017 DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)",
2018 (long)tv.tv_sec), 1);
2022 #if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT)
2023 if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
2024 int val = LDAP_OPT_X_TLS_HARD;
2025 rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
2026 if (rc != LDAP_SUCCESS) {
2027 warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
2028 ldap_err2string(rc));
2029 debug_return_int(-1);
2031 DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)"), 1);
2034 debug_return_int(0);
2038 * Create a new sudo_ldap_result structure.
2040 static struct ldap_result *
2041 sudo_ldap_result_alloc(void)
2043 struct ldap_result *result;
2044 debug_decl(sudo_ldap_result_alloc, SUDO_DEBUG_LDAP)
2046 debug_return_ptr(ecalloc(1, sizeof(*result)));
2050 * Free the ldap result structure
2053 sudo_ldap_result_free(struct ldap_result *lres)
2055 struct ldap_search_list *s;
2056 debug_decl(sudo_ldap_result_free, SUDO_DEBUG_LDAP)
2059 if (lres->nentries) {
2060 efree(lres->entries);
2061 lres->entries = NULL;
2063 if (lres->searches) {
2064 while ((s = lres->searches) != NULL) {
2065 ldap_msgfree(s->searchresult);
2066 lres->searches = s->next;
2076 * Add a search result to the ldap_result structure.
2078 static struct ldap_search_list *
2079 sudo_ldap_result_add_search(struct ldap_result *lres, LDAP *ldap,
2080 LDAPMessage *searchresult)
2082 struct ldap_search_list *s, *news;
2083 debug_decl(sudo_ldap_result_add_search, SUDO_DEBUG_LDAP)
2085 news = ecalloc(1, sizeof(struct ldap_search_list));
2087 news->searchresult = searchresult;
2088 /* news->next = NULL; */
2090 /* Add entry to the end of the chain (XXX - tailq instead?). */
2091 if (lres->searches) {
2092 for (s = lres->searches; s->next != NULL; s = s->next)
2096 lres->searches = news;
2098 debug_return_ptr(news);
2102 * Connect to the LDAP server specified by ld
2105 sudo_ldap_bind_s(LDAP *ld)
2108 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
2109 const char *old_ccname = user_ccname;
2110 # ifdef HAVE_GSS_KRB5_CCACHE_NAME
2111 unsigned int status;
2114 debug_decl(sudo_ldap_bind_s, SUDO_DEBUG_LDAP)
2116 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
2117 if (ldap_conf.rootuse_sasl == true ||
2118 (ldap_conf.rootuse_sasl != false && ldap_conf.use_sasl == true)) {
2119 void *auth_id = ldap_conf.rootsasl_auth_id ?
2120 ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id;
2122 if (ldap_conf.krb5_ccname != NULL) {
2123 # ifdef HAVE_GSS_KRB5_CCACHE_NAME
2124 if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname)
2125 != GSS_S_COMPLETE) {
2127 DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
2130 sudo_setenv("KRB5CCNAME", ldap_conf.krb5_ccname, true);
2133 rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI",
2134 NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id);
2135 if (ldap_conf.krb5_ccname != NULL) {
2136 # ifdef HAVE_GSS_KRB5_CCACHE_NAME
2137 if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE)
2138 DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
2140 if (old_ccname != NULL)
2141 sudo_setenv("KRB5CCNAME", old_ccname, true);
2143 sudo_unsetenv("KRB5CCNAME");
2146 if (rc != LDAP_SUCCESS) {
2147 warningx("ldap_sasl_interactive_bind_s(): %s",
2148 ldap_err2string(rc));
2149 debug_return_int(-1);
2151 DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1);
2153 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
2154 #ifdef HAVE_LDAP_SASL_BIND_S
2158 bv.bv_val = ldap_conf.bindpw ? ldap_conf.bindpw : "";
2159 bv.bv_len = strlen(bv.bv_val);
2161 rc = ldap_sasl_bind_s(ld, ldap_conf.binddn, LDAP_SASL_SIMPLE, &bv,
2163 if (rc != LDAP_SUCCESS) {
2164 warningx("ldap_sasl_bind_s(): %s", ldap_err2string(rc));
2165 debug_return_int(-1);
2167 DPRINTF(("ldap_sasl_bind_s() ok"), 1);
2171 rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw);
2172 if (rc != LDAP_SUCCESS) {
2173 warningx("ldap_simple_bind_s(): %s", ldap_err2string(rc));
2174 debug_return_int(-1);
2176 DPRINTF(("ldap_simple_bind_s() ok"), 1);
2179 debug_return_int(0);
2183 * Open a connection to the LDAP server.
2184 * Returns 0 on success and non-zero on failure.
2187 sudo_ldap_open(struct sudo_nss *nss)
2191 bool ldapnoinit = false;
2192 struct sudo_ldap_handle *handle;
2193 debug_decl(sudo_ldap_open, SUDO_DEBUG_LDAP)
2195 if (!sudo_ldap_read_config())
2196 debug_return_int(-1);
2198 /* Prevent reading of user ldaprc and system defaults. */
2199 if (sudo_getenv("LDAPNOINIT") == NULL) {
2201 sudo_setenv("LDAPNOINIT", "1", true);
2204 /* Set global LDAP options */
2205 if (sudo_ldap_set_options_global() < 0)
2206 debug_return_int(-1);
2208 /* Connect to LDAP server */
2209 #ifdef HAVE_LDAP_INITIALIZE
2210 if (ldap_conf.uri != NULL) {
2211 char *buf = sudo_ldap_join_uri(ldap_conf.uri);
2212 DPRINTF(("ldap_initialize(ld, %s)", buf), 2);
2213 rc = ldap_initialize(&ld, buf);
2215 if (rc != LDAP_SUCCESS)
2216 warningx(_("unable to initialize LDAP: %s"), ldap_err2string(rc));
2219 rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);
2220 if (rc != LDAP_SUCCESS)
2221 debug_return_int(-1);
2223 /* Set LDAP per-connection options */
2224 if (sudo_ldap_set_options_conn(ld) < 0)
2225 debug_return_int(-1);
2228 sudo_unsetenv("LDAPNOINIT");
2230 if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
2231 #if defined(HAVE_LDAP_START_TLS_S)
2232 rc = ldap_start_tls_s(ld, NULL, NULL);
2233 if (rc != LDAP_SUCCESS) {
2234 warningx("ldap_start_tls_s(): %s", ldap_err2string(rc));
2235 debug_return_int(-1);
2237 DPRINTF(("ldap_start_tls_s() ok"), 1);
2238 #elif defined(HAVE_LDAP_SSL_CLIENT_INIT) && defined(HAVE_LDAP_START_TLS_S_NP)
2239 if (ldap_ssl_client_init(NULL, NULL, 0, &rc) != LDAP_SUCCESS) {
2240 warningx("ldap_ssl_client_init(): %s", ldap_err2string(rc));
2241 debug_return_int(-1);
2243 rc = ldap_start_tls_s_np(ld, NULL);
2244 if (rc != LDAP_SUCCESS) {
2245 warningx("ldap_start_tls_s_np(): %s", ldap_err2string(rc));
2246 debug_return_int(-1);
2248 DPRINTF(("ldap_start_tls_s_np() ok"), 1);
2250 warningx(_("start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()"));
2251 #endif /* !HAVE_LDAP_START_TLS_S && !HAVE_LDAP_START_TLS_S_NP */
2254 /* Actually connect */
2255 if (sudo_ldap_bind_s(ld) != 0)
2256 debug_return_int(-1);
2258 /* Create a handle container. */
2259 handle = ecalloc(1, sizeof(struct sudo_ldap_handle));
2261 /* handle->result = NULL; */
2262 /* handle->username = NULL; */
2263 /* handle->grlist = NULL; */
2264 nss->handle = handle;
2266 debug_return_int(0);
2270 sudo_ldap_setdefs(struct sudo_nss *nss)
2272 struct ldap_config_list_str *base;
2273 struct sudo_ldap_handle *handle = nss->handle;
2274 struct timeval tv, *tvp = NULL;
2276 LDAPMessage *entry, *result;
2279 debug_decl(sudo_ldap_setdefs, SUDO_DEBUG_LDAP)
2281 if (handle == NULL || handle->ld == NULL)
2282 debug_return_int(-1);
2285 filt = sudo_ldap_build_default_filter();
2286 DPRINTF(("Looking for cn=defaults: %s", filt), 1);
2288 for (base = ldap_conf.base; base != NULL; base = base->next) {
2289 if (ldap_conf.timeout > 0) {
2290 tv.tv_sec = ldap_conf.timeout;
2295 rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
2296 filt, NULL, 0, NULL, NULL, tvp, 0, &result);
2297 if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
2298 DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
2299 sudo_ldap_parse_options(ld, entry);
2301 DPRINTF(("no default options found in %s", base->val), 1);
2304 ldap_msgfree(result);
2308 debug_return_int(0);
2312 * like sudoers_lookup() - only LDAP style
2315 sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
2317 struct sudo_ldap_handle *handle = nss->handle;
2320 int i, rc, setenv_implied;
2321 struct ldap_result *lres = NULL;
2322 debug_decl(sudo_ldap_lookup, SUDO_DEBUG_LDAP)
2324 if (handle == NULL || handle->ld == NULL)
2325 debug_return_int(ret);
2328 /* Fetch list of sudoRole entries that match user and host. */
2329 lres = sudo_ldap_result_get(nss, sudo_user.pw);
2332 * The following queries are only determine whether or not a
2333 * password is required, so the order of the entries doesn't matter.
2336 int doauth = UNSPEC;
2337 int matched = UNSPEC;
2338 enum def_tuple pwcheck =
2339 (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
2341 DPRINTF(("perform search for pwflag %d", pwflag), 1);
2342 for (i = 0; i < lres->nentries; i++) {
2343 entry = lres->entries[i].entry;
2344 if ((pwcheck == any && doauth != false) ||
2345 (pwcheck == all && doauth == false)) {
2346 doauth = sudo_ldap_check_bool(ld, entry, "authenticate");
2348 /* Only check the command when listing another user. */
2349 if (user_uid == 0 || list_pw == NULL ||
2350 user_uid == list_pw->pw_uid ||
2351 sudo_ldap_check_command(ld, entry, NULL)) {
2356 if (matched || user_uid == 0) {
2357 SET(ret, VALIDATE_OK);
2358 CLR(ret, VALIDATE_NOT_OK);
2359 if (def_authenticate) {
2362 SET(ret, FLAG_CHECK_USER);
2366 if (doauth == false)
2367 def_authenticate = false;
2370 def_authenticate = false;
2380 DPRINTF(("searching LDAP for sudoers entries"), 1);
2382 setenv_implied = false;
2383 for (i = 0; i < lres->nentries; i++) {
2384 entry = lres->entries[i].entry;
2385 if (!sudo_ldap_check_runas(ld, entry))
2387 rc = sudo_ldap_check_command(ld, entry, &setenv_implied);
2389 /* We have a match. */
2390 DPRINTF(("Command %sallowed", rc == true ? "" : "NOT "), 1);
2392 DPRINTF(("LDAP entry: %p", entry), 1);
2393 /* Apply entry-specific options. */
2396 sudo_ldap_parse_options(ld, entry);
2398 /* Set role and type if not specified on command line. */
2399 if (user_role == NULL)
2400 user_role = def_role;
2401 if (user_type == NULL)
2402 user_type = def_type;
2403 #endif /* HAVE_SELINUX */
2404 SET(ret, VALIDATE_OK);
2405 CLR(ret, VALIDATE_NOT_OK);
2407 SET(ret, VALIDATE_NOT_OK);
2408 CLR(ret, VALIDATE_OK);
2415 DPRINTF(("done with LDAP searches"), 1);
2416 DPRINTF(("user_matches=%d", lres->user_matches), 1);
2417 DPRINTF(("host_matches=%d", lres->host_matches), 1);
2419 if (!ISSET(ret, VALIDATE_OK)) {
2420 /* No matching entries. */
2421 if (pwflag && list_pw == NULL)
2422 SET(ret, FLAG_NO_CHECK);
2424 if (lres->user_matches)
2425 CLR(ret, FLAG_NO_USER);
2426 if (lres->host_matches)
2427 CLR(ret, FLAG_NO_HOST);
2428 DPRINTF(("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret), 1);
2430 debug_return_int(ret);
2434 * Comparison function for ldap_entry_wrapper structures, descending order.
2437 ldap_entry_compare(const void *a, const void *b)
2439 const struct ldap_entry_wrapper *aw = a;
2440 const struct ldap_entry_wrapper *bw = b;
2441 debug_decl(ldap_entry_compare, SUDO_DEBUG_LDAP)
2443 debug_return_int(bw->order < aw->order ? -1 :
2444 (bw->order > aw->order ? 1 : 0));
2448 * Find the last entry in the list of searches, usually the
2449 * one currently being used to add entries.
2450 * XXX - use a tailq instead?
2452 static struct ldap_search_list *
2453 sudo_ldap_result_last_search(struct ldap_result *lres)
2455 struct ldap_search_list *result = lres->searches;
2456 debug_decl(sudo_ldap_result_last_search, SUDO_DEBUG_LDAP)
2459 while (result->next)
2460 result = result->next;
2462 debug_return_ptr(result);
2466 * Add an entry to the result structure.
2468 static struct ldap_entry_wrapper *
2469 sudo_ldap_result_add_entry(struct ldap_result *lres, LDAPMessage *entry)
2471 struct ldap_search_list *last;
2475 debug_decl(sudo_ldap_result_add_entry, SUDO_DEBUG_LDAP)
2477 /* Determine whether the entry has the sudoOrder attribute. */
2478 last = sudo_ldap_result_last_search(lres);
2479 bv = ldap_get_values_len(last->ldap, entry, "sudoOrder");
2481 if (ldap_count_values_len(bv) > 0) {
2482 /* Get the value of this attribute, 0 if not present. */
2483 DPRINTF(("order attribute raw: %s", (*bv)->bv_val), 1);
2484 order = strtod((*bv)->bv_val, &ep);
2485 if (ep == (*bv)->bv_val || *ep != '\0') {
2486 warningx(_("invalid sudoOrder attribute: %s"), (*bv)->bv_val);
2489 DPRINTF(("order attribute: %f", order), 1);
2491 ldap_value_free_len(bv);
2495 * Enlarge the array of entry wrappers as needed, preallocating blocks
2496 * of 100 entries to save on allocation time.
2498 if (++lres->nentries > lres->allocated_entries) {
2499 lres->allocated_entries += ALLOCATION_INCREMENT;
2500 lres->entries = erealloc3(lres->entries, lres->allocated_entries,
2501 sizeof(lres->entries[0]));
2504 /* Fill in the new entry and return it. */
2505 lres->entries[lres->nentries - 1].entry = entry;
2506 lres->entries[lres->nentries - 1].order = order;
2508 debug_return_ptr(&lres->entries[lres->nentries - 1]);
2512 * Free the ldap result structure in the sudo_nss handle.
2515 sudo_ldap_result_free_nss(struct sudo_nss *nss)
2517 struct sudo_ldap_handle *handle = nss->handle;
2518 debug_decl(sudo_ldap_result_free_nss, SUDO_DEBUG_LDAP)
2520 if (handle->result != NULL) {
2521 DPRINTF(("removing reusable search result"), 1);
2522 sudo_ldap_result_free(handle->result);
2523 if (handle->username) {
2524 efree(handle->username);
2525 handle->username = NULL;
2527 handle->grlist = NULL;
2528 handle->result = NULL;
2534 * Perform the LDAP query for the user or return a cached query if
2535 * there is one for this user.
2537 static struct ldap_result *
2538 sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
2540 struct sudo_ldap_handle *handle = nss->handle;
2541 struct ldap_config_list_str *base;
2542 struct ldap_result *lres;
2543 struct timeval tv, *tvp = NULL;
2544 LDAPMessage *entry, *result;
2545 LDAP *ld = handle->ld;
2548 debug_decl(sudo_ldap_result_get, SUDO_DEBUG_LDAP)
2551 * If we already have a cached result, return it so we don't have to
2552 * have to contact the LDAP server again.
2554 if (handle->result) {
2555 if (handle->grlist == user_group_list &&
2556 strcmp(pw->pw_name, handle->username) == 0) {
2557 DPRINTF(("reusing previous result (user %s) with %d entries",
2558 handle->username, handle->result->nentries), 1);
2559 debug_return_ptr(handle->result);
2561 /* User mismatch, cached result cannot be used. */
2562 DPRINTF(("removing result (user %s), new search (user %s)",
2563 handle->username, pw->pw_name), 1);
2564 sudo_ldap_result_free_nss(nss);
2568 * Okay - time to search for anything that matches this user
2569 * Lets limit it to only two queries of the LDAP server
2571 * The first pass will look by the username, groups, and
2572 * the keyword ALL. We will then inspect the results that
2573 * came back from the query. We don't need to inspect the
2574 * sudoUser in this pass since the LDAP server already scanned
2577 * The second pass will return all the entries that contain
2578 * user netgroups. Then we take the netgroups returned and
2579 * try to match them against the username.
2581 * Since we have to sort the possible entries before we make a
2582 * decision, we perform the queries and store all of the results in
2583 * an ldap_result object. The results are then sorted by sudoOrder.
2585 lres = sudo_ldap_result_alloc();
2586 for (do_netgr = 0; do_netgr < 2; do_netgr++) {
2587 filt = do_netgr ? sudo_ldap_build_pass2() : sudo_ldap_build_pass1(pw);
2588 DPRINTF(("ldap search '%s'", filt), 1);
2589 for (base = ldap_conf.base; base != NULL; base = base->next) {
2590 DPRINTF(("searching from base '%s'", base->val), 1);
2591 if (ldap_conf.timeout > 0) {
2592 tv.tv_sec = ldap_conf.timeout;
2597 rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt,
2598 NULL, 0, NULL, NULL, tvp, 0, &result);
2599 if (rc != LDAP_SUCCESS) {
2600 DPRINTF(("nothing found for '%s'", filt), 1);
2603 lres->user_matches = true;
2605 /* Add the seach result to list of search results. */
2606 DPRINTF(("adding search result"), 1);
2607 sudo_ldap_result_add_search(lres, ld, result);
2608 LDAP_FOREACH(entry, ld, result) {
2610 sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
2611 sudo_ldap_check_host(ld, entry)) {
2612 lres->host_matches = true;
2613 sudo_ldap_result_add_entry(lres, entry);
2616 DPRINTF(("result now has %d entries", lres->nentries), 1);
2621 /* Sort the entries by the sudoOrder attribute. */
2622 DPRINTF(("sorting remaining %d entries", lres->nentries), 1);
2623 qsort(lres->entries, lres->nentries, sizeof(lres->entries[0]),
2624 ldap_entry_compare);
2626 /* Store everything in the sudo_nss handle. */
2627 handle->result = lres;
2628 handle->username = estrdup(pw->pw_name);
2629 handle->grlist = user_group_list;
2631 debug_return_ptr(lres);
2635 * Shut down the LDAP connection.
2638 sudo_ldap_close(struct sudo_nss *nss)
2640 struct sudo_ldap_handle *handle = nss->handle;
2641 debug_decl(sudo_ldap_close, SUDO_DEBUG_LDAP)
2643 if (handle != NULL) {
2644 /* Free the result before unbinding; it may use the LDAP connection. */
2645 sudo_ldap_result_free_nss(nss);
2647 /* Unbind and close the LDAP connection. */
2648 if (handle->ld != NULL) {
2649 ldap_unbind_ext_s(handle->ld, NULL, NULL);
2653 /* Free the handle container. */
2657 debug_return_int(0);
2664 sudo_ldap_parse(struct sudo_nss *nss)
2671 * Create an ldap_result from an LDAP search result.
2673 * This function is currently not used anywhere, it is left here as
2674 * an example of how to use the cached searches.
2676 static struct ldap_result *
2677 sudo_ldap_result_from_search(LDAP *ldap, LDAPMessage *searchresult)
2680 * An ldap_result is built from several search results, which are
2681 * organized in a list. The head of the list is maintained in the
2682 * ldap_result structure, together with the wrappers that point
2683 * to individual entries, this has to be initialized first.
2685 struct ldap_result *result = sudo_ldap_result_alloc();
2688 * Build a new list node for the search result, this creates the
2691 struct ldap_search_list *last = sudo_ldap_result_add_search(result,
2692 ldap, searchresult);
2695 * Now add each entry in the search result to the array of of entries
2696 * in the ldap_result object.
2699 LDAP_FOREACH(entry, last->ldap, last->searchresult) {
2700 sudo_ldap_result_add_entry(result, entry);
2702 DPRINTF(("sudo_ldap_result_from_search: %d entries found",
2703 result->nentries), 2);