2 * Copyright (c) 2003-2008 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 */
37 # ifdef HAVE_STRINGS_H
40 #endif /* HAVE_STRING_H */
41 #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
43 #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
46 #endif /* HAVE_UNISTD_H */
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
57 #if defined(HAVE_LDAP_SSL_H)
58 # include <ldap_ssl.h>
59 #elif defined(HAVE_MPS_LDAP_SSL_H)
60 # include <mps/ldap_ssl.h>
62 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
63 # ifdef HAVE_SASL_SASL_H
64 # include <sasl/sasl.h>
68 # if HAVE_GSS_KRB5_CCACHE_NAME
69 # if defined(HAVE_GSSAPI_GSSAPI_KRB5_H)
70 # include <gssapi/gssapi.h>
71 # include <gssapi/gssapi_krb5.h>
72 # elif defined(HAVE_GSSAPI_GSSAPI_H)
73 # include <gssapi/gssapi.h>
85 __unused static const char rcsid[] = "$Sudo: ldap.c,v 1.100 2008/04/23 12:30:07 millert Exp $";
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 #define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k) \
106 ldap_search_s(a, b, c, d, e, f, k)
109 #define LDAP_FOREACH(var, ld, res) \
110 for ((var) = ldap_first_entry((ld), (res)); \
112 (var) = ldap_next_entry((ld), (var)))
114 #define DPRINTF(args, level) if (ldap_conf.debug >= level) warningx args
120 #define SUDO_LDAP_SSL 1
121 #define SUDO_LDAP_STARTTLS 2
123 struct ldap_config_table {
124 const char *conf_str; /* config file string */
125 short type; /* CONF_BOOL, CONF_INT, CONF_STR */
126 short connected; /* connection-specific value? */
127 int opt_val; /* LDAP_OPT_* (or -1 for sudo internal) */
128 void *valp; /* pointer into ldap_conf */
131 /* ldap configuration structure */
132 static struct ldap_config {
150 char *tls_cacertfile;
152 char *tls_random_file;
153 char *tls_cipher_suite;
157 char *rootsasl_auth_id;
162 static struct ldap_config_table ldap_conf_table[] = {
163 { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug },
164 { "host", CONF_STR, FALSE, -1, &ldap_conf.host },
165 { "port", CONF_INT, FALSE, -1, &ldap_conf.port },
166 { "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl },
167 { "sslpath", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
168 { "uri", CONF_STR, FALSE, -1, &ldap_conf.uri },
169 #ifdef LDAP_OPT_DEBUG_LEVEL
170 { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
172 #ifdef LDAP_OPT_PROTOCOL_VERSION
173 { "ldap_version", CONF_INT, TRUE, LDAP_OPT_PROTOCOL_VERSION,
174 &ldap_conf.version },
176 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
177 { "tls_checkpeer", CONF_BOOL, FALSE, LDAP_OPT_X_TLS_REQUIRE_CERT,
178 &ldap_conf.tls_checkpeer },
180 { "tls_checkpeer", CONF_BOOL, FALSE, -1, &ldap_conf.tls_checkpeer },
182 #ifdef LDAP_OPT_X_TLS_CACERTFILE
183 { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
184 &ldap_conf.tls_cacertfile },
186 #ifdef LDAP_OPT_X_TLS_CACERTDIR
187 { "tls_cacertdir", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTDIR,
188 &ldap_conf.tls_cacertdir },
190 #ifdef LDAP_OPT_X_TLS_RANDOM_FILE
191 { "tls_randfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_RANDOM_FILE,
192 &ldap_conf.tls_random_file },
194 #ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
195 { "tls_ciphers", CONF_STR, FALSE, LDAP_OPT_X_TLS_CIPHER_SUITE,
196 &ldap_conf.tls_cipher_suite },
198 #ifdef LDAP_OPT_X_TLS_CERTFILE
199 { "tls_cert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CERTFILE,
200 &ldap_conf.tls_certfile },
202 { "tls_cert", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
204 #ifdef LDAP_OPT_X_TLS_KEYFILE
205 { "tls_key", CONF_STR, FALSE, LDAP_OPT_X_TLS_KEYFILE,
206 &ldap_conf.tls_keyfile },
208 { "tls_key", CONF_STR, FALSE, -1, &ldap_conf.tls_keyfile },
210 #ifdef LDAP_OPT_NETWORK_TIMEOUT
211 { "bind_timelimit", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
212 &ldap_conf.bind_timelimit },
213 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
214 { "bind_timelimit", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT,
215 &ldap_conf.bind_timelimit },
217 { "timelimit", CONF_INT, TRUE, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit },
218 { "binddn", CONF_STR, FALSE, -1, &ldap_conf.binddn },
219 { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw },
220 { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
221 { "sudoers_base", CONF_STR, FALSE, -1, &ldap_conf.base },
222 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
223 { "use_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.use_sasl },
224 { "sasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.sasl_auth_id },
225 { "rootuse_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.rootuse_sasl },
226 { "rootsasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.rootsasl_auth_id },
227 # ifdef LDAP_OPT_X_SASL_SECPROPS
228 { "sasl_secprops", CONF_STR, TRUE, LDAP_OPT_X_SASL_SECPROPS,
229 &ldap_conf.sasl_secprops },
231 { "krb5_ccname", CONF_STR, FALSE, -1, &ldap_conf.krb5_ccname },
232 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
236 struct sudo_nss sudo_nss_ldap = {
244 sudo_ldap_display_cmnd,
245 sudo_ldap_display_defaults,
246 sudo_ldap_display_bound_defaults,
247 sudo_ldap_display_privs
250 #ifdef HAVE_LDAP_CREATE
252 * Rebuild the hosts list and include a specific port for each host.
253 * ldap_create() does not take a default port parameter so we must
254 * append one if we want something other than LDAP_PORT.
257 sudo_ldap_conf_add_ports()
260 char *host, *port, defport[13];
261 char hostbuf[LINE_MAX * 2];
264 if (snprintf(defport, sizeof(defport), ":%d", ldap_conf.port) >= sizeof(defport))
265 errorx(1, "sudo_ldap_conf_add_ports: port too large");
267 for ((host = strtok(ldap_conf.host, " \t")); host; (host = strtok(NULL, " \t"))) {
268 if (hostbuf[0] != '\0') {
269 if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
273 if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
275 /* Append port if there is not one already. */
276 if ((port = strrchr(host, ':')) == NULL || !isdigit(port[1])) {
277 if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf))
282 free(ldap_conf.host);
283 ldap_conf.host = estrdup(hostbuf);
287 errorx(1, "sudo_ldap_conf_add_ports: out of space expanding hostbuf");
291 #ifndef HAVE_LDAP_INITIALIZE
293 * For each uri, convert to host:port pairs. For ldaps:// enable SSL
294 * Accepts: uris of the form ldap:/// or ldap://hostname:portnum/
295 * where the trailing slash is optional.
298 sudo_ldap_parse_uri(uri_list)
299 const char *uri_list;
301 char *buf, *uri, *host, *cp, *port;
302 char hostbuf[LINE_MAX];
303 int nldap = 0, nldaps = 0;
306 buf = estrdup(uri_list);
308 for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
309 if (strncasecmp(uri, "ldap://", 7) == 0) {
312 } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
316 warningx("unsupported LDAP uri type: %s", uri);
320 /* trim optional trailing slash */
321 if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
325 if (hostbuf[0] != '\0') {
326 if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
331 host = "localhost"; /* no host specified, use localhost */
333 if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
336 /* If using SSL and no port specified, add port 636 */
338 if ((port = strrchr(host, ':')) == NULL || !isdigit(port[1]))
339 if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
343 if (hostbuf[0] == '\0') {
344 warningx("invalid uri: %s", uri_list);
350 warningx("cannot mix ldap and ldaps URIs");
353 if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
354 warningx("cannot mix ldaps and starttls");
357 ldap_conf.ssl_mode = SUDO_LDAP_SSL;
360 free(ldap_conf.host);
361 ldap_conf.host = estrdup(hostbuf);
369 errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
371 #endif /* HAVE_LDAP_INITIALIZE */
374 sudo_ldap_init(ldp, host, port)
380 int rc = LDAP_CONNECT_ERROR;
382 #ifdef HAVE_LDAPSSL_INIT
383 if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
384 DPRINTF(("ldapssl_clientauth_init(%s, %s)",
385 ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
386 ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
387 rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
388 ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
389 if (rc != LDAP_SUCCESS) {
390 warningx("unable to initialize SSL cert and key db: %s",
391 ldapssl_err2string(rc));
395 DPRINTF(("ldapssl_init(%s, %d, 1)", host, port), 2);
396 if ((ld = ldapssl_init(host, port, 1)) != NULL)
401 #ifdef HAVE_LDAP_CREATE
402 DPRINTF(("ldap_create()"), 2);
403 if ((rc = ldap_create(&ld)) != LDAP_SUCCESS)
405 DPRINTF(("ldap_set_option(LDAP_OPT_HOST_NAME, %s)", host), 2);
406 rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, host);
408 DPRINTF(("ldap_init(%s, %d)", host, port), 2);
409 if ((ld = ldap_init(host, port)) != NULL)
420 * Walk through search results and return TRUE if we have a matching
421 * netgroup, else FALSE.
424 sudo_ldap_check_user_netgroup(ld, entry, user)
429 struct berval **bv, **p;
436 /* get the values from the entry */
437 bv = ldap_get_values_len(ld, entry, "sudoUser");
441 /* walk through values */
442 for (p = bv; *p != NULL && !ret; p++) {
445 if (netgr_matches(val, NULL, NULL, user))
447 DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val,
448 ret ? "MATCH!" : "not"), 2);
451 ldap_value_free_len(bv); /* cleanup */
457 * Walk through search results and return TRUE if we have a
458 * host match, else FALSE.
461 sudo_ldap_check_host(ld, entry)
465 struct berval **bv, **p;
472 /* get the values from the entry */
473 bv = ldap_get_values_len(ld, entry, "sudoHost");
477 /* walk through values */
478 for (p = bv; *p != NULL && !ret; p++) {
480 /* match any or address or netgroup or hostname */
481 if (!strcmp(val, "ALL") || addr_matches(val) ||
482 netgr_matches(val, user_host, user_shost, NULL) ||
483 hostname_matches(user_shost, user_host, val))
485 DPRINTF(("ldap sudoHost '%s' ... %s", val,
486 ret ? "MATCH!" : "not"), 2);
489 ldap_value_free_len(bv); /* cleanup */
495 sudo_ldap_check_runas_user(ld, entry)
499 struct berval **bv, **p;
506 /* get the runas user from the entry */
507 bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
509 bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */
514 * if runas is not specified on the command line, the only information
515 * as to which user to run as is in the runas_default option. We should
516 * check to see if we have the local option present. Unfortunately we
517 * don't parse these options until after this routine says yes or no.
518 * The query has already returned, so we could peek at the attribute
519 * values here though.
521 * For now just require users to always use -u option unless its set
522 * in the global defaults. This behaviour is no different than the global
525 * Sigh - maybe add this feature later
529 * If there are no runas entries, match runas_default against
530 * what the user specified on the command line.
533 return(!strcasecmp(runas_pw->pw_name, def_runas_default));
535 /* walk through values returned, looking for a match */
536 for (p = bv; *p != NULL && !ret; p++) {
540 if (netgr_matches(val, NULL, NULL, runas_pw->pw_name))
544 if (usergr_matches(val, runas_pw->pw_name, runas_pw))
548 if (strcmp(val, "ALL") == 0) {
554 if (strcasecmp(val, runas_pw->pw_name) == 0)
558 DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val,
559 ret ? "MATCH!" : "not"), 2);
562 ldap_value_free_len(bv); /* cleanup */
568 sudo_ldap_check_runas_group(ld, entry)
572 struct berval **bv, **p;
576 /* runas_gr is only set if the user specified the -g flag */
580 /* get the values from the entry */
581 bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
585 /* walk through values returned, looking for a match */
586 for (p = bv; *p != NULL && !ret; p++) {
588 if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
590 DPRINTF(("ldap sudoRunAsGroup '%s' ... %s", val,
591 ret ? "MATCH!" : "not"), 2);
594 ldap_value_free_len(bv); /* cleanup */
600 * Walk through search results and return TRUE if we have a runas match,
601 * else FALSE. RunAs info is optional.
604 sudo_ldap_check_runas(ld, entry)
613 ret = sudo_ldap_check_runas_user(ld, entry) != FALSE &&
614 sudo_ldap_check_runas_group(ld, entry) != FALSE;
620 * Walk through search results and return TRUE if we have a command match,
621 * FALSE if disallowed and UNSPEC if not matched.
624 sudo_ldap_check_command(ld, entry, setenv_implied)
629 struct berval **bv, **p;
630 char *allowed_cmnd, *allowed_args, *val;
631 int foundbang, ret = UNSPEC;
636 bv = ldap_get_values_len(ld, entry, "sudoCommand");
640 for (p = bv; *p != NULL && ret != FALSE; p++) {
642 /* Match against ALL ? */
643 if (!strcmp(val, "ALL")) {
645 if (setenv_implied != NULL)
646 *setenv_implied = TRUE;
647 DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2);
651 /* check for !command */
654 allowed_cmnd = estrdup(1 + val); /* !command */
657 allowed_cmnd = estrdup(val); /* command */
660 /* split optional args away from command */
661 allowed_args = strchr(allowed_cmnd, ' ');
663 *allowed_args++ = '\0';
665 /* check the command like normal */
666 if (command_matches(allowed_cmnd, allowed_args)) {
668 * If allowed (no bang) set ret but keep on checking.
669 * If disallowed (bang), exit loop.
671 ret = foundbang ? FALSE : TRUE;
673 DPRINTF(("ldap sudoCommand '%s' ... %s", val,
674 ret == TRUE ? "MATCH!" : "not"), 2);
676 efree(allowed_cmnd); /* cleanup */
679 ldap_value_free_len(bv); /* more cleanup */
685 * Search for boolean "option" in sudoOption.
686 * Returns TRUE if found and allowed, FALSE if negated, else UNSPEC.
689 sudo_ldap_check_bool(ld, entry, option)
694 struct berval **bv, **p;
701 bv = ldap_get_values_len(ld, entry, "sudoOption");
705 /* walk through options */
706 for (p = bv; *p != NULL; p++) {
708 DPRINTF(("ldap sudoOption: '%s'", var), 2);
710 if ((ch = *var) == '!')
712 if (strcmp(var, option) == 0)
716 ldap_value_free_len(bv);
722 * Read sudoOption and modify the defaults as we go. This is used once
723 * from the cn=defaults entry and also once when a final sudoRole is matched.
726 sudo_ldap_parse_options(ld, entry)
730 struct berval **bv, **p;
736 bv = ldap_get_values_len(ld, entry, "sudoOption");
740 /* walk through options */
741 for (p = bv; *p != NULL; p++) {
742 var = estrdup((*p)->bv_val);
743 DPRINTF(("ldap sudoOption: '%s'", var), 2);
745 /* check for equals sign past first char */
746 val = strchr(var, '=');
748 *val++ = '\0'; /* split on = and truncate var */
749 op = *(val - 2); /* peek for += or -= cases */
750 if (op == '+' || op == '-') {
751 *(val - 2) = '\0'; /* found, remove extra char */
752 /* case var+=val or var-=val */
753 set_default(var, val, (int) op);
756 set_default(var, val, TRUE);
758 } else if (*var == '!') {
759 /* case !var Boolean False */
760 set_default(var + 1, NULL, FALSE);
762 /* case var Boolean True */
763 set_default(var, NULL, TRUE);
768 ldap_value_free_len(bv);
772 * builds together a filter to check against ldap
775 sudo_ldap_build_pass1(pw)
783 /* Start with (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
784 sz = 29 + strlen(pw->pw_name);
786 /* Add space for groups */
787 if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL)
788 sz += 12 + strlen(grp->gr_name); /* primary group */
789 for (i = 0; i < user_ngroups; i++) {
790 if (user_groups[i] == pw->pw_gid)
792 if ((grp = sudo_getgrgid(user_groups[i])) != NULL)
793 sz += 12 + strlen(grp->gr_name); /* supplementary group */
797 /* Global OR + sudoUser=user_name filter */
798 (void) strlcpy(buf, "(|(sudoUser=", sz);
799 (void) strlcat(buf, pw->pw_name, sz);
800 (void) strlcat(buf, ")", sz);
802 /* Append primary group */
803 if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
804 (void) strlcat(buf, "(sudoUser=%", sz);
805 (void) strlcat(buf, grp->gr_name, sz);
806 (void) strlcat(buf, ")", sz);
809 /* Append supplementary groups */
810 for (i = 0; i < user_ngroups; i++) {
811 if (user_groups[i] == pw->pw_gid)
813 if ((grp = sudo_getgrgid(user_groups[i])) != NULL) {
814 (void) strlcat(buf, "(sudoUser=%", sz);
815 (void) strlcat(buf, grp->gr_name, sz);
816 (void) strlcat(buf, ")", sz);
820 /* Add ALL to list and end the global OR */
821 if (strlcat(buf, "(sudoUser=ALL))", sz) >= sz)
822 errorx(1, "sudo_ldap_build_pass1 allocation mismatch");
828 * Map yes/true/on to TRUE, no/false/off to FALSE, else -1
837 if (strcasecmp(s, "yes") == 0)
842 if (strcasecmp(s, "true") == 0)
847 if (strcasecmp(s, "on") == 0)
849 if (strcasecmp(s, "off") == 0)
854 if (strcasecmp(s, "no") == 0)
859 if (strcasecmp(s, "false") == 0)
867 sudo_ldap_read_secret(path)
871 char buf[LINE_MAX], *cp;
873 if ((fp = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
874 if (fgets(buf, sizeof(buf), fp) != NULL) {
875 if ((cp = strchr(buf, '\n')) != NULL)
877 /* copy to bindpw and binddn */
878 efree(ldap_conf.bindpw);
879 ldap_conf.bindpw = estrdup(buf);
880 efree(ldap_conf.binddn);
881 ldap_conf.binddn = ldap_conf.rootbinddn;
882 ldap_conf.rootbinddn = NULL;
889 sudo_ldap_read_config()
892 char *cp, *keyword, *value;
893 struct ldap_config_table *cur;
896 ldap_conf.version = 3;
898 ldap_conf.tls_checkpeer = -1;
899 ldap_conf.timelimit = -1;
900 ldap_conf.bind_timelimit = -1;
901 ldap_conf.use_sasl = -1;
902 ldap_conf.rootuse_sasl = -1;
904 if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL)
907 while ((cp = sudo_parseln(fp)) != NULL) {
909 continue; /* skip empty line */
911 /* split into keyword and value */
913 while (*cp && !isblank((unsigned char) *cp))
916 *cp++ = '\0'; /* terminate keyword */
918 /* skip whitespace before value */
919 while (isblank((unsigned char) *cp))
923 /* Look up keyword in config table. */
924 for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
925 if (strcasecmp(keyword, cur->conf_str) == 0) {
928 *(int *)(cur->valp) = _atobool(value);
931 *(int *)(cur->valp) = atoi(value);
934 efree(*(char **)(cur->valp));
935 *(char **)(cur->valp) = estrdup(value);
945 ldap_conf.host = estrdup("localhost");
947 if (ldap_conf.bind_timelimit > 0)
948 ldap_conf.bind_timelimit *= 1000; /* convert to ms */
950 if (ldap_conf.debug > 1) {
951 fprintf(stderr, "LDAP Config Summary\n");
952 fprintf(stderr, "===================\n");
954 fprintf(stderr, "uri %s\n", ldap_conf.uri);
956 fprintf(stderr, "host %s\n", ldap_conf.host ?
957 ldap_conf.host : "(NONE)");
958 fprintf(stderr, "port %d\n", ldap_conf.port);
960 fprintf(stderr, "ldap_version %d\n", ldap_conf.version);
962 fprintf(stderr, "sudoers_base %s\n", ldap_conf.base ?
963 ldap_conf.base : "(NONE) <---Sudo will ignore ldap)");
964 fprintf(stderr, "binddn %s\n", ldap_conf.binddn ?
965 ldap_conf.binddn : "(anonymous)");
966 fprintf(stderr, "bindpw %s\n", ldap_conf.bindpw ?
967 ldap_conf.bindpw : "(anonymous)");
968 if (ldap_conf.bind_timelimit > 0)
969 fprintf(stderr, "bind_timelimit %d\n", ldap_conf.bind_timelimit);
970 if (ldap_conf.timelimit > 0)
971 fprintf(stderr, "timelimit %d\n", ldap_conf.timelimit);
972 fprintf(stderr, "ssl %s\n", ldap_conf.ssl ?
973 ldap_conf.ssl : "(no)");
974 if (ldap_conf.tls_checkpeer != -1)
975 fprintf(stderr, "tls_checkpeer %s\n", ldap_conf.tls_checkpeer ?
977 if (ldap_conf.tls_cacertfile != NULL)
978 fprintf(stderr, "tls_cacertfile %s\n", ldap_conf.tls_cacertfile);
979 if (ldap_conf.tls_cacertdir != NULL)
980 fprintf(stderr, "tls_cacertdir %s\n", ldap_conf.tls_cacertdir);
981 if (ldap_conf.tls_random_file != NULL)
982 fprintf(stderr, "tls_random_file %s\n", ldap_conf.tls_random_file);
983 if (ldap_conf.tls_cipher_suite != NULL)
984 fprintf(stderr, "tls_cipher_suite %s\n", ldap_conf.tls_cipher_suite);
985 if (ldap_conf.tls_certfile != NULL)
986 fprintf(stderr, "tls_certfile %s\n", ldap_conf.tls_certfile);
987 if (ldap_conf.tls_keyfile != NULL)
988 fprintf(stderr, "tls_keyfile %s\n", ldap_conf.tls_keyfile);
989 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
990 if (ldap_conf.use_sasl != -1) {
991 fprintf(stderr, "use_sasl %s\n",
992 ldap_conf.use_sasl ? "yes" : "no");
993 fprintf(stderr, "sasl_auth_id %s\n", ldap_conf.sasl_auth_id ?
994 ldap_conf.sasl_auth_id : "(NONE)");
995 fprintf(stderr, "rootuse_sasl %d\n", ldap_conf.rootuse_sasl);
996 fprintf(stderr, "rootsasl_auth_id %s\n", ldap_conf.rootsasl_auth_id ?
997 ldap_conf.rootsasl_auth_id : "(NONE)");
998 fprintf(stderr, "sasl_secprops %s\n", ldap_conf.sasl_secprops ?
999 ldap_conf.sasl_secprops : "(NONE)");
1000 fprintf(stderr, "krb5_ccname %s\n", ldap_conf.krb5_ccname ?
1001 ldap_conf.krb5_ccname : "(NONE)");
1004 fprintf(stderr, "===================\n");
1006 if (!ldap_conf.base)
1007 return(FALSE); /* if no base is defined, ignore LDAP */
1010 * Interpret SSL option
1012 if (ldap_conf.ssl != NULL) {
1013 if (strcasecmp(ldap_conf.ssl, "start_tls") == 0)
1014 ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS;
1015 else if (_atobool(ldap_conf.ssl))
1016 ldap_conf.ssl_mode = SUDO_LDAP_SSL;
1019 #if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
1020 if (ldap_conf.tls_checkpeer != -1) {
1021 ldapssl_set_strength(NULL,
1022 ldap_conf.tls_checkpeer ? LDAPSSL_AUTH_CERT : LDAPSSL_AUTH_WEAK);
1026 #ifndef HAVE_LDAP_INITIALIZE
1027 /* Convert uri list to host list if no ldap_initialize(). */
1028 if (ldap_conf.uri) {
1029 if (sudo_ldap_parse_uri(ldap_conf.uri) != 0)
1031 free(ldap_conf.uri);
1032 ldap_conf.uri = NULL;
1033 ldap_conf.port = LDAP_PORT;
1037 if (!ldap_conf.uri) {
1038 /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
1039 if (ldap_conf.port < 0)
1041 ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
1043 #ifdef HAVE_LDAP_CREATE
1045 * Cannot specify port directly to ldap_create(), each host must
1046 * include :port to override the default.
1048 if (ldap_conf.port != LDAP_PORT)
1049 sudo_ldap_conf_add_ports();
1053 /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
1054 if (ldap_conf.rootbinddn)
1055 sudo_ldap_read_secret(_PATH_LDAP_SECRET);
1057 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1059 * Make sure we can open the file specified by krb5_ccname.
1061 if (ldap_conf.krb5_ccname != NULL) {
1062 if (strncasecmp(ldap_conf.krb5_ccname, "FILE:", 5) == 0 ||
1063 strncasecmp(ldap_conf.krb5_ccname, "WRFILE:", 7) == 0) {
1064 value = ldap_conf.krb5_ccname +
1065 (ldap_conf.krb5_ccname[4] == ':' ? 5 : 7);
1066 if ((fp = fopen(value, "r")) != NULL) {
1067 DPRINTF(("using krb5 credential cache: %s", value), 1);
1070 /* Can't open it, just ignore the entry. */
1071 DPRINTF(("unable to open krb5 credential cache: %s", value), 1);
1072 efree(ldap_conf.krb5_ccname);
1073 ldap_conf.krb5_ccname = NULL;
1082 * Extract the dn from an entry and return the first rdn from it.
1085 sudo_ldap_get_first_rdn(ld, entry)
1089 #ifdef HAVE_LDAP_STR2DN
1090 char *dn, *rdn = NULL;
1093 if ((dn = ldap_get_dn(ld, entry)) == NULL)
1095 if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) {
1096 ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN);
1104 if ((dn = ldap_get_dn(ld, entry)) == NULL)
1106 edn = ldap_explode_dn(dn, 1);
1108 return(edn ? edn[0] : NULL);
1113 * Fetch and display the global Options.
1116 sudo_ldap_display_defaults(nss, pw, lbuf)
1117 struct sudo_nss *nss;
1121 struct berval **bv, **p;
1122 LDAP *ld = (LDAP *) nss->handle;
1123 LDAPMessage *entry = NULL, *result = NULL;
1124 char *prefix = NULL;
1130 rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
1131 "cn=defaults", NULL, 0, NULL, NULL, NULL, -1, &result);
1132 if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
1133 bv = ldap_get_values_len(ld, entry, "sudoOption");
1139 for (p = bv; *p != NULL; p++) {
1140 lbuf_append(lbuf, prefix, (*p)->bv_val, NULL);
1144 ldap_value_free_len(bv);
1148 ldap_msgfree(result);
1156 sudo_ldap_display_bound_defaults(nss, pw, lbuf)
1157 struct sudo_nss *nss;
1165 * Print a record in the short form, ala file sudoers.
1168 sudo_ldap_display_entry_short(ld, entry, lbuf)
1173 struct berval **bv, **p;
1176 lbuf_append(lbuf, " (", NULL);
1178 /* get the RunAsUser Values from the entry */
1179 bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
1181 bv = ldap_get_values_len(ld, entry, "sudoRunAs");
1183 for (p = bv; *p != NULL; p++) {
1185 lbuf_append(lbuf, ", ", NULL);
1186 lbuf_append(lbuf, (*p)->bv_val, NULL);
1188 ldap_value_free_len(bv);
1190 lbuf_append(lbuf, def_runas_default, NULL);
1192 /* get the RunAsGroup Values from the entry */
1193 bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
1195 lbuf_append(lbuf, " : ", NULL);
1196 for (p = bv; *p != NULL; p++) {
1198 lbuf_append(lbuf, ", ", NULL);
1199 lbuf_append(lbuf, (*p)->bv_val, NULL);
1201 ldap_value_free_len(bv);
1203 lbuf_append(lbuf, ") ", NULL);
1205 /* get the Option Values from the entry */
1206 bv = ldap_get_values_len(ld, entry, "sudoOption");
1210 for (p = bv; *p != NULL; p++) {
1215 if (strcmp(cp, "authenticate") == 0)
1216 tag = (*p)->bv_val[0] == '!' ?
1217 "NOPASSWD: " : "PASSWD: ";
1218 else if (strcmp(cp, "noexec") == 0)
1219 tag = (*p)->bv_val[0] == '!' ?
1220 "EXEC: " : "NOEXEC: ";
1221 else if (strcmp(cp, "setenv") == 0)
1222 tag = (*p)->bv_val[0] == '!' ?
1223 "NOSETENV: " : "SETENV: ";
1225 lbuf_append(lbuf, tag, NULL);
1226 /* XXX - ignores other options */
1228 ldap_value_free_len(bv);
1231 /* get the Command Values from the entry */
1232 bv = ldap_get_values_len(ld, entry, "sudoCommand");
1234 for (p = bv; *p != NULL; p++) {
1236 lbuf_append(lbuf, ", ", NULL);
1237 lbuf_append(lbuf, (*p)->bv_val, NULL);
1240 ldap_value_free_len(bv);
1243 lbuf_print(lbuf); /* forces a newline */
1248 * Print a record in the long form.
1251 sudo_ldap_display_entry_long(ld, entry, lbuf)
1256 struct berval **bv, **p;
1260 /* extract the dn, only show the first rdn */
1261 rdn = sudo_ldap_get_first_rdn(ld, entry);
1262 lbuf_print(lbuf); /* force a newline */
1263 lbuf_append(lbuf, "LDAP Role: ", rdn ? rdn : "UNKNOWN", NULL);
1268 /* get the RunAsUser Values from the entry */
1269 lbuf_append(lbuf, " RunAsUsers: ", NULL);
1270 bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
1272 bv = ldap_get_values_len(ld, entry, "sudoRunAs");
1274 for (p = bv; *p != NULL; p++) {
1276 lbuf_append(lbuf, ", ", NULL);
1277 lbuf_append(lbuf, (*p)->bv_val, NULL);
1279 ldap_value_free_len(bv);
1281 lbuf_append(lbuf, def_runas_default, NULL);
1284 /* get the RunAsGroup Values from the entry */
1285 bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
1287 lbuf_append(lbuf, " RunAsGroups: ", NULL);
1288 for (p = bv; *p != NULL; p++) {
1290 lbuf_append(lbuf, ", ", NULL);
1291 lbuf_append(lbuf, (*p)->bv_val, NULL);
1293 ldap_value_free_len(bv);
1297 /* get the Option Values from the entry */
1298 bv = ldap_get_values_len(ld, entry, "sudoOption");
1300 lbuf_append(lbuf, " Options: ", NULL);
1301 for (p = bv; *p != NULL; p++) {
1303 lbuf_append(lbuf, ", ", NULL);
1304 lbuf_append(lbuf, (*p)->bv_val, NULL);
1306 ldap_value_free_len(bv);
1310 /* get the Command Values from the entry */
1311 bv = ldap_get_values_len(ld, entry, "sudoCommand");
1313 lbuf_append(lbuf, " Commands:", NULL);
1315 for (p = bv; *p != NULL; p++) {
1316 lbuf_append(lbuf, "\t", (*p)->bv_val, NULL);
1320 ldap_value_free_len(bv);
1327 * Like sudo_ldap_lookup(), except we just print entries.
1330 sudo_ldap_display_privs(nss, pw, lbuf)
1331 struct sudo_nss *nss;
1335 LDAP *ld = (LDAP *) nss->handle;
1336 LDAPMessage *entry = NULL, *result = NULL;
1338 int rc, do_netgr, count = 0;
1344 * Okay - time to search for anything that matches this user
1345 * Lets limit it to only two queries of the LDAP server
1347 * The first pass will look by the username, groups, and
1348 * the keyword ALL. We will then inspect the results that
1349 * came back from the query. We don't need to inspect the
1350 * sudoUser in this pass since the LDAP server already scanned
1353 * The second pass will return all the entries that contain
1354 * user netgroups. Then we take the netgroups returned and
1355 * try to match them against the username.
1357 for (do_netgr = 0; do_netgr < 2; do_netgr++) {
1358 filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
1359 DPRINTF(("ldap search '%s'", filt), 1);
1360 rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
1361 NULL, 0, NULL, NULL, NULL, -1, &result);
1363 if (rc != LDAP_SUCCESS)
1364 continue; /* no entries for this pass */
1366 /* print each matching entry */
1367 LDAP_FOREACH(entry, ld, result) {
1369 sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
1370 sudo_ldap_check_host(ld, entry)) {
1373 count += sudo_ldap_display_entry_long(ld, entry, lbuf);
1375 count += sudo_ldap_display_entry_short(ld, entry, lbuf);
1378 ldap_msgfree(result);
1385 sudo_ldap_display_cmnd(nss, pw)
1386 struct sudo_nss *nss;
1389 LDAP *ld = (LDAP *) nss->handle;
1390 LDAPMessage *entry = NULL, *result = NULL; /* used for searches */
1391 char *filt; /* used to parse attributes */
1392 int rc, found, do_netgr; /* temp/final return values */
1398 * Okay - time to search for anything that matches this user
1399 * Lets limit it to only two queries of the LDAP server
1401 * The first pass will look by the username, groups, and
1402 * the keyword ALL. We will then inspect the results that
1403 * came back from the query. We don't need to inspect the
1404 * sudoUser in this pass since the LDAP server already scanned
1407 * The second pass will return all the entries that contain
1408 * user netgroups. Then we take the netgroups returned and
1409 * try to match them against the username.
1411 for (found = FALSE, do_netgr = 0; !found && do_netgr < 2; do_netgr++) {
1412 filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
1413 DPRINTF(("ldap search '%s'", filt), 1);
1414 rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
1415 NULL, 0, NULL, NULL, NULL, -1, &result);
1417 if (rc != LDAP_SUCCESS)
1418 continue; /* no entries for this pass */
1420 LDAP_FOREACH(entry, ld, result) {
1422 sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
1423 sudo_ldap_check_host(ld, entry) &&
1424 sudo_ldap_check_command(ld, entry, NULL) &&
1425 sudo_ldap_check_runas(ld, entry)) {
1431 ldap_msgfree(result);
1436 printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
1437 user_args ? " " : "", user_args ? user_args : "");
1441 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1443 sudo_ldap_sasl_interact(ld, flags, _auth_id, _interact)
1449 char *auth_id = (char *)_auth_id;
1450 sasl_interact_t *interact = (sasl_interact_t *)_interact;
1452 for (; interact->id != SASL_CB_LIST_END; interact++) {
1453 if (interact->id != SASL_CB_USER)
1454 return(LDAP_PARAM_ERROR);
1456 if (auth_id != NULL)
1457 interact->result = auth_id;
1458 else if (interact->defresult != NULL)
1459 interact->result = interact->defresult;
1461 interact->result = "";
1463 interact->len = strlen(interact->result);
1464 #if SASL_VERSION_MAJOR < 2
1465 interact->result = estrdup(interact->result);
1466 #endif /* SASL_VERSION_MAJOR < 2 */
1468 return(LDAP_SUCCESS);
1470 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
1473 * Set LDAP options based on the config table.
1476 sudo_ldap_set_options(ld)
1479 struct ldap_config_table *cur;
1482 /* Set ber options */
1483 #ifdef LBER_OPT_DEBUG_LEVEL
1484 if (ldap_conf.ldap_debug)
1485 ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug);
1488 /* Set simple LDAP options */
1489 for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
1494 if (cur->opt_val == -1)
1497 conn = cur->connected ? ld : NULL;
1498 switch (cur->type) {
1501 ival = *(int *)(cur->valp);
1503 rc = ldap_set_option(conn, cur->opt_val, &ival);
1504 if (rc != LDAP_OPT_SUCCESS) {
1505 warningx("ldap_set_option: %s -> %d: %s",
1506 cur->conf_str, ival, ldap_err2string(rc));
1509 DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
1513 sval = *(char **)(cur->valp);
1515 rc = ldap_set_option(conn, cur->opt_val, sval);
1516 if (rc != LDAP_OPT_SUCCESS) {
1517 warningx("ldap_set_option: %s -> %s: %s",
1518 cur->conf_str, sval, ldap_err2string(rc));
1521 DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
1527 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1528 /* Convert bind_timelimit to a timeval */
1529 if (ldap_conf.bind_timelimit > 0) {
1531 tv.tv_sec = ldap_conf.bind_timelimit / 1000;
1533 rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
1534 if (rc != LDAP_OPT_SUCCESS) {
1535 warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
1536 (long)tv.tv_sec, ldap_err2string(rc));
1539 DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)\n",
1540 (long)tv.tv_sec), 1);
1544 #if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT)
1545 if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
1546 int val = LDAP_OPT_X_TLS_HARD;
1547 rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
1548 if (rc != LDAP_SUCCESS) {
1549 warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
1550 ldap_err2string(rc));
1553 DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)\n"), 1);
1560 * Connect to the LDAP server specified by ld
1563 sudo_ldap_bind_s(ld)
1567 const char *old_ccname = user_ccname;
1568 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
1569 unsigned int status;
1572 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1573 if (ldap_conf.rootuse_sasl == TRUE ||
1574 (ldap_conf.rootuse_sasl != FALSE && ldap_conf.use_sasl == TRUE)) {
1575 void *auth_id = ldap_conf.rootsasl_auth_id ?
1576 ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id;
1578 if (ldap_conf.krb5_ccname != NULL) {
1579 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
1580 if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname)
1581 != GSS_S_COMPLETE) {
1583 DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
1586 sudo_setenv("KRB5CCNAME", ldap_conf.krb5_ccname, TRUE);
1589 rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI",
1590 NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id);
1591 if (ldap_conf.krb5_ccname != NULL) {
1592 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
1593 if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE)
1594 DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
1596 if (old_ccname != NULL)
1597 sudo_setenv("KRB5CCNAME", old_ccname, TRUE);
1599 sudo_unsetenv("KRB5CCNAME");
1602 if (rc != LDAP_SUCCESS) {
1603 warningx("ldap_sasl_interactive_bind_s(): %s", ldap_err2string(rc));
1606 DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1);
1608 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
1609 #ifdef HAVE_LDAP_SASL_BIND_S
1613 bv.bv_val = ldap_conf.bindpw ? ldap_conf.bindpw : "";
1614 bv.bv_len = strlen(bv.bv_val);
1616 rc = ldap_sasl_bind_s(ld, ldap_conf.binddn, LDAP_SASL_SIMPLE, &bv,
1618 if (rc != LDAP_SUCCESS) {
1619 warningx("ldap_sasl_bind_s(): %s", ldap_err2string(rc));
1622 DPRINTF(("ldap_sasl_bind_s() ok"), 1);
1626 rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw);
1627 if (rc != LDAP_SUCCESS) {
1628 warningx("ldap_simple_bind_s(): %s", ldap_err2string(rc));
1631 DPRINTF(("ldap_simple_bind_s() ok"), 1);
1638 * Open a connection to the LDAP server.
1639 * Returns 0 on success and non-zero on failure.
1643 struct sudo_nss *nss;
1646 int rc, ldapnoinit = FALSE;
1648 if (!sudo_ldap_read_config())
1651 /* Prevent reading of user ldaprc and system defaults. */
1652 if (getenv("LDAPNOINIT") == NULL) {
1654 sudo_setenv("LDAPNOINIT", "1", TRUE);
1657 /* Connect to LDAP server */
1658 #ifdef HAVE_LDAP_INITIALIZE
1659 if (ldap_conf.uri != NULL) {
1660 DPRINTF(("ldap_initialize(ld, %s)", ldap_conf.uri), 2);
1661 rc = ldap_initialize(&ld, ldap_conf.uri);
1664 rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);
1665 if (rc != LDAP_SUCCESS) {
1666 warningx("unable to initialize LDAP: %s", ldap_err2string(rc));
1671 sudo_unsetenv("LDAPNOINIT");
1673 /* Set LDAP options */
1674 if (sudo_ldap_set_options(ld) < 0)
1677 if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
1678 #ifdef HAVE_LDAP_START_TLS_S
1679 rc = ldap_start_tls_s(ld, NULL, NULL);
1680 if (rc != LDAP_SUCCESS) {
1681 warningx("ldap_start_tls_s(): %s", ldap_err2string(rc));
1684 DPRINTF(("ldap_start_tls_s() ok"), 1);
1686 warningx("start_tls specified but LDAP libs do not support ldap_start_tls_s()");
1687 #endif /* HAVE_LDAP_START_TLS_S */
1690 /* Actually connect */
1691 if (sudo_ldap_bind_s(ld) != 0)
1699 sudo_ldap_setdefs(nss)
1700 struct sudo_nss *nss;
1702 LDAP *ld = (LDAP *) nss->handle;
1703 LDAPMessage *entry = NULL, *result = NULL; /* used for searches */
1704 int rc; /* temp return value */
1709 rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
1710 "cn=defaults", NULL, 0, NULL, NULL, NULL, -1, &result);
1711 if (rc == 0 && (entry = ldap_first_entry(ld, result))) {
1712 DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
1713 sudo_ldap_parse_options(ld, entry);
1715 DPRINTF(("no default options found!"), 1);
1718 ldap_msgfree(result);
1724 * like sudoers_lookup() - only LDAP style
1727 sudo_ldap_lookup(nss, ret, pwflag)
1728 struct sudo_nss *nss;
1732 LDAP *ld = (LDAP *) nss->handle;
1733 LDAPMessage *entry = NULL, *result = NULL;
1735 int do_netgr, rc, matched;
1737 int ldap_user_matches = FALSE, ldap_host_matches = FALSE;
1738 struct passwd *pw = list_pw ? list_pw : sudo_user.pw;
1744 int doauth = UNSPEC;
1745 enum def_tupple pwcheck =
1746 (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
1748 for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) {
1749 filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
1750 rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
1751 NULL, 0, NULL, NULL, NULL, -1, &result);
1753 if (rc != LDAP_SUCCESS)
1756 LDAP_FOREACH(entry, ld, result) {
1757 /* only verify netgroup matches in pass 2 */
1758 if (do_netgr && !sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name))
1761 ldap_user_matches = TRUE;
1762 if (sudo_ldap_check_host(ld, entry)) {
1763 ldap_host_matches = TRUE;
1764 if ((pwcheck == any && doauth != FALSE) ||
1765 (pwcheck == all && doauth == FALSE))
1766 doauth = sudo_ldap_check_bool(ld, entry, "authenticate");
1767 /* Only check the command when listing another user. */
1768 if (user_uid == 0 || list_pw == NULL ||
1769 user_uid == list_pw->pw_uid ||
1770 sudo_ldap_check_command(ld, entry, NULL)) {
1772 break; /* end foreach */
1776 ldap_msgfree(result);
1779 if (matched || user_uid == 0) {
1780 SET(ret, VALIDATE_OK);
1781 CLR(ret, VALIDATE_NOT_OK);
1782 if (def_authenticate) {
1785 SET(ret, FLAG_CHECK_USER);
1789 if (doauth == FALSE)
1790 def_authenticate = FALSE;
1793 def_authenticate = FALSE;
1804 * Okay - time to search for anything that matches this user
1805 * Lets limit it to only two queries of the LDAP server
1807 * The first pass will look by the username, groups, and
1808 * the keyword ALL. We will then inspect the results that
1809 * came back from the query. We don't need to inspect the
1810 * sudoUser in this pass since the LDAP server already scanned
1813 * The second pass will return all the entries that contain
1814 * user netgroups. Then we take the netgroups returned and
1815 * try to match them against the username.
1817 setenv_implied = FALSE;
1818 for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) {
1819 filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
1820 DPRINTF(("ldap search '%s'", filt), 1);
1821 rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
1822 NULL, 0, NULL, NULL, NULL, -1, &result);
1823 if (rc != LDAP_SUCCESS)
1824 DPRINTF(("nothing found for '%s'", filt), 1);
1827 /* parse each entry returned from this most recent search */
1828 if (rc == LDAP_SUCCESS) {
1829 LDAP_FOREACH(entry, ld, result) {
1830 DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
1832 /* first verify user netgroup matches - only if in pass 2 */
1833 (!do_netgr || sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
1834 /* remember that user matched */
1835 (ldap_user_matches = TRUE) &&
1836 /* verify host match */
1837 sudo_ldap_check_host(ld, entry) &&
1838 /* remember that host matched */
1839 (ldap_host_matches = TRUE) &&
1840 /* verify runas match */
1841 sudo_ldap_check_runas(ld, entry) &&
1842 /* verify command match */
1843 (rc = sudo_ldap_check_command(ld, entry, &setenv_implied)) != UNSPEC
1845 /* We have a match! */
1846 DPRINTF(("Command %sallowed", rc == TRUE ? "" : "NOT "), 1);
1849 /* pick up any options */
1852 sudo_ldap_parse_options(ld, entry);
1854 /* Set role and type if not specified on command line. */
1855 if (user_role == NULL)
1856 user_role = def_role;
1857 if (user_type == NULL)
1858 user_type = def_type;
1859 #endif /* HAVE_SELINUX */
1860 /* make sure we don't reenter loop */
1861 SET(ret, VALIDATE_OK);
1862 CLR(ret, VALIDATE_NOT_OK);
1864 SET(ret, VALIDATE_NOT_OK);
1865 CLR(ret, VALIDATE_OK);
1867 /* break from inside for loop */
1871 ldap_msgfree(result);
1877 DPRINTF(("user_matches=%d", ldap_user_matches), 1);
1878 DPRINTF(("host_matches=%d", ldap_host_matches), 1);
1880 if (!ISSET(ret, VALIDATE_OK)) {
1881 /* we do not have a match */
1882 if (pwflag && list_pw == NULL)
1883 SET(ret, FLAG_NO_CHECK);
1885 if (ldap_user_matches)
1886 CLR(ret, FLAG_NO_USER);
1887 if (ldap_host_matches)
1888 CLR(ret, FLAG_NO_HOST);
1889 DPRINTF(("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret), 1);
1895 * shut down LDAP connection
1898 sudo_ldap_close(nss)
1899 struct sudo_nss *nss;
1901 if (nss->handle != NULL) {
1902 ldap_unbind_ext_s((LDAP *) nss->handle, NULL, NULL);
1912 sudo_ldap_parse(nss)
1913 struct sudo_nss *nss;