man pages get built in the build- directories
[debian/sudo] / ldap.c
1 /*
2  * Copyright (c) 2003-2008 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * This code is derived from software contributed by Aaron Spangler.
5  *
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.
9  *
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.
17  */
18
19 #include <config.h>
20
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <sys/param.h>
24 #include <sys/stat.h>
25 #include <stdio.h>
26 #ifdef STDC_HEADERS
27 # include <stdlib.h>
28 # include <stddef.h>
29 #else
30 # ifdef HAVE_STDLIB_H
31 #  include <stdlib.h>
32 # endif
33 #endif /* STDC_HEADERS */
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #else
37 # ifdef HAVE_STRINGS_H
38 #  include <strings.h>
39 # endif
40 #endif /* HAVE_STRING_H */
41 #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
42 # include <malloc.h>
43 #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
44 #ifdef HAVE_UNISTD_H
45 # include <unistd.h>
46 #endif /* HAVE_UNISTD_H */
47 #include <ctype.h>
48 #include <pwd.h>
49 #include <grp.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #include <netdb.h>
53 #ifdef HAVE_LBER_H
54 # include <lber.h>
55 #endif
56 #include <ldap.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>
61 #endif
62 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
63 # ifdef HAVE_SASL_SASL_H
64 #  include <sasl/sasl.h>
65 # else
66 #  include <sasl.h>
67 # endif
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>
74 #  else
75 #   include <gssapi.h>
76 #  endif
77 # endif
78 #endif
79
80 #include "sudo.h"
81 #include "parse.h"
82 #include "lbuf.h"
83
84 #ifndef lint
85 __unused static const char rcsid[] = "$Sudo: ldap.c,v 1.100 2008/04/23 12:30:07 millert Exp $";
86 #endif /* lint */
87
88 #ifndef LDAP_OPT_SUCCESS
89 # define LDAP_OPT_SUCCESS LDAP_SUCCESS
90 #endif
91
92 #ifndef LDAPS_PORT
93 # define LDAPS_PORT 636
94 #endif
95
96 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && !defined(LDAP_SASL_QUIET)
97 # define LDAP_SASL_QUIET        0
98 #endif
99
100 #ifndef HAVE_LDAP_UNBIND_EXT_S
101 #define ldap_unbind_ext_s(a, b, c)      ldap_unbind_s(a)
102 #endif
103
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)
107 #endif
108
109 #define LDAP_FOREACH(var, ld, res)                                      \
110     for ((var) = ldap_first_entry((ld), (res));                         \
111         (var) != NULL;                                                  \
112         (var) = ldap_next_entry((ld), (var)))
113
114 #define DPRINTF(args, level)    if (ldap_conf.debug >= level) warningx args
115
116 #define CONF_BOOL       0
117 #define CONF_INT        1
118 #define CONF_STR        2
119
120 #define SUDO_LDAP_SSL           1
121 #define SUDO_LDAP_STARTTLS      2
122
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 */
129 };
130
131 /* ldap configuration structure */
132 static struct ldap_config {
133     int port;
134     int version;
135     int debug;
136     int ldap_debug;
137     int tls_checkpeer;
138     int timelimit;
139     int bind_timelimit;
140     int use_sasl;
141     int rootuse_sasl;
142     int ssl_mode;
143     char *host;
144     char *uri;
145     char *binddn;
146     char *bindpw;
147     char *rootbinddn;
148     char *base;
149     char *ssl;
150     char *tls_cacertfile;
151     char *tls_cacertdir;
152     char *tls_random_file;
153     char *tls_cipher_suite;
154     char *tls_certfile;
155     char *tls_keyfile;
156     char *sasl_auth_id;
157     char *rootsasl_auth_id;
158     char *sasl_secprops;
159     char *krb5_ccname;
160 } ldap_conf;
161
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 },
171 #endif
172 #ifdef LDAP_OPT_PROTOCOL_VERSION
173     { "ldap_version", CONF_INT, TRUE, LDAP_OPT_PROTOCOL_VERSION,
174         &ldap_conf.version },
175 #endif
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 },
179 #else
180     { "tls_checkpeer", CONF_BOOL, FALSE, -1, &ldap_conf.tls_checkpeer },
181 #endif
182 #ifdef LDAP_OPT_X_TLS_CACERTFILE
183     { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
184         &ldap_conf.tls_cacertfile },
185 #endif
186 #ifdef LDAP_OPT_X_TLS_CACERTDIR
187     { "tls_cacertdir", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTDIR,
188         &ldap_conf.tls_cacertdir },
189 #endif
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 },
193 #endif
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 },
197 #endif
198 #ifdef LDAP_OPT_X_TLS_CERTFILE
199     { "tls_cert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CERTFILE,
200         &ldap_conf.tls_certfile },
201 #else
202     { "tls_cert", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
203 #endif
204 #ifdef LDAP_OPT_X_TLS_KEYFILE
205     { "tls_key", CONF_STR, FALSE, LDAP_OPT_X_TLS_KEYFILE,
206         &ldap_conf.tls_keyfile },
207 #else
208     { "tls_key", CONF_STR, FALSE, -1, &ldap_conf.tls_keyfile },
209 #endif
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 },
216 #endif
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 },
230 # endif
231     { "krb5_ccname", CONF_STR, FALSE, -1, &ldap_conf.krb5_ccname },
232 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
233     { NULL }
234 };
235
236 struct sudo_nss sudo_nss_ldap = {
237     &sudo_nss_ldap,
238     NULL,
239     sudo_ldap_open,
240     sudo_ldap_close,
241     sudo_ldap_parse,
242     sudo_ldap_setdefs,
243     sudo_ldap_lookup,
244     sudo_ldap_display_cmnd,
245     sudo_ldap_display_defaults,
246     sudo_ldap_display_bound_defaults,
247     sudo_ldap_display_privs
248 };
249
250 #ifdef HAVE_LDAP_CREATE
251 /*
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.
255  */
256 static void
257 sudo_ldap_conf_add_ports()
258 {
259
260     char *host, *port, defport[13];
261     char hostbuf[LINE_MAX * 2];
262
263     hostbuf[0] = '\0';
264     if (snprintf(defport, sizeof(defport), ":%d", ldap_conf.port) >= sizeof(defport))
265         errorx(1, "sudo_ldap_conf_add_ports: port too large");
266
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))
270                 goto toobig;
271         }
272
273         if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
274             goto toobig;
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))
278                 goto toobig;
279         }
280     }
281
282     free(ldap_conf.host);
283     ldap_conf.host = estrdup(hostbuf);
284     return;
285
286 toobig:
287     errorx(1, "sudo_ldap_conf_add_ports: out of space expanding hostbuf");
288 }
289 #endif
290
291 #ifndef HAVE_LDAP_INITIALIZE
292 /*
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.
296  */
297 static int
298 sudo_ldap_parse_uri(uri_list)
299     const char *uri_list;
300 {
301     char *buf, *uri, *host, *cp, *port;
302     char hostbuf[LINE_MAX];
303     int nldap = 0, nldaps = 0;
304     int rc = -1;
305
306     buf = estrdup(uri_list);
307     hostbuf[0] = '\0';
308     for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
309         if (strncasecmp(uri, "ldap://", 7) == 0) {
310             nldap++;
311             host = uri + 7;
312         } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
313             nldaps++;
314             host = uri + 8;
315         } else {
316             warningx("unsupported LDAP uri type: %s", uri);
317             goto done;
318         }
319
320         /* trim optional trailing slash */
321         if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
322             *cp = '\0';
323         }
324
325         if (hostbuf[0] != '\0') {
326             if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
327                 goto toobig;
328         }
329
330         if (*host == '\0')
331             host = "localhost";         /* no host specified, use localhost */
332
333         if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
334             goto toobig;
335
336         /* If using SSL and no port specified, add port 636 */
337         if (nldaps) {
338             if ((port = strrchr(host, ':')) == NULL || !isdigit(port[1]))
339                 if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
340                     goto toobig;
341         }
342     }
343     if (hostbuf[0] == '\0') {
344         warningx("invalid uri: %s", uri_list);
345         goto done;
346     }
347
348     if (nldaps != 0) {
349         if (nldap != 0) {
350             warningx("cannot mix ldap and ldaps URIs");
351             goto done;
352         }
353         if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
354             warningx("cannot mix ldaps and starttls");
355             goto done;
356         }
357         ldap_conf.ssl_mode = SUDO_LDAP_SSL;
358     }
359
360     free(ldap_conf.host);
361     ldap_conf.host = estrdup(hostbuf);
362     rc = 0;
363
364 done:
365     efree(buf);
366     return(rc);
367
368 toobig:
369     errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
370 }
371 #endif /* HAVE_LDAP_INITIALIZE */
372
373 static int
374 sudo_ldap_init(ldp, host, port)
375     LDAP **ldp;
376     const char *host;
377     int port;
378 {
379     LDAP *ld = NULL;
380     int rc = LDAP_CONNECT_ERROR;
381
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));
392             goto done;
393         }
394
395         DPRINTF(("ldapssl_init(%s, %d, 1)", host, port), 2);
396         if ((ld = ldapssl_init(host, port, 1)) != NULL)
397             rc = LDAP_SUCCESS;
398     } else
399 #endif
400     {
401 #ifdef HAVE_LDAP_CREATE
402         DPRINTF(("ldap_create()"), 2);
403         if ((rc = ldap_create(&ld)) != LDAP_SUCCESS)
404             goto done;
405         DPRINTF(("ldap_set_option(LDAP_OPT_HOST_NAME, %s)", host), 2);
406         rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, host);
407 #else
408         DPRINTF(("ldap_init(%s, %d)", host, port), 2);
409         if ((ld = ldap_init(host, port)) != NULL)
410             rc = LDAP_SUCCESS;
411 #endif
412     }
413
414 done:
415     *ldp = ld;
416     return(rc);
417 }
418
419 /*
420  * Walk through search results and return TRUE if we have a matching
421  * netgroup, else FALSE.
422  */
423 int
424 sudo_ldap_check_user_netgroup(ld, entry, user)
425     LDAP *ld;
426     LDAPMessage *entry;
427     char *user;
428 {
429     struct berval **bv, **p;
430     char *val;
431     int ret = FALSE;
432
433     if (!entry)
434         return(ret);
435
436     /* get the values from the entry */
437     bv = ldap_get_values_len(ld, entry, "sudoUser");
438     if (bv == NULL)
439         return(ret);
440
441     /* walk through values */
442     for (p = bv; *p != NULL && !ret; p++) {
443         val = (*p)->bv_val;
444         /* match any */
445         if (netgr_matches(val, NULL, NULL, user))
446             ret = TRUE;
447         DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val,
448             ret ? "MATCH!" : "not"), 2);
449     }
450
451     ldap_value_free_len(bv);    /* cleanup */
452
453     return(ret);
454 }
455
456 /*
457  * Walk through search results and return TRUE if we have a
458  * host match, else FALSE.
459  */
460 int
461 sudo_ldap_check_host(ld, entry)
462     LDAP *ld;
463     LDAPMessage *entry;
464 {
465     struct berval **bv, **p;
466     char *val;
467     int ret = FALSE;
468
469     if (!entry)
470         return(ret);
471
472     /* get the values from the entry */
473     bv = ldap_get_values_len(ld, entry, "sudoHost");
474     if (bv == NULL)
475         return(ret);
476
477     /* walk through values */
478     for (p = bv; *p != NULL && !ret; p++) {
479         val = (*p)->bv_val;
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))
484             ret = TRUE;
485         DPRINTF(("ldap sudoHost '%s' ... %s", val,
486             ret ? "MATCH!" : "not"), 2);
487     }
488
489     ldap_value_free_len(bv);    /* cleanup */
490
491     return(ret);
492 }
493
494 int
495 sudo_ldap_check_runas_user(ld, entry)
496     LDAP *ld;
497     LDAPMessage *entry;
498 {
499     struct berval **bv, **p;
500     char *val;
501     int ret = FALSE;
502
503     if (!runas_pw)
504         return(UNSPEC);
505
506     /* get the runas user from the entry */
507     bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
508     if (bv == NULL)
509         bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */
510
511     /*
512      * BUG:
513      * 
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.
520      * 
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
523      * /etc/sudoers.
524      * 
525      * Sigh - maybe add this feature later
526      */
527
528     /*
529      * If there are no runas entries, match runas_default against
530      * what the user specified on the command line.
531      */
532     if (bv == NULL)
533         return(!strcasecmp(runas_pw->pw_name, def_runas_default));
534
535     /* walk through values returned, looking for a match */
536     for (p = bv; *p != NULL && !ret; p++) {
537         val = (*p)->bv_val;
538         switch (val[0]) {
539         case '+':
540             if (netgr_matches(val, NULL, NULL, runas_pw->pw_name))
541                 ret = TRUE;
542             break;
543         case '%':
544             if (usergr_matches(val, runas_pw->pw_name, runas_pw))
545                 ret = TRUE;
546             break;
547         case 'A':
548             if (strcmp(val, "ALL") == 0) {
549                 ret = TRUE;
550                 break;
551             }
552             /* FALLTHROUGH */
553         default:
554             if (strcasecmp(val, runas_pw->pw_name) == 0)
555                 ret = TRUE;
556             break;
557         }
558         DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val,
559             ret ? "MATCH!" : "not"), 2);
560     }
561
562     ldap_value_free_len(bv);    /* cleanup */
563
564     return(ret);
565 }
566
567 int
568 sudo_ldap_check_runas_group(ld, entry)
569     LDAP *ld;
570     LDAPMessage *entry;
571 {
572     struct berval **bv, **p;
573     char *val;
574     int ret = FALSE;
575
576     /* runas_gr is only set if the user specified the -g flag */
577     if (!runas_gr)
578         return(UNSPEC);
579
580     /* get the values from the entry */
581     bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
582     if (bv == NULL)
583         return(ret);
584
585     /* walk through values returned, looking for a match */
586     for (p = bv; *p != NULL && !ret; p++) {
587         val = (*p)->bv_val;
588         if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
589             ret = TRUE;
590         DPRINTF(("ldap sudoRunAsGroup '%s' ... %s", val,
591             ret ? "MATCH!" : "not"), 2);
592     }
593
594     ldap_value_free_len(bv);    /* cleanup */
595
596     return(ret);
597 }
598
599 /*
600  * Walk through search results and return TRUE if we have a runas match,
601  * else FALSE.  RunAs info is optional.
602  */
603 int
604 sudo_ldap_check_runas(ld, entry)
605     LDAP *ld;
606     LDAPMessage *entry;
607 {
608     int ret;
609
610     if (!entry)
611         return(FALSE);
612
613     ret = sudo_ldap_check_runas_user(ld, entry) != FALSE &&
614         sudo_ldap_check_runas_group(ld, entry) != FALSE;
615
616     return(ret);
617 }
618
619 /*
620  * Walk through search results and return TRUE if we have a command match,
621  * FALSE if disallowed and UNSPEC if not matched.
622  */
623 int
624 sudo_ldap_check_command(ld, entry, setenv_implied)
625     LDAP *ld;
626     LDAPMessage *entry;
627     int *setenv_implied;
628 {
629     struct berval **bv, **p;
630     char *allowed_cmnd, *allowed_args, *val;
631     int foundbang, ret = UNSPEC;
632
633     if (!entry)
634         return(ret);
635
636     bv = ldap_get_values_len(ld, entry, "sudoCommand");
637     if (bv == NULL)
638         return(ret);
639
640     for (p = bv; *p != NULL && ret != FALSE; p++) {
641         val = (*p)->bv_val;
642         /* Match against ALL ? */
643         if (!strcmp(val, "ALL")) {
644             ret = TRUE;
645             if (setenv_implied != NULL)
646                 *setenv_implied = TRUE;
647             DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2);
648             continue;
649         }
650
651         /* check for !command */
652         if (*val == '!') {
653             foundbang = TRUE;
654             allowed_cmnd = estrdup(1 + val);    /* !command */
655         } else {
656             foundbang = FALSE;
657             allowed_cmnd = estrdup(val);        /* command */
658         }
659
660         /* split optional args away from command */
661         allowed_args = strchr(allowed_cmnd, ' ');
662         if (allowed_args)
663             *allowed_args++ = '\0';
664
665         /* check the command like normal */
666         if (command_matches(allowed_cmnd, allowed_args)) {
667             /*
668              * If allowed (no bang) set ret but keep on checking.
669              * If disallowed (bang), exit loop.
670              */
671             ret = foundbang ? FALSE : TRUE;
672         }
673         DPRINTF(("ldap sudoCommand '%s' ... %s", val,
674             ret == TRUE ? "MATCH!" : "not"), 2);
675
676         efree(allowed_cmnd);    /* cleanup */
677     }
678
679     ldap_value_free_len(bv);    /* more cleanup */
680
681     return(ret);
682 }
683
684 /*
685  * Search for boolean "option" in sudoOption.
686  * Returns TRUE if found and allowed, FALSE if negated, else UNSPEC.
687  */
688 int
689 sudo_ldap_check_bool(ld, entry, option)
690     LDAP *ld;
691     LDAPMessage *entry;
692     char *option;
693 {
694     struct berval **bv, **p;
695     char ch, *var;
696     int ret = UNSPEC;
697
698     if (entry == NULL)
699         return(UNSPEC);
700
701     bv = ldap_get_values_len(ld, entry, "sudoOption");
702     if (bv == NULL)
703         return(ret);
704
705     /* walk through options */
706     for (p = bv; *p != NULL; p++) {
707         var = (*p)->bv_val;;
708         DPRINTF(("ldap sudoOption: '%s'", var), 2);
709
710         if ((ch = *var) == '!')
711             var++;
712         if (strcmp(var, option) == 0)
713             ret = (ch != '!');
714     }
715
716     ldap_value_free_len(bv);
717
718     return(ret);
719 }
720
721 /*
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.
724  */
725 void
726 sudo_ldap_parse_options(ld, entry)
727     LDAP *ld;
728     LDAPMessage *entry;
729 {
730     struct berval **bv, **p;
731     char op, *var, *val;
732
733     if (entry == NULL)
734         return;
735
736     bv = ldap_get_values_len(ld, entry, "sudoOption");
737     if (bv == NULL)
738         return;
739
740     /* walk through options */
741     for (p = bv; *p != NULL; p++) {
742         var = estrdup((*p)->bv_val);
743         DPRINTF(("ldap sudoOption: '%s'", var), 2);
744
745         /* check for equals sign past first char */
746         val = strchr(var, '=');
747         if (val > 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);
754             } else {
755                 /* case var=val */
756                 set_default(var, val, TRUE);
757             }
758         } else if (*var == '!') {
759             /* case !var Boolean False */
760             set_default(var + 1, NULL, FALSE);
761         } else {
762             /* case var Boolean True */
763             set_default(var, NULL, TRUE);
764         }
765         efree(var);
766     }
767
768     ldap_value_free_len(bv);
769 }
770
771 /*
772  * builds together a filter to check against ldap
773  */
774 char *
775 sudo_ldap_build_pass1(pw)
776     struct passwd *pw;
777 {
778     struct group *grp;
779     size_t sz;
780     char *buf;
781     int i;
782
783     /* Start with (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
784     sz = 29 + strlen(pw->pw_name);
785
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)
791             continue;
792         if ((grp = sudo_getgrgid(user_groups[i])) != NULL)
793             sz += 12 + strlen(grp->gr_name);    /* supplementary group */
794     }
795     buf = emalloc(sz);
796
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);
801
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);
807     }
808
809     /* Append supplementary groups */
810     for (i = 0; i < user_ngroups; i++) {
811         if (user_groups[i] == pw->pw_gid)
812             continue;
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);
817         }
818     }
819
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");
823
824     return(buf);
825 }
826
827 /*
828  * Map yes/true/on to TRUE, no/false/off to FALSE, else -1
829  */
830 int
831 _atobool(s)
832     const char *s;
833 {
834     switch (*s) {
835         case 'y':
836         case 'Y':
837             if (strcasecmp(s, "yes") == 0)
838                 return(TRUE);
839             break;
840         case 't':
841         case 'T':
842             if (strcasecmp(s, "true") == 0)
843                 return(TRUE);
844             break;
845         case 'o':
846         case 'O':
847             if (strcasecmp(s, "on") == 0)
848                 return(TRUE);
849             if (strcasecmp(s, "off") == 0)
850                 return(FALSE);
851             break;
852         case 'n':
853         case 'N':
854             if (strcasecmp(s, "no") == 0)
855                 return(FALSE);
856             break;
857         case 'f':
858         case 'F':
859             if (strcasecmp(s, "false") == 0)
860                 return(FALSE);
861             break;
862     }
863     return(-1);
864 }
865
866 static void
867 sudo_ldap_read_secret(path)
868     const char *path;
869 {
870     FILE *fp;
871     char buf[LINE_MAX], *cp;
872
873     if ((fp = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
874         if (fgets(buf, sizeof(buf), fp) != NULL) {
875             if ((cp = strchr(buf, '\n')) != NULL)
876                 *cp = '\0';
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;
883         }
884         fclose(fp);
885     }
886 }
887
888 int
889 sudo_ldap_read_config()
890 {
891     FILE *fp;
892     char *cp, *keyword, *value;
893     struct ldap_config_table *cur;
894
895     /* defaults */
896     ldap_conf.version = 3;
897     ldap_conf.port = -1;
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;
903
904     if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL)
905         return(FALSE);
906
907     while ((cp = sudo_parseln(fp)) != NULL) {
908         if (*cp == '\0')
909             continue;           /* skip empty line */
910
911         /* split into keyword and value */
912         keyword = cp;
913         while (*cp && !isblank((unsigned char) *cp))
914             cp++;
915         if (*cp)
916             *cp++ = '\0';       /* terminate keyword */
917
918         /* skip whitespace before value */
919         while (isblank((unsigned char) *cp))
920             cp++;
921         value = cp;
922
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) {
926                 switch (cur->type) {
927                 case CONF_BOOL:
928                     *(int *)(cur->valp) = _atobool(value);
929                     break;
930                 case CONF_INT:
931                     *(int *)(cur->valp) = atoi(value);
932                     break;
933                 case CONF_STR:
934                     efree(*(char **)(cur->valp));
935                     *(char **)(cur->valp) = estrdup(value);
936                     break;
937                 }
938                 break;
939             }
940         }
941     }
942     fclose(fp);
943
944     if (!ldap_conf.host)
945         ldap_conf.host = estrdup("localhost");
946
947     if (ldap_conf.bind_timelimit > 0)
948         ldap_conf.bind_timelimit *= 1000;       /* convert to ms */
949
950     if (ldap_conf.debug > 1) {
951         fprintf(stderr, "LDAP Config Summary\n");
952         fprintf(stderr, "===================\n");
953         if (ldap_conf.uri) {
954             fprintf(stderr, "uri              %s\n", ldap_conf.uri);
955         } else {
956             fprintf(stderr, "host             %s\n", ldap_conf.host ?
957                 ldap_conf.host : "(NONE)");
958             fprintf(stderr, "port             %d\n", ldap_conf.port);
959         }
960         fprintf(stderr, "ldap_version     %d\n", ldap_conf.version);
961
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 ?
976                 "(yes)" : "(no)");
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)");
1002         }
1003 #endif
1004         fprintf(stderr, "===================\n");
1005     }
1006     if (!ldap_conf.base)
1007         return(FALSE);          /* if no base is defined, ignore LDAP */
1008
1009     /*
1010      * Interpret SSL option
1011      */
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;
1017     }
1018
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);
1023     }
1024 #endif
1025
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)
1030             return(FALSE);
1031         free(ldap_conf.uri);
1032         ldap_conf.uri = NULL;
1033         ldap_conf.port = LDAP_PORT;
1034     }
1035 #endif
1036
1037     if (!ldap_conf.uri) {
1038         /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
1039         if (ldap_conf.port < 0)
1040             ldap_conf.port =
1041                 ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
1042
1043 #ifdef HAVE_LDAP_CREATE
1044         /*
1045          * Cannot specify port directly to ldap_create(), each host must
1046          * include :port to override the default.
1047          */
1048         if (ldap_conf.port != LDAP_PORT)
1049             sudo_ldap_conf_add_ports();
1050 #endif
1051     }
1052
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);
1056
1057 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1058     /*
1059      * Make sure we can open the file specified by krb5_ccname.
1060      */
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);
1068                 fclose(fp);
1069             } else {
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;
1074             }
1075         }
1076     }
1077 #endif
1078     return(TRUE);
1079 }
1080
1081 /*
1082  * Extract the dn from an entry and return the first rdn from it.
1083  */
1084 static char *
1085 sudo_ldap_get_first_rdn(ld, entry)
1086     LDAP *ld;
1087     LDAPMessage *entry;
1088 {
1089 #ifdef HAVE_LDAP_STR2DN
1090     char *dn, *rdn = NULL;
1091     LDAPDN tmpDN;
1092
1093     if ((dn = ldap_get_dn(ld, entry)) == NULL)
1094         return(NULL);
1095     if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) {
1096         ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN);
1097         ldap_dnfree(tmpDN);
1098     }
1099     ldap_memfree(dn);
1100     return(rdn);
1101 #else
1102     char *dn, **edn;
1103
1104     if ((dn = ldap_get_dn(ld, entry)) == NULL)
1105         return(NULL);
1106     edn = ldap_explode_dn(dn, 1);
1107     ldap_memfree(dn);
1108     return(edn ? edn[0] : NULL);
1109 #endif
1110 }
1111
1112 /*
1113  * Fetch and display the global Options.
1114  */
1115 int
1116 sudo_ldap_display_defaults(nss, pw, lbuf)
1117     struct sudo_nss *nss;
1118     struct passwd *pw;
1119     struct lbuf *lbuf;
1120 {
1121     struct berval **bv, **p;
1122     LDAP *ld = (LDAP *) nss->handle;
1123     LDAPMessage *entry = NULL, *result = NULL;
1124     char *prefix = NULL;
1125     int rc, count = 0;
1126
1127     if (ld == NULL)
1128         return(-1);
1129
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");
1134         if (bv != NULL) {
1135             if (lbuf->len == 0)
1136                 prefix = "    ";
1137             else
1138                 prefix = ", ";
1139             for (p = bv; *p != NULL; p++) {
1140                 lbuf_append(lbuf, prefix, (*p)->bv_val, NULL);
1141                 prefix = ", ";
1142                 count++;
1143             }
1144             ldap_value_free_len(bv);
1145         }
1146     }
1147     if (result)
1148         ldap_msgfree(result);
1149     return(count);
1150 }
1151
1152 /*
1153  * STUB
1154  */
1155 int
1156 sudo_ldap_display_bound_defaults(nss, pw, lbuf)
1157     struct sudo_nss *nss;
1158     struct passwd *pw;
1159     struct lbuf *lbuf;
1160 {
1161     return(1);
1162 }
1163
1164 /*
1165  * Print a record in the short form, ala file sudoers.
1166  */
1167 int
1168 sudo_ldap_display_entry_short(ld, entry, lbuf)
1169     LDAP *ld;
1170     LDAPMessage *entry;
1171     struct lbuf *lbuf;
1172 {
1173     struct berval **bv, **p;
1174     int count = 0;
1175
1176     lbuf_append(lbuf, "    (", NULL);
1177
1178     /* get the RunAsUser Values from the entry */
1179     bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
1180     if (bv == NULL)
1181         bv = ldap_get_values_len(ld, entry, "sudoRunAs");
1182     if (bv != NULL) {
1183         for (p = bv; *p != NULL; p++) {
1184             if (p != bv)
1185                 lbuf_append(lbuf, ", ", NULL);
1186             lbuf_append(lbuf, (*p)->bv_val, NULL);
1187         }
1188         ldap_value_free_len(bv);
1189     } else
1190         lbuf_append(lbuf, def_runas_default, NULL);
1191
1192     /* get the RunAsGroup Values from the entry */
1193     bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
1194     if (bv != NULL) {
1195         lbuf_append(lbuf, " : ", NULL);
1196         for (p = bv; *p != NULL; p++) {
1197             if (p != bv)
1198                 lbuf_append(lbuf, ", ", NULL);
1199             lbuf_append(lbuf, (*p)->bv_val, NULL);
1200         }
1201         ldap_value_free_len(bv);
1202     }
1203     lbuf_append(lbuf, ") ", NULL);
1204
1205     /* get the Option Values from the entry */
1206     bv = ldap_get_values_len(ld, entry, "sudoOption");
1207     if (bv != NULL) {
1208         char *cp, *tag;
1209
1210         for (p = bv; *p != NULL; p++) {
1211             cp = (*p)->bv_val;
1212             if (*cp == '!')
1213                 cp++;
1214             tag = NULL;
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: ";
1224             if (tag != NULL)
1225                 lbuf_append(lbuf, tag, NULL);
1226             /* XXX - ignores other options */
1227         }
1228         ldap_value_free_len(bv);
1229     }
1230
1231     /* get the Command Values from the entry */
1232     bv = ldap_get_values_len(ld, entry, "sudoCommand");
1233     if (bv != NULL) {
1234         for (p = bv; *p != NULL; p++) {
1235             if (p != bv)
1236                 lbuf_append(lbuf, ", ", NULL);
1237             lbuf_append(lbuf, (*p)->bv_val, NULL);
1238             count++;
1239         }
1240         ldap_value_free_len(bv);
1241     }
1242
1243     lbuf_print(lbuf);           /* forces a newline */
1244     return(count);
1245 }
1246
1247 /*
1248  * Print a record in the long form.
1249  */
1250 int
1251 sudo_ldap_display_entry_long(ld, entry, lbuf)
1252     LDAP *ld;
1253     LDAPMessage *entry;
1254     struct lbuf *lbuf;
1255 {
1256     struct berval **bv, **p;
1257     char *rdn;
1258     int count = 0;
1259
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);
1264     lbuf_print(lbuf);
1265     if (rdn)
1266         ldap_memfree(rdn);
1267
1268     /* get the RunAsUser Values from the entry */
1269     lbuf_append(lbuf, "    RunAsUsers: ", NULL);
1270     bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
1271     if (bv == NULL)
1272         bv = ldap_get_values_len(ld, entry, "sudoRunAs");
1273     if (bv != NULL) {
1274         for (p = bv; *p != NULL; p++) {
1275             if (p != bv)
1276                 lbuf_append(lbuf, ", ", NULL);
1277             lbuf_append(lbuf, (*p)->bv_val, NULL);
1278         }
1279         ldap_value_free_len(bv);
1280     } else
1281         lbuf_append(lbuf, def_runas_default, NULL);
1282     lbuf_print(lbuf);
1283
1284     /* get the RunAsGroup Values from the entry */
1285     bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
1286     if (bv != NULL) {
1287         lbuf_append(lbuf, "    RunAsGroups: ", NULL);
1288         for (p = bv; *p != NULL; p++) {
1289             if (p != bv)
1290                 lbuf_append(lbuf, ", ", NULL);
1291             lbuf_append(lbuf, (*p)->bv_val, NULL);
1292         }
1293         ldap_value_free_len(bv);
1294         lbuf_print(lbuf);
1295     }
1296
1297     /* get the Option Values from the entry */
1298     bv = ldap_get_values_len(ld, entry, "sudoOption");
1299     if (bv != NULL) {
1300         lbuf_append(lbuf, "    Options: ", NULL);
1301         for (p = bv; *p != NULL; p++) {
1302             if (p != bv)
1303                 lbuf_append(lbuf, ", ", NULL);
1304             lbuf_append(lbuf, (*p)->bv_val, NULL);
1305         }
1306         ldap_value_free_len(bv);
1307         lbuf_print(lbuf);
1308     }
1309
1310     /* get the Command Values from the entry */
1311     bv = ldap_get_values_len(ld, entry, "sudoCommand");
1312     if (bv != NULL) {
1313         lbuf_append(lbuf, "    Commands:", NULL);
1314         lbuf_print(lbuf);
1315         for (p = bv; *p != NULL; p++) {
1316             lbuf_append(lbuf, "\t", (*p)->bv_val, NULL);
1317             lbuf_print(lbuf);
1318             count++;
1319         }
1320         ldap_value_free_len(bv);
1321     }
1322
1323     return(count);
1324 }
1325
1326 /*
1327  * Like sudo_ldap_lookup(), except we just print entries.
1328  */
1329 int
1330 sudo_ldap_display_privs(nss, pw, lbuf)
1331     struct sudo_nss *nss;
1332     struct passwd *pw;
1333     struct lbuf *lbuf;
1334 {
1335     LDAP *ld = (LDAP *) nss->handle;
1336     LDAPMessage *entry = NULL, *result = NULL;
1337     char *filt;
1338     int rc, do_netgr, count = 0;
1339
1340     if (ld == NULL)
1341         return(-1);
1342
1343     /*
1344      * Okay - time to search for anything that matches this user
1345      * Lets limit it to only two queries of the LDAP server
1346      *
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
1351      * it for us.
1352      *
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.
1356      */
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);
1362         efree(filt);
1363         if (rc != LDAP_SUCCESS)
1364             continue;   /* no entries for this pass */
1365
1366         /* print each matching entry */
1367         LDAP_FOREACH(entry, ld, result) {
1368             if ((!do_netgr ||
1369                 sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
1370                 sudo_ldap_check_host(ld, entry)) {
1371
1372                 if (long_list)
1373                     count += sudo_ldap_display_entry_long(ld, entry, lbuf);
1374                 else
1375                     count += sudo_ldap_display_entry_short(ld, entry, lbuf);
1376             }
1377         }
1378         ldap_msgfree(result);
1379         result = NULL;
1380     }
1381     return(count);
1382 }
1383
1384 int
1385 sudo_ldap_display_cmnd(nss, pw)
1386     struct sudo_nss *nss;
1387     struct passwd *pw;
1388 {
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 */
1393
1394     if (ld == NULL)
1395         return(1);
1396
1397     /*
1398      * Okay - time to search for anything that matches this user
1399      * Lets limit it to only two queries of the LDAP server
1400      *
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
1405      * it for us.
1406      *
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.
1410      */
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);
1416         efree(filt);
1417         if (rc != LDAP_SUCCESS)
1418             continue;   /* no entries for this pass */
1419
1420         LDAP_FOREACH(entry, ld, result) {
1421             if ((!do_netgr ||
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)) {
1426
1427                 found = TRUE;
1428                 break;
1429             }
1430         }
1431         ldap_msgfree(result);
1432         result = NULL;
1433     }
1434
1435     if (found)
1436         printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
1437             user_args ? " " : "", user_args ? user_args : "");
1438    return(!found);
1439 }
1440
1441 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1442 static int
1443 sudo_ldap_sasl_interact(ld, flags, _auth_id, _interact)
1444     LDAP *ld;
1445     unsigned int flags;
1446     void *_auth_id;
1447     void *_interact;
1448 {
1449     char *auth_id = (char *)_auth_id;
1450     sasl_interact_t *interact = (sasl_interact_t *)_interact;
1451
1452     for (; interact->id != SASL_CB_LIST_END; interact++) {
1453         if (interact->id != SASL_CB_USER)
1454             return(LDAP_PARAM_ERROR);
1455
1456         if (auth_id != NULL)
1457             interact->result = auth_id;
1458         else if (interact->defresult != NULL)
1459             interact->result = interact->defresult;
1460         else
1461             interact->result = "";
1462
1463         interact->len = strlen(interact->result);
1464 #if SASL_VERSION_MAJOR < 2
1465         interact->result = estrdup(interact->result);
1466 #endif /* SASL_VERSION_MAJOR < 2 */
1467     }
1468     return(LDAP_SUCCESS);
1469 }
1470 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
1471
1472 /*
1473  * Set LDAP options based on the config table.
1474  */
1475 int
1476 sudo_ldap_set_options(ld)
1477     LDAP *ld;
1478 {
1479     struct ldap_config_table *cur;
1480     int rc;
1481
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);
1486 #endif
1487
1488     /* Set simple LDAP options */
1489     for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
1490         LDAP *conn;
1491         int ival;
1492         char *sval;
1493
1494         if (cur->opt_val == -1)
1495             continue;
1496
1497         conn = cur->connected ? ld : NULL;
1498         switch (cur->type) {
1499         case CONF_BOOL:
1500         case CONF_INT:
1501             ival = *(int *)(cur->valp);
1502             if (ival >= 0) {
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));
1507                     return(-1);
1508                 }
1509                 DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
1510             }
1511             break;
1512         case CONF_STR:
1513             sval = *(char **)(cur->valp);
1514             if (sval != NULL) {
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));
1519                     return(-1);
1520                 }
1521                 DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
1522             }
1523             break;
1524         }
1525     }
1526
1527 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1528     /* Convert bind_timelimit to a timeval */
1529     if (ldap_conf.bind_timelimit > 0) {
1530         struct timeval tv;
1531         tv.tv_sec = ldap_conf.bind_timelimit / 1000;
1532         tv.tv_usec = 0;
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));
1537             return(-1);
1538         }
1539         DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)\n",
1540             (long)tv.tv_sec), 1);
1541     }
1542 #endif
1543
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));
1551             return(-1);
1552         }
1553         DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)\n"), 1);
1554     }
1555 #endif
1556     return(0);
1557 }
1558
1559 /*
1560  * Connect to the LDAP server specified by ld
1561  */
1562 static int
1563 sudo_ldap_bind_s(ld)
1564     LDAP *ld;
1565 {
1566     int rc;
1567     const char *old_ccname = user_ccname;
1568 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
1569     unsigned int status;
1570 #endif
1571
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;
1577
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) {
1582                 old_ccname = NULL;
1583                 DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
1584             }
1585 #else
1586             sudo_setenv("KRB5CCNAME", ldap_conf.krb5_ccname, TRUE);
1587 #endif
1588         }
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);
1595 #else
1596             if (old_ccname != NULL)
1597                 sudo_setenv("KRB5CCNAME", old_ccname, TRUE);
1598             else
1599                 sudo_unsetenv("KRB5CCNAME");
1600 #endif
1601         }
1602         if (rc != LDAP_SUCCESS) {
1603             warningx("ldap_sasl_interactive_bind_s(): %s", ldap_err2string(rc));
1604             return(-1);
1605         }
1606         DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1);
1607     } else
1608 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
1609 #ifdef HAVE_LDAP_SASL_BIND_S
1610     {
1611         struct berval bv;
1612
1613         bv.bv_val = ldap_conf.bindpw ? ldap_conf.bindpw : "";
1614         bv.bv_len = strlen(bv.bv_val);
1615
1616         rc = ldap_sasl_bind_s(ld, ldap_conf.binddn, LDAP_SASL_SIMPLE, &bv,
1617             NULL, NULL, NULL);
1618         if (rc != LDAP_SUCCESS) {
1619             warningx("ldap_sasl_bind_s(): %s", ldap_err2string(rc));
1620             return(-1);
1621         }
1622         DPRINTF(("ldap_sasl_bind_s() ok"), 1);
1623     }
1624 #else
1625     {
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));
1629             return(-1);
1630         }
1631         DPRINTF(("ldap_simple_bind_s() ok"), 1);
1632     }
1633 #endif
1634     return(0);
1635 }
1636
1637 /*
1638  * Open a connection to the LDAP server.
1639  * Returns 0 on success and non-zero on failure.
1640  */
1641 int
1642 sudo_ldap_open(nss)
1643     struct sudo_nss *nss;
1644 {
1645     LDAP *ld;
1646     int rc, ldapnoinit = FALSE;
1647
1648     if (!sudo_ldap_read_config())
1649         return(-1);
1650
1651     /* Prevent reading of user ldaprc and system defaults. */
1652     if (getenv("LDAPNOINIT") == NULL) {
1653         ldapnoinit = TRUE;
1654         sudo_setenv("LDAPNOINIT", "1", TRUE);
1655     }
1656
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);
1662     } else
1663 #endif
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));
1667         return(-1);
1668     }
1669
1670     if (ldapnoinit)
1671         sudo_unsetenv("LDAPNOINIT");
1672
1673     /* Set LDAP options */
1674     if (sudo_ldap_set_options(ld) < 0)
1675         return(-1);
1676
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));
1682             return(-1);
1683         }
1684         DPRINTF(("ldap_start_tls_s() ok"), 1);
1685 #else
1686         warningx("start_tls specified but LDAP libs do not support ldap_start_tls_s()");
1687 #endif /* HAVE_LDAP_START_TLS_S */
1688     }
1689
1690     /* Actually connect */
1691     if (sudo_ldap_bind_s(ld) != 0)
1692         return(-1);
1693
1694     nss->handle = ld;
1695     return(0);
1696 }
1697
1698 int
1699 sudo_ldap_setdefs(nss)
1700     struct sudo_nss *nss;
1701 {
1702     LDAP *ld = (LDAP *) nss->handle;
1703     LDAPMessage *entry = NULL, *result = NULL;   /* used for searches */
1704     int rc;                                      /* temp return value */
1705
1706     if (ld == NULL)
1707         return(-1);
1708
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);
1714     } else
1715         DPRINTF(("no default options found!"), 1);
1716
1717     if (result)
1718         ldap_msgfree(result);
1719
1720     return(0);
1721 }
1722
1723 /*
1724  * like sudoers_lookup() - only LDAP style
1725  */
1726 int
1727 sudo_ldap_lookup(nss, ret, pwflag)
1728     struct sudo_nss *nss;
1729     int ret;
1730     int pwflag;
1731 {
1732     LDAP *ld = (LDAP *) nss->handle;
1733     LDAPMessage *entry = NULL, *result = NULL;
1734     char *filt;
1735     int do_netgr, rc, matched;
1736     int setenv_implied;
1737     int ldap_user_matches = FALSE, ldap_host_matches = FALSE;
1738     struct passwd *pw = list_pw ? list_pw : sudo_user.pw;
1739
1740     if (ld == NULL)
1741         return(ret);
1742
1743     if (pwflag) {
1744         int doauth = UNSPEC;
1745         enum def_tupple pwcheck = 
1746             (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
1747
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);
1752             efree(filt);
1753             if (rc != LDAP_SUCCESS)
1754                 continue;
1755
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))
1759                     continue;
1760
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)) {
1771                         matched = 1;
1772                         break;  /* end foreach */
1773                     }
1774                 }
1775             }
1776             ldap_msgfree(result);
1777             result = NULL;
1778         }
1779         if (matched || user_uid == 0) {
1780             SET(ret, VALIDATE_OK);
1781             CLR(ret, VALIDATE_NOT_OK);
1782             if (def_authenticate) {
1783                 switch (pwcheck) {
1784                     case always:
1785                         SET(ret, FLAG_CHECK_USER);
1786                         break;
1787                     case all:
1788                     case any:
1789                         if (doauth == FALSE)
1790                             def_authenticate = FALSE;
1791                         break;
1792                     case never:
1793                         def_authenticate = FALSE;
1794                         break;
1795                     default:
1796                         break;
1797                 }
1798             }
1799         }
1800         goto done;
1801     }
1802
1803     /*
1804      * Okay - time to search for anything that matches this user
1805      * Lets limit it to only two queries of the LDAP server
1806      *
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
1811      * it for us.
1812      *
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.
1816      */
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);
1825         efree(filt);
1826
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);
1831                 if (
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
1844                     ) {
1845                     /* We have a match! */
1846                     DPRINTF(("Command %sallowed", rc == TRUE ? "" : "NOT "), 1);
1847                     matched = TRUE;
1848                     if (rc == TRUE) {
1849                         /* pick up any options */
1850                         if (setenv_implied)
1851                             def_setenv = TRUE;
1852                         sudo_ldap_parse_options(ld, entry);
1853 #ifdef HAVE_SELINUX
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);
1863                     } else {
1864                         SET(ret, VALIDATE_NOT_OK);
1865                         CLR(ret, VALIDATE_OK);
1866                     }
1867                     /* break from inside for loop */
1868                     break;
1869                 }
1870             }
1871             ldap_msgfree(result);
1872             result = NULL;
1873         }
1874     }
1875
1876 done:
1877     DPRINTF(("user_matches=%d", ldap_user_matches), 1);
1878     DPRINTF(("host_matches=%d", ldap_host_matches), 1);
1879
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);
1884     }
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);
1890
1891     return(ret);
1892 }
1893
1894 /*
1895  * shut down LDAP connection
1896  */
1897 int
1898 sudo_ldap_close(nss)
1899     struct sudo_nss *nss;
1900 {
1901     if (nss->handle != NULL) {
1902         ldap_unbind_ext_s((LDAP *) nss->handle, NULL, NULL);
1903         nss->handle = NULL;
1904     }
1905     return(0);
1906 }
1907
1908 /*
1909  * STUB
1910  */
1911 int
1912 sudo_ldap_parse(nss)
1913     struct sudo_nss *nss;
1914 {
1915     return(0);
1916 }