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 */
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
57 # include "emul/err.h"
58 #endif /* HAVE_ERR_H */
64 #if defined(HAVE_LDAP_SSL_H)
65 # include <ldap_ssl.h>
66 #elif defined(HAVE_MPS_LDAP_SSL_H)
67 # include <mps/ldap_ssl.h>
74 __unused static const char rcsid[] = "$Sudo: ldap.c,v 1.11.2.38 2008/04/11 14:03:51 millert Exp $";
78 # define LINE_MAX 2048
81 #ifndef LDAP_OPT_SUCCESS
82 # define LDAP_OPT_SUCCESS LDAP_SUCCESS
86 # define LDAPS_PORT 636
89 #define DPRINTF(args, level) if (ldap_conf.debug >= level) warnx args
95 #define SUDO_LDAP_SSL 1
96 #define SUDO_LDAP_STARTTLS 2
98 struct ldap_config_table {
99 const char *conf_str; /* config file string */
100 short type; /* CONF_BOOL, CONF_INT, CONF_STR */
101 short connected; /* connection-specific value? */
102 int opt_val; /* LDAP_OPT_* (or -1 for sudo internal) */
103 void *valp; /* pointer into ldap_conf */
106 /* ldap configuration structure */
123 char *tls_cacertfile;
125 char *tls_random_file;
126 char *tls_cipher_suite;
131 struct ldap_config_table ldap_conf_table[] = {
132 { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug },
133 { "host", CONF_STR, FALSE, -1, &ldap_conf.host },
134 { "port", CONF_INT, FALSE, -1, &ldap_conf.port },
135 { "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl },
136 { "sslpath", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
137 { "uri", CONF_STR, FALSE, -1, &ldap_conf.uri },
138 #ifdef LDAP_OPT_DEBUG_LEVEL
139 { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
141 #ifdef LDAP_OPT_PROTOCOL_VERSION
142 { "ldap_version", CONF_INT, TRUE, LDAP_OPT_PROTOCOL_VERSION,
143 &ldap_conf.version },
145 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
146 { "tls_checkpeer", CONF_BOOL, FALSE, LDAP_OPT_X_TLS_REQUIRE_CERT,
147 &ldap_conf.tls_checkpeer },
149 { "tls_checkpeer", CONF_BOOL, FALSE, -1, &ldap_conf.tls_checkpeer },
151 #ifdef LDAP_OPT_X_TLS_CACERTFILE
152 { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
153 &ldap_conf.tls_cacertfile },
155 #ifdef LDAP_OPT_X_TLS_CACERTDIR
156 { "tls_cacertdir", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTDIR,
157 &ldap_conf.tls_cacertdir },
159 #ifdef LDAP_OPT_X_TLS_RANDOM_FILE
160 { "tls_randfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_RANDOM_FILE,
161 &ldap_conf.tls_random_file },
163 #ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
164 { "tls_ciphers", CONF_STR, FALSE, LDAP_OPT_X_TLS_CIPHER_SUITE,
165 &ldap_conf.tls_cipher_suite },
167 #ifdef LDAP_OPT_X_TLS_CERTFILE
168 { "tls_cert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CERTFILE,
169 &ldap_conf.tls_certfile },
171 { "tls_cert", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
173 #ifdef LDAP_OPT_X_TLS_KEYFILE
174 { "tls_key", CONF_STR, FALSE, LDAP_OPT_X_TLS_KEYFILE,
175 &ldap_conf.tls_keyfile },
177 { "tls_key", CONF_STR, FALSE, -1, &ldap_conf.tls_keyfile },
179 #ifdef LDAP_OPT_NETWORK_TIMEOUT
180 { "bind_timelimit", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
181 &ldap_conf.bind_timelimit },
182 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
183 { "bind_timelimit", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT,
184 &ldap_conf.bind_timelimit },
186 { "timelimit", CONF_INT, TRUE, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit },
187 { "binddn", CONF_STR, FALSE, -1, &ldap_conf.binddn },
188 { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw },
189 { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
190 { "sudoers_base", CONF_STR, FALSE, -1, &ldap_conf.base },
194 static void sudo_ldap_update_defaults __P((LDAP *));
195 static void sudo_ldap_close __P((LDAP *));
196 static LDAP *sudo_ldap_open __P((void));
198 #ifndef HAVE_LDAP_INITIALIZE
200 * For each uri, convert to host:port pairs. For ldaps:// enable SSL
201 * Accepts: uris of the form ldap:/// or ldap://hostname:portnum/
202 * where the trailing slash is optional.
205 sudo_ldap_parse_uri(uri_list)
206 const char *uri_list;
208 char *buf, *uri, *host, *cp, *port;
209 char hostbuf[LINE_MAX];
210 int nldap = 0, nldaps = 0;
213 buf = estrdup(uri_list);
215 for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
216 if (strncasecmp(uri, "ldap://", 7) == 0) {
219 } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
223 warnx("unsupported LDAP uri type: %s", uri);
227 /* trim optional trailing slash */
228 if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
232 if (hostbuf[0] != '\0') {
233 if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
238 host = "localhost"; /* no host specified, use localhost */
240 if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
243 /* If using SSL and no port specified, add port 636 */
245 if ((port = strrchr(host, ':')) == NULL || !isdigit(port[1]))
246 if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
250 if (hostbuf[0] == '\0') {
251 warnx("invalid uri: %s", uri_list);
257 warnx("cannot mix ldap and ldaps URIs");
260 if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
261 warnx("cannot mix ldaps and starttls");
264 ldap_conf.ssl_mode = SUDO_LDAP_SSL;
267 free(ldap_conf.host);
268 ldap_conf.host = estrdup(hostbuf);
276 errx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
278 #endif /* HAVE_LDAP_INITIALIZE */
281 sudo_ldap_init(ldp, host, port)
287 int rc = LDAP_CONNECT_ERROR;
289 #ifdef HAVE_LDAPSSL_INIT
290 if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
291 DPRINTF(("ldapssl_clientauth_init(%s, %s)",
292 ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
293 ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
294 rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
295 ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
296 if (rc != LDAP_SUCCESS) {
297 warnx("unable to initialize SSL cert and key db: %s",
298 ldapssl_err2string(rc));
302 DPRINTF(("ldapssl_init(%s, %d, 1)", host, port), 2);
303 if ((ld = ldapssl_init(host, port, 1)) == NULL)
308 DPRINTF(("ldap_init(%s, %d)", host, port), 2);
309 if ((ld = ldap_init(host, port)) == NULL)
320 * Walk through search results and return TRUE if we have a matching
321 * netgroup, else FALSE.
324 sudo_ldap_check_user_netgroup(ld, entry)
328 char **v = NULL, **p = NULL;
334 /* get the values from the entry */
335 v = ldap_get_values(ld, entry, "sudoUser");
337 /* walk through values */
338 for (p = v; p && *p && !ret; p++) {
340 if (netgr_matches(*p, NULL, NULL, user_name))
342 DPRINTF(("ldap sudoUser netgroup '%s' ... %s", *p,
343 ret ? "MATCH!" : "not"), 2);
347 ldap_value_free(v); /* cleanup */
353 * Walk through search results and return TRUE if we have a
354 * host match, else FALSE.
357 sudo_ldap_check_host(ld, entry)
361 char **v = NULL, **p = NULL;
367 /* get the values from the entry */
368 v = ldap_get_values(ld, entry, "sudoHost");
370 /* walk through values */
371 for (p = v; p && *p && !ret; p++) {
372 /* match any or address or netgroup or hostname */
373 if (!strcmp(*p, "ALL") || addr_matches(*p) ||
374 netgr_matches(*p, user_host, user_shost, NULL) ||
375 !hostname_matches(user_shost, user_host, *p))
377 DPRINTF(("ldap sudoHost '%s' ... %s", *p,
378 ret ? "MATCH!" : "not"), 2);
382 ldap_value_free(v); /* cleanup */
388 * Walk through search results and return TRUE if we have a runas match,
390 * Since the runas directive in /etc/sudoers is optional, so is sudoRunAs.
393 sudo_ldap_check_runas(ld, entry)
397 char **v = NULL, **p = NULL;
403 /* get the values from the entry */
404 v = ldap_get_values(ld, entry, "sudoRunAs");
409 * if runas is not specified on the command line, the only information
410 * as to which user to run as is in the runas_default option. We should
411 * check to see if we have the local option present. Unfortunately we
412 * don't parse these options until after this routine says yes or no.
413 * The query has already returned, so we could peek at the attribute
414 * values here though.
416 * For now just require users to always use -u option unless its set
417 * in the global defaults. This behaviour is no different than the global
420 * Sigh - maybe add this feature later
425 * If there are no runas entries, match runas_default against
426 * what the user specified on the command line.
429 ret = !strcasecmp(runas_pw->pw_name, def_runas_default);
431 /* walk through values returned, looking for a match */
432 for (p = v; p && *p && !ret; p++) {
435 if (netgr_matches(*p, NULL, NULL, runas_pw->pw_name))
439 if (usergr_matches(*p, runas_pw->pw_name, runas_pw))
443 if (strcmp(*p, "ALL") == 0) {
449 if (strcasecmp(*p, runas_pw->pw_name) == 0)
453 DPRINTF(("ldap sudoRunAs '%s' ... %s", *p,
454 ret ? "MATCH!" : "not"), 2);
458 ldap_value_free(v); /* cleanup */
464 * Walk through search results and return TRUE if we have a command match.
467 sudo_ldap_check_command(ld, entry, setenv_implied)
472 char *allowed_cmnd, *allowed_args, **v = NULL, **p = NULL;
473 int foundbang, ret = FALSE;
478 v = ldap_get_values(ld, entry, "sudoCommand");
480 /* get_first_entry */
481 for (p = v; p && *p && ret >= 0; p++) {
482 /* Match against ALL ? */
483 if (!strcmp(*p, "ALL")) {
485 if (setenv_implied != NULL)
486 *setenv_implied = TRUE;
487 DPRINTF(("ldap sudoCommand '%s' ... MATCH!", *p), 2);
491 /* check for !command */
494 allowed_cmnd = estrdup(1 + *p); /* !command */
497 allowed_cmnd = estrdup(*p); /* command */
500 /* split optional args away from command */
501 allowed_args = strchr(allowed_cmnd, ' ');
503 *allowed_args++ = '\0';
505 /* check the command like normal */
506 if (command_matches(allowed_cmnd, allowed_args)) {
508 * If allowed (no bang) set ret but keep on checking.
509 * If disallowed (bang), exit loop.
511 ret = foundbang ? -1 : TRUE;
513 DPRINTF(("ldap sudoCommand '%s' ... %s", *p,
514 ret == TRUE ? "MATCH!" : "not"), 2);
516 efree(allowed_cmnd); /* cleanup */
520 ldap_value_free(v); /* more cleanup */
522 /* return TRUE if we found at least one ALLOW and no DENY */
527 * Read sudoOption and modify the defaults as we go. This is used once
528 * from the cn=defaults entry and also once when a final sudoRole is matched.
531 sudo_ldap_parse_options(ld, entry)
535 char op, *var, *val, **v = NULL, **p = NULL;
540 v = ldap_get_values(ld, entry, "sudoOption");
542 /* walk through options */
543 for (p = v; p && *p; p++) {
545 DPRINTF(("ldap sudoOption: '%s'", *p), 2);
548 /* check for equals sign past first char */
549 val = strchr(var, '=');
551 *val++ = '\0'; /* split on = and truncate var */
552 op = *(val - 2); /* peek for += or -= cases */
553 if (op == '+' || op == '-') {
554 *(val - 2) = '\0'; /* found, remove extra char */
555 /* case var+=val or var-=val */
556 set_default(var, val, (int) op);
559 set_default(var, val, TRUE);
561 } else if (*var == '!') {
562 /* case !var Boolean False */
563 set_default(var + 1, NULL, FALSE);
565 /* case var Boolean True */
566 set_default(var, NULL, TRUE);
576 * Concatenate strings, dynamically growing them as necessary.
577 * Strings can be arbitrarily long and are allocated/reallocated on
578 * the fly. Make sure to free them when you are done.
585 * ncat(&s,&sz,"This ");
586 * ncat(&s,&sz,"is ");
587 * ncat(&s,&sz,"an ");
588 * ncat(&s,&sz,"arbitrarily ");
589 * ncat(&s,&sz,"long ");
590 * ncat(&s,&sz,"string!");
592 * printf("String Value='%s', but has %d bytes allocated\n",s,sz);
603 /* handle initial alloc */
606 *sz = strlen(src) + 1;
610 nsz = strlen(*s) + strlen(src) + 1;
612 *s = erealloc((void *) *s, *sz = nsz * 2);
613 strlcat(*s, src, *sz);
617 * builds together a filter to check against ldap
620 sudo_ldap_build_pass1()
630 /* build filter sudoUser=user_name */
631 ncat(&b, &sz, "(sudoUser=");
632 ncat(&b, &sz, user_name);
635 /* Append primary group */
636 grp = getgrgid(user_gid);
638 ncat(&b, &sz, "(sudoUser=%");
639 ncat(&b, &sz, grp -> gr_name);
643 /* Append supplementary groups */
644 for (i = 0; i < user_ngroups; i++) {
645 if (user_groups[i] == user_gid)
647 if ((grp = getgrgid(user_groups[i])) != NULL) {
648 ncat(&b, &sz, "(sudoUser=%");
649 ncat(&b, &sz, grp -> gr_name);
654 /* Add ALL to list */
655 ncat(&b, &sz, "(sudoUser=ALL)");
664 * Map yes/true/on to TRUE, no/false/off to FALSE, else -1
673 if (strcasecmp(s, "yes") == 0)
678 if (strcasecmp(s, "true") == 0)
683 if (strcasecmp(s, "on") == 0)
685 if (strcasecmp(s, "off") == 0)
690 if (strcasecmp(s, "no") == 0)
695 if (strcasecmp(s, "false") == 0)
703 sudo_ldap_read_config()
706 char buf[LINE_MAX], *c, *keyword, *value;
707 struct ldap_config_table *cur;
710 ldap_conf.version = 3;
712 ldap_conf.tls_checkpeer = -1;
713 ldap_conf.timelimit = -1;
714 ldap_conf.bind_timelimit = -1;
716 if ((f = fopen(_PATH_LDAP_CONF, "r")) == NULL)
719 while (fgets(buf, sizeof(buf), f)) {
720 /* ignore text after comment character */
721 if ((c = strchr(buf, '#')) != NULL)
724 /* skip leading whitespace */
725 for (c = buf; isspace((unsigned char) *c); c++)
728 if (*c == '\0' || *c == '\n')
729 continue; /* skip empty line */
731 /* properly terminate keyword string */
733 while (*c && !isspace((unsigned char) *c))
736 *c++ = '\0'; /* terminate keyword */
738 /* skip whitespace before value */
739 while (isspace((unsigned char) *c))
743 /* trim whitespace after value */
745 c++; /* wind to end */
746 while (--c > value && isspace((unsigned char) *c))
749 /* Look up keyword in config table. */
750 for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
751 if (strcasecmp(keyword, cur->conf_str) == 0) {
754 *(int *)(cur->valp) = _atobool(value);
757 *(int *)(cur->valp) = atoi(value);
760 efree(*(char **)(cur->valp));
761 *(char **)(cur->valp) = estrdup(value);
771 ldap_conf.host = "localhost";
773 if (ldap_conf.bind_timelimit > 0)
774 ldap_conf.bind_timelimit *= 1000; /* convert to ms */
776 if (ldap_conf.debug > 1) {
777 fprintf(stderr, "LDAP Config Summary\n");
778 fprintf(stderr, "===================\n");
780 fprintf(stderr, "uri %s\n", ldap_conf.uri);
782 fprintf(stderr, "host %s\n", ldap_conf.host ?
783 ldap_conf.host : "(NONE)");
784 fprintf(stderr, "port %d\n", ldap_conf.port);
786 fprintf(stderr, "ldap_version %d\n", ldap_conf.version);
788 fprintf(stderr, "sudoers_base %s\n", ldap_conf.base ?
789 ldap_conf.base : "(NONE) <---Sudo will ignore ldap)");
790 fprintf(stderr, "binddn %s\n", ldap_conf.binddn ?
791 ldap_conf.binddn : "(anonymous)");
792 fprintf(stderr, "bindpw %s\n", ldap_conf.bindpw ?
793 ldap_conf.bindpw : "(anonymous)");
794 if (ldap_conf.bind_timelimit > 0)
795 fprintf(stderr, "bind_timelimit %d\n", ldap_conf.bind_timelimit);
796 if (ldap_conf.timelimit > 0)
797 fprintf(stderr, "timelimit %d\n", ldap_conf.timelimit);
798 fprintf(stderr, "ssl %s\n", ldap_conf.ssl ?
799 ldap_conf.ssl : "(no)");
800 if (ldap_conf.tls_checkpeer != -1)
801 fprintf(stderr, "tls_checkpeer %s\n", ldap_conf.tls_checkpeer ?
803 if (ldap_conf.tls_cacertfile != NULL)
804 fprintf(stderr, "tls_cacertfile %s\n", ldap_conf.tls_cacertfile);
805 if (ldap_conf.tls_cacertdir != NULL)
806 fprintf(stderr, "tls_cacertdir %s\n", ldap_conf.tls_cacertdir);
807 if (ldap_conf.tls_random_file != NULL)
808 fprintf(stderr, "tls_random_file %s\n", ldap_conf.tls_random_file);
809 if (ldap_conf.tls_cipher_suite != NULL)
810 fprintf(stderr, "tls_cipher_suite %s\n", ldap_conf.tls_cipher_suite);
811 if (ldap_conf.tls_certfile != NULL)
812 fprintf(stderr, "tls_certfile %s\n", ldap_conf.tls_certfile);
813 if (ldap_conf.tls_keyfile != NULL)
814 fprintf(stderr, "tls_keyfile %s\n", ldap_conf.tls_keyfile);
815 fprintf(stderr, "===================\n");
818 return(FALSE); /* if no base is defined, ignore LDAP */
821 * Interpret SSL option
823 if (ldap_conf.ssl != NULL) {
824 if (strcasecmp(ldap_conf.ssl, "start_tls") == 0)
825 ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS;
826 else if (_atobool(ldap_conf.ssl))
827 ldap_conf.ssl_mode = SUDO_LDAP_SSL;
830 #if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
831 if (ldap_conf.tls_checkpeer != -1) {
832 ldapssl_set_strength(NULL,
833 ldap_conf.tls_checkpeer ? LDAPSSL_AUTH_CERT : LDAPSSL_AUTH_WEAK);
837 #ifndef HAVE_LDAP_INITIALIZE
838 /* Convert uri list to host list if no ldap_initialize(). */
840 if (sudo_ldap_parse_uri(ldap_conf.uri) != 0)
843 ldap_conf.uri = NULL;
844 ldap_conf.port = LDAP_PORT;
848 /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
849 if (!ldap_conf.uri && ldap_conf.port < 0)
851 ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
853 /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
854 if (ldap_conf.rootbinddn) {
855 if ((f = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
856 if (fgets(buf, sizeof(buf), f) != NULL) {
857 /* removing trailing newlines */
858 for (c = buf; *c != '\0'; c++)
860 while (--c > buf && *c == '\n')
862 /* copy to bindpw and binddn */
863 efree(ldap_conf.bindpw);
864 ldap_conf.bindpw = estrdup(buf);
865 efree(ldap_conf.binddn);
866 ldap_conf.binddn = ldap_conf.rootbinddn;
867 ldap_conf.rootbinddn = NULL;
876 * like perl's join(sep,@ARGS)
879 _ldap_join_values(sep, v)
883 char *b = NULL, **p = NULL;
886 /* paste values together */
887 for (p = v; p && *p; p++) {
888 if (p != v && sep != NULL)
889 ncat(&b, &sz, sep); /* append separator */
890 ncat(&b, &sz, *p); /* append value */
895 /* something went wrong, put something here */
896 ncat(&b, &sz, "(empty list)"); /* append value */
902 char *sudo_ldap_cm_list = NULL;
903 size_t sudo_ldap_cm_list_size;
905 #define SAVE_LIST(x) ncat(&sudo_ldap_cm_list,&sudo_ldap_cm_list_size,(x))
907 * Walks through search result and returns TRUE if we have a
911 sudo_ldap_add_match(ld, entry, pwflag)
916 char *dn, **edn, **v = NULL;
918 /* if we are not collecting matches, then don't save them */
919 if (pwflag != I_LISTPW)
922 /* collect the dn, only show the rdn */
923 dn = ldap_get_dn(ld, entry);
924 edn = dn ? ldap_explode_dn(dn, 1) : NULL;
925 SAVE_LIST("\nLDAP Role: ");
926 SAVE_LIST((edn && *edn) ? *edn : "UNKNOWN");
931 ldap_value_free(edn);
933 /* get the Runas Values from the entry */
934 v = ldap_get_values(ld, entry, "sudoRunAs");
936 SAVE_LIST(" RunAs: (");
937 SAVE_LIST(_ldap_join_values(", ", v));
943 /* get the Command Values from the entry */
944 v = ldap_get_values(ld, entry, "sudoCommand");
946 SAVE_LIST(" Commands:\n ");
947 SAVE_LIST(_ldap_join_values("\n ", v));
950 SAVE_LIST(" Commands: NONE\n");
955 return(FALSE); /* Don't stop at the first match */
960 sudo_ldap_list_matches()
962 if (sudo_ldap_cm_list != NULL)
963 printf("%s", sudo_ldap_cm_list);
967 * Set LDAP options based on the config table.
970 sudo_ldap_set_options(ld)
973 struct ldap_config_table *cur;
976 /* Set ber options */
977 #ifdef LBER_OPT_DEBUG_LEVEL
978 if (ldap_conf.ldap_debug)
979 ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug);
982 /* Set simple LDAP options */
983 for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
988 if (cur->opt_val == -1)
991 conn = cur->connected ? ld : NULL;
995 ival = *(int *)(cur->valp);
997 rc = ldap_set_option(conn, cur->opt_val, &ival);
998 if (rc != LDAP_OPT_SUCCESS) {
999 warnx("ldap_set_option: %s -> %d: %s",
1000 cur->conf_str, ival, ldap_err2string(rc));
1003 DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
1007 sval = *(char **)(cur->valp);
1009 rc = ldap_set_option(conn, cur->opt_val, sval);
1010 if (rc != LDAP_OPT_SUCCESS) {
1011 warnx("ldap_set_option: %s -> %s: %s",
1012 cur->conf_str, sval, ldap_err2string(rc));
1015 DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
1021 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1022 /* Convert bind_timelimit to a timeval */
1023 if (ldap_conf.bind_timelimit > 0) {
1025 tv.tv_sec = ldap_conf.bind_timelimit / 1000;
1027 rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
1028 if (rc != LDAP_OPT_SUCCESS) {
1029 warnx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
1030 (long)tv.tv_sec, ldap_err2string(rc));
1033 DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)\n",
1034 (long)tv.tv_sec), 1);
1038 #if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT)
1039 if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
1040 int val = LDAP_OPT_X_TLS_HARD;
1041 rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
1042 if (rc != LDAP_SUCCESS) {
1043 warnx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
1044 ldap_err2string(rc));
1047 DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)\n"), 1);
1054 * Open a connection to the LDAP server.
1062 if (!sudo_ldap_read_config())
1065 /* Connect to LDAP server */
1066 #ifdef HAVE_LDAP_INITIALIZE
1067 if (ldap_conf.uri != NULL) {
1068 DPRINTF(("ldap_initialize(ld, %s)", ldap_conf.uri), 2);
1069 rc = ldap_initialize(&ld, ldap_conf.uri);
1071 #endif /* HAVE_LDAP_INITIALIZE */
1072 rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);
1073 if (rc != LDAP_SUCCESS) {
1074 warnx("unable to initialize LDAP: %s", ldap_err2string(rc));
1078 /* Set LDAP options */
1079 if (sudo_ldap_set_options(ld) < 0)
1082 if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
1083 #ifdef HAVE_LDAP_START_TLS_S
1084 rc = ldap_start_tls_s(ld, NULL, NULL);
1085 if (rc != LDAP_SUCCESS) {
1086 warnx("ldap_start_tls_s(): %s", ldap_err2string(rc));
1090 DPRINTF(("ldap_start_tls_s() ok"), 1);
1092 warnx("start_tls specified but LDAP libs do not support ldap_start_tls_s()");
1093 #endif /* HAVE_LDAP_START_TLS_S */
1096 /* Actually connect */
1097 if ((rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw))) {
1098 warnx("ldap_simple_bind_s: %s", ldap_err2string(rc));
1101 DPRINTF(("ldap_simple_bind_s() ok"), 1);
1107 sudo_ldap_update_defaults(ld)
1110 LDAPMessage *entry = NULL, *result = NULL; /* used for searches */
1111 int rc; /* temp return value */
1113 rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
1114 "cn=defaults", NULL, 0, &result);
1115 if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
1116 DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
1117 sudo_ldap_parse_options(ld, entry);
1119 DPRINTF(("no default options found!"), 1);
1122 ldap_msgfree(result);
1126 * like sudoers_lookup() - only LDAP style
1129 sudo_ldap_check(pwflag)
1133 LDAPMessage *entry = NULL, *result = NULL; /* used for searches */
1134 char *filt; /* used to parse attributes */
1135 int rc, ret = FALSE, do_netgr; /* temp/final return values */
1137 int ldap_user_matches = FALSE, ldap_host_matches = FALSE; /* flags */
1139 /* Open a connection to the LDAP server. */
1140 if ((ld = sudo_ldap_open()) == NULL)
1141 return(VALIDATE_ERROR);
1143 /* Parse Default options. */
1144 sudo_ldap_update_defaults(ld);
1147 * Okay - time to search for anything that matches this user
1148 * Lets limit it to only two queries of the LDAP server
1150 * The first pass will look by the username, groups, and
1151 * the keyword ALL. We will then inspect the results that
1152 * came back from the query. We don't need to inspect the
1153 * sudoUser in this pass since the LDAP server already scanned
1156 * The second pass will return all the entries that contain
1157 * user netgroups. Then we take the netgroups returned and
1158 * try to match them against the username.
1160 setenv_implied = FALSE;
1161 for (do_netgr = 0; !ret && do_netgr < 2; do_netgr++) {
1162 filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1();
1163 DPRINTF(("ldap search '%s'", filt), 1);
1164 rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
1166 if (rc != LDAP_SUCCESS)
1167 DPRINTF(("nothing found for '%s'", filt), 1);
1170 /* parse each entry returned from this most recent search */
1171 entry = rc ? NULL : ldap_first_entry(ld, result);
1172 while (entry != NULL) {
1173 DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
1175 /* first verify user netgroup matches - only if in pass 2 */
1176 (!do_netgr || sudo_ldap_check_user_netgroup(ld, entry)) &&
1177 /* remember that user matched */
1178 (ldap_user_matches = -1) &&
1179 /* verify host match */
1180 sudo_ldap_check_host(ld, entry) &&
1181 /* remember that host matched */
1182 (ldap_host_matches = -1) &&
1183 /* add matches for listing later */
1184 sudo_ldap_add_match(ld, entry, pwflag) &&
1185 /* verify command match */
1186 sudo_ldap_check_command(ld, entry, &setenv_implied) &&
1187 /* verify runas match */
1188 sudo_ldap_check_runas(ld, entry)
1190 /* We have a match! */
1191 DPRINTF(("Perfect Matched!"), 1);
1192 /* pick up any options */
1195 sudo_ldap_parse_options(ld, entry);
1197 /* Set role and type if not specified on command line. */
1198 if (user_role == NULL)
1199 user_role = def_role;
1200 if (user_type == NULL)
1201 user_type = def_type;
1202 #endif /* HAVE_SELINUX */
1203 /* make sure we don't reenter loop */
1205 /* break from inside for loop */
1208 entry = ldap_next_entry(ld, entry);
1211 ldap_msgfree(result);
1215 sudo_ldap_close(ld); /* shut down connection */
1217 DPRINTF(("user_matches=%d", ldap_user_matches), 1);
1218 DPRINTF(("host_matches=%d", ldap_host_matches), 1);
1220 /* Check for special case for -v, -k, -l options */
1221 if (pwflag && ldap_user_matches && ldap_host_matches) {
1223 * Handle verifypw & listpw
1225 * To be extra paranoid, since we haven't read any NOPASSWD options
1226 * in /etc/sudoers yet, but we have to make the decission now, lets
1227 * assume the worst and prefer to prompt for password unless the setting
1228 * is "never". (example verifypw=never or listpw=never)
1233 SET(ret, FLAG_NOPASS); /* -k or -K */
1235 switch (sudo_defs_table[pwflag].sd_un.tuple) {
1237 SET(ret, FLAG_NOPASS);
1240 if (def_authenticate)
1241 SET(ret, FLAG_CHECK_USER);
1248 if (ISSET(ret, VALIDATE_OK)) {
1249 /* we have a match, should we check the password? */
1250 if (!def_authenticate)
1251 SET(ret, FLAG_NOPASS);
1253 SET(ret, FLAG_NOEXEC);
1255 SET(ret, FLAG_SETENV);
1257 /* we do not have a match */
1258 ret = VALIDATE_NOT_OK;
1260 SET(ret, FLAG_NO_CHECK);
1261 else if (!ldap_user_matches)
1262 SET(ret, FLAG_NO_USER);
1263 else if (!ldap_host_matches)
1264 SET(ret, FLAG_NO_HOST);
1266 DPRINTF(("sudo_ldap_check(%d)=0x%02x", pwflag, ret), 1);
1272 * shut down LDAP connection
1275 sudo_ldap_close(LDAP *ld)