Merge commit 'upstream/1.8.3'
[debian/sudo] / plugins / sudoers / ldap.c
1 /*
2  * Copyright (c) 2003-2011 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 #endif /* HAVE_STRING_H */
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif /* HAVE_STRINGS_H */
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif /* HAVE_UNISTD_H */
43 #if TIME_WITH_SYS_TIME
44 # include <time.h>
45 #endif
46 #include <ctype.h>
47 #include <pwd.h>
48 #include <grp.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <netdb.h>
52 #ifdef HAVE_LBER_H
53 # include <lber.h>
54 #endif
55 #include <ldap.h>
56 #if defined(HAVE_LDAP_SSL_H)
57 # include <ldap_ssl.h>
58 #elif defined(HAVE_MPS_LDAP_SSL_H)
59 # include <mps/ldap_ssl.h>
60 #endif
61 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
62 # ifdef HAVE_SASL_SASL_H
63 #  include <sasl/sasl.h>
64 # else
65 #  include <sasl.h>
66 # endif
67 # if HAVE_GSS_KRB5_CCACHE_NAME
68 #  if defined(HAVE_GSSAPI_GSSAPI_KRB5_H)
69 #   include <gssapi/gssapi.h>
70 #   include <gssapi/gssapi_krb5.h>
71 #  elif defined(HAVE_GSSAPI_GSSAPI_H)
72 #   include <gssapi/gssapi.h>
73 #  else
74 #   include <gssapi.h>
75 #  endif
76 # endif
77 #endif
78
79 #include "sudoers.h"
80 #include "parse.h"
81 #include "lbuf.h"
82
83 #ifndef LDAP_OPT_SUCCESS
84 # define LDAP_OPT_SUCCESS LDAP_SUCCESS
85 #endif
86
87 #ifndef LDAPS_PORT
88 # define LDAPS_PORT 636
89 #endif
90
91 #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && !defined(LDAP_SASL_QUIET)
92 # define LDAP_SASL_QUIET        0
93 #endif
94
95 #ifndef HAVE_LDAP_UNBIND_EXT_S
96 #define ldap_unbind_ext_s(a, b, c)      ldap_unbind_s(a)
97 #endif
98
99 #ifndef HAVE_LDAP_SEARCH_EXT_S
100 # ifdef HAVE_LDAP_SEARCH_ST
101 #  define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k)            \
102         ldap_search_st(a, b, c, d, e, f, i, k)
103 # else
104 #  define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k)            \
105         ldap_search_s(a, b, c, d, e, f, k)
106 # endif
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 #define CONF_LIST_STR   4
120 #define CONF_DEREF_VAL  5
121
122 #define SUDO_LDAP_SSL           1
123 #define SUDO_LDAP_STARTTLS      2
124
125 /* The TIMEFILTER_LENGTH includes the filter itself plus the global AND
126    wrapped around the user filter and the time filter when timed entries
127    are used. The length is computed as follows:
128        85       for the filter
129        + 2 * 13 for the now timestamp
130        +      3 for the global AND
131 */
132 #define TIMEFILTER_LENGTH       114    
133
134 /*
135  * The ldap_search structure implements a linked list of ldap and
136  * search result pointers, which allows us to remove them after
137  * all search results have been combined in memory.
138  * XXX - should probably be a tailq since we do appends
139  */
140 struct ldap_search_list {
141     LDAP *ldap;
142     LDAPMessage *searchresult;
143     struct ldap_search_list *next;
144 };
145
146 /*
147  * The ldap_entry_wrapper structure is used to implement sorted result entries.
148  * A double is used for the order to allow for insertion of new entries
149  * without having to renumber everything.
150  * Note: there is no standard floating point type in LDAP.
151  *       As a result, some LDAP servers will only allow an integer.
152  */
153 struct ldap_entry_wrapper {
154     LDAPMessage *entry;
155     double order;
156 };
157
158 /*
159  * The ldap_result structure contains the list of matching searches as
160  * well as an array of all result entries sorted by the sudoOrder attribute.
161  */
162 struct ldap_result {
163     struct ldap_search_list *searches;
164     struct ldap_entry_wrapper *entries;
165     int allocated_entries;
166     int nentries;
167     int user_matches;
168     int host_matches;
169 };
170 #define ALLOCATION_INCREMENT    100
171
172 struct ldap_config_table {
173     const char *conf_str;       /* config file string */
174     short type;                 /* CONF_BOOL, CONF_INT, CONF_STR */
175     short connected;            /* connection-specific value? */
176     int opt_val;                /* LDAP_OPT_* (or -1 for sudo internal) */
177     void *valp;                 /* pointer into ldap_conf */
178 };
179
180 struct ldap_config_list_str {
181     struct ldap_config_list_str *next;
182     char val[1];
183 };
184
185 /* LDAP configuration structure */
186 static struct ldap_config {
187     int port;
188     int version;
189     int debug;
190     int ldap_debug;
191     int tls_checkpeer;
192     int timelimit;
193     int timeout;
194     int bind_timelimit;
195     int use_sasl;
196     int rootuse_sasl;
197     int ssl_mode;
198     int timed;
199     int deref;
200     char *host;
201     struct ldap_config_list_str *uri;
202     char *binddn;
203     char *bindpw;
204     char *rootbinddn;
205     struct ldap_config_list_str *base;
206     char *search_filter;
207     char *ssl;
208     char *tls_cacertfile;
209     char *tls_cacertdir;
210     char *tls_random_file;
211     char *tls_cipher_suite;
212     char *tls_certfile;
213     char *tls_keyfile;
214     char *sasl_auth_id;
215     char *rootsasl_auth_id;
216     char *sasl_secprops;
217     char *krb5_ccname;
218 } ldap_conf;
219
220 static struct ldap_config_table ldap_conf_table[] = {
221     { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug },
222     { "host", CONF_STR, FALSE, -1, &ldap_conf.host },
223     { "port", CONF_INT, FALSE, -1, &ldap_conf.port },
224     { "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl },
225     { "sslpath", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
226     { "uri", CONF_LIST_STR, FALSE, -1, &ldap_conf.uri },
227 #ifdef LDAP_OPT_DEBUG_LEVEL
228     { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
229 #endif
230 #ifdef LDAP_OPT_PROTOCOL_VERSION
231     { "ldap_version", CONF_INT, TRUE, LDAP_OPT_PROTOCOL_VERSION,
232         &ldap_conf.version },
233 #endif
234 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
235     { "tls_checkpeer", CONF_BOOL, FALSE, LDAP_OPT_X_TLS_REQUIRE_CERT,
236         &ldap_conf.tls_checkpeer },
237 #else
238     { "tls_checkpeer", CONF_BOOL, FALSE, -1, &ldap_conf.tls_checkpeer },
239 #endif
240 #ifdef LDAP_OPT_X_TLS_CACERTFILE
241     { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
242         &ldap_conf.tls_cacertfile },
243     { "tls_cacert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
244         &ldap_conf.tls_cacertfile },
245 #endif
246 #ifdef LDAP_OPT_X_TLS_CACERTDIR
247     { "tls_cacertdir", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTDIR,
248         &ldap_conf.tls_cacertdir },
249 #endif
250 #ifdef LDAP_OPT_X_TLS_RANDOM_FILE
251     { "tls_randfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_RANDOM_FILE,
252         &ldap_conf.tls_random_file },
253 #endif
254 #ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
255     { "tls_ciphers", CONF_STR, FALSE, LDAP_OPT_X_TLS_CIPHER_SUITE,
256         &ldap_conf.tls_cipher_suite },
257 #endif
258 #ifdef LDAP_OPT_X_TLS_CERTFILE
259     { "tls_cert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CERTFILE,
260         &ldap_conf.tls_certfile },
261 #else
262     { "tls_cert", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
263 #endif
264 #ifdef LDAP_OPT_X_TLS_KEYFILE
265     { "tls_key", CONF_STR, FALSE, LDAP_OPT_X_TLS_KEYFILE,
266         &ldap_conf.tls_keyfile },
267 #else
268     { "tls_key", CONF_STR, FALSE, -1, &ldap_conf.tls_keyfile },
269 #endif
270 #ifdef LDAP_OPT_NETWORK_TIMEOUT
271     { "bind_timelimit", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
272         &ldap_conf.bind_timelimit },
273     { "network_timeout", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
274         &ldap_conf.bind_timelimit },
275 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
276     { "bind_timelimit", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT,
277         &ldap_conf.bind_timelimit },
278     { "network_timeout", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT,
279         &ldap_conf.bind_timelimit },
280 #endif
281     { "timelimit", CONF_INT, TRUE, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit },
282 #ifdef LDAP_OPT_TIMEOUT
283     { "timeout", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
284         &ldap_conf.timeout },
285 #endif
286 #ifdef LDAP_OPT_DEREF
287     { "deref", CONF_DEREF_VAL, TRUE, LDAP_OPT_DEREF, &ldap_conf.deref },
288 #endif
289     { "binddn", CONF_STR, FALSE, -1, &ldap_conf.binddn },
290     { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw },
291     { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
292     { "sudoers_base", CONF_LIST_STR, FALSE, -1, &ldap_conf.base },
293     { "sudoers_timed", CONF_BOOL, FALSE, -1, &ldap_conf.timed },
294     { "sudoers_search_filter", CONF_STR, FALSE, -1, &ldap_conf.search_filter },
295 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
296     { "use_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.use_sasl },
297     { "sasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.sasl_auth_id },
298     { "rootuse_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.rootuse_sasl },
299     { "rootsasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.rootsasl_auth_id },
300 # ifdef LDAP_OPT_X_SASL_SECPROPS
301     { "sasl_secprops", CONF_STR, TRUE, LDAP_OPT_X_SASL_SECPROPS,
302         &ldap_conf.sasl_secprops },
303 # endif
304     { "krb5_ccname", CONF_STR, FALSE, -1, &ldap_conf.krb5_ccname },
305 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
306     { NULL }
307 };
308
309 /* sudo_nss implementation */
310 static int sudo_ldap_open(struct sudo_nss *nss);
311 static int sudo_ldap_close(struct sudo_nss *nss);
312 static int sudo_ldap_parse(struct sudo_nss *nss);
313 static int sudo_ldap_setdefs(struct sudo_nss *nss);
314 static int sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag);
315 static int sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
316 static int sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
317     struct lbuf *lbuf);
318 static int sudo_ldap_display_bound_defaults(struct sudo_nss *nss,
319     struct passwd *pw, struct lbuf *lbuf);
320 static int sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
321     struct lbuf *lbuf);
322 static struct ldap_result *sudo_ldap_result_get(struct sudo_nss *nss,
323     struct passwd *pw);
324
325 /*
326  * LDAP sudo_nss handle.
327  * We store the connection to the LDAP server, the cached ldap_result object
328  * (if any), and the name of the user the query was performed for.
329  * If a new query is launched with sudo_ldap_result_get() that specifies a
330  * different user, the old cached result is freed before the new query is run.
331  */
332 struct sudo_ldap_handle {
333     LDAP *ld;
334     struct ldap_result *result;
335     char *username;
336     struct group_list *grlist;
337 };
338
339 struct sudo_nss sudo_nss_ldap = {
340     &sudo_nss_ldap,
341     NULL,
342     sudo_ldap_open,
343     sudo_ldap_close,
344     sudo_ldap_parse,
345     sudo_ldap_setdefs,
346     sudo_ldap_lookup,
347     sudo_ldap_display_cmnd,
348     sudo_ldap_display_defaults,
349     sudo_ldap_display_bound_defaults,
350     sudo_ldap_display_privs
351 };
352
353 #ifdef HAVE_LDAP_CREATE
354 /*
355  * Rebuild the hosts list and include a specific port for each host.
356  * ldap_create() does not take a default port parameter so we must
357  * append one if we want something other than LDAP_PORT.
358  */
359 static void
360 sudo_ldap_conf_add_ports(void)
361 {
362
363     char *host, *port, defport[13];
364     char hostbuf[LINE_MAX * 2];
365
366     hostbuf[0] = '\0';
367     if (snprintf(defport, sizeof(defport), ":%d", ldap_conf.port) >= sizeof(defport))
368         errorx(1, _("sudo_ldap_conf_add_ports: port too large"));
369
370     for ((host = strtok(ldap_conf.host, " \t")); host; (host = strtok(NULL, " \t"))) {
371         if (hostbuf[0] != '\0') {
372             if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
373                 goto toobig;
374         }
375
376         if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
377             goto toobig;
378         /* Append port if there is not one already. */
379         if ((port = strrchr(host, ':')) == NULL ||
380             !isdigit((unsigned char)port[1])) {
381             if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf))
382                 goto toobig;
383         }
384     }
385
386     efree(ldap_conf.host);
387     ldap_conf.host = estrdup(hostbuf);
388     return;
389
390 toobig:
391     errorx(1, _("sudo_ldap_conf_add_ports: out of space expanding hostbuf"));
392 }
393 #endif
394
395 #ifndef HAVE_LDAP_INITIALIZE
396 /*
397  * For each uri, convert to host:port pairs.  For ldaps:// enable SSL
398  * Accepts: uris of the form ldap:/// or ldap://hostname:portnum/
399  * where the trailing slash is optional.
400  */
401 static int
402 sudo_ldap_parse_uri(const struct ldap_config_list_str *uri_list)
403 {
404     char *buf, *uri, *host, *cp, *port;
405     char hostbuf[LINE_MAX];
406     int nldap = 0, nldaps = 0;
407     int rc = -1;
408
409     do {
410         buf = estrdup(uri_list->val);
411         hostbuf[0] = '\0';
412         for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
413             if (strncasecmp(uri, "ldap://", 7) == 0) {
414                 nldap++;
415                 host = uri + 7;
416             } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
417                 nldaps++;
418                 host = uri + 8;
419             } else {
420                 warningx(_("unsupported LDAP uri type: %s"), uri);
421                 goto done;
422             }
423
424             /* trim optional trailing slash */
425             if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
426                 *cp = '\0';
427             }
428
429             if (hostbuf[0] != '\0') {
430                 if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
431                     goto toobig;
432             }
433
434             if (*host == '\0')
435                 host = "localhost";             /* no host specified, use localhost */
436
437             if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
438                 goto toobig;
439
440             /* If using SSL and no port specified, add port 636 */
441             if (nldaps) {
442                 if ((port = strrchr(host, ':')) == NULL ||
443                     !isdigit((unsigned char)port[1]))
444                     if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
445                         goto toobig;
446             }
447         }
448         if (hostbuf[0] == '\0') {
449             warningx(_("invalid uri: %s"), uri_list);
450             goto done;
451         }
452
453         if (nldaps != 0) {
454             if (nldap != 0) {
455                 warningx(_("unable to mix ldap and ldaps URIs"));
456                 goto done;
457             }
458             if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
459                 warningx(_("unable to mix ldaps and starttls"));
460                 goto done;
461             }
462             ldap_conf.ssl_mode = SUDO_LDAP_SSL;
463         }
464
465         efree(ldap_conf.host);
466         ldap_conf.host = estrdup(hostbuf);
467         efree(buf);
468     } while ((uri_list = uri_list->next));
469
470     buf = NULL;
471     rc = 0;
472
473 done:
474     efree(buf);
475     return rc;
476
477 toobig:
478     errorx(1, _("sudo_ldap_parse_uri: out of space building hostbuf"));
479 }
480 #else
481 static char *
482 sudo_ldap_join_uri(struct ldap_config_list_str *uri_list)
483 {
484     struct ldap_config_list_str *uri;
485     size_t len = 0;
486     char *buf, *cp;
487
488     /* Usually just a single entry. */
489     if (uri_list->next == NULL)
490         return estrdup(uri_list->val);
491
492     for (uri = uri_list; uri != NULL; uri = uri->next) {
493         len += strlen(uri->val) + 1;
494     }
495     buf = cp = emalloc(len);
496     buf[0] = '\0';
497     for (uri = uri_list; uri != NULL; uri = uri->next) {
498         cp += strlcpy(cp, uri->val, len - (cp - buf));
499         *cp++ = ' ';
500     }
501     cp[-1] = '\0';
502     return buf;
503 }
504 #endif /* HAVE_LDAP_INITIALIZE */
505
506 static int
507 sudo_ldap_init(LDAP **ldp, const char *host, int port)
508 {
509     LDAP *ld = NULL;
510     int rc = LDAP_CONNECT_ERROR;
511
512 #ifdef HAVE_LDAPSSL_INIT
513     if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
514         DPRINTF(("ldapssl_clientauth_init(%s, %s)",
515             ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
516             ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
517         rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
518             ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
519         /*
520          * Mozilla-derived SDKs have a bug starting with version 5.0
521          * where the path can no longer be a file name and must be a dir.
522          */
523         if (rc != LDAP_SUCCESS) {
524             char *cp;
525             if (ldap_conf.tls_certfile) {
526                 cp = strrchr(ldap_conf.tls_certfile, '/');
527                 if (cp != NULL && strncmp(cp + 1, "cert", 4) == 0)
528                     *cp = '\0';
529             }
530             if (ldap_conf.tls_keyfile) {
531                 cp = strrchr(ldap_conf.tls_keyfile, '/');
532                 if (cp != NULL && strncmp(cp + 1, "key", 3) == 0)
533                     *cp = '\0';
534             }
535             DPRINTF(("ldapssl_clientauth_init(%s, %s)",
536                 ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
537                 ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
538             rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
539                 ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
540             if (rc != LDAP_SUCCESS) {
541                 warningx(_("unable to initialize SSL cert and key db: %s"),
542                     ldapssl_err2string(rc));
543                 goto done;
544             }
545         }
546
547         DPRINTF(("ldapssl_init(%s, %d, 1)", host, port), 2);
548         if ((ld = ldapssl_init(host, port, 1)) != NULL)
549             rc = LDAP_SUCCESS;
550     } else
551 #endif
552     {
553 #ifdef HAVE_LDAP_CREATE
554         DPRINTF(("ldap_create()"), 2);
555         if ((rc = ldap_create(&ld)) != LDAP_SUCCESS)
556             goto done;
557         DPRINTF(("ldap_set_option(LDAP_OPT_HOST_NAME, %s)", host), 2);
558         rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, host);
559 #else
560         DPRINTF(("ldap_init(%s, %d)", host, port), 2);
561         if ((ld = ldap_init(host, port)) != NULL)
562             rc = LDAP_SUCCESS;
563 #endif
564     }
565
566 done:
567     *ldp = ld;
568     return rc;
569 }
570
571 /*
572  * Walk through search results and return TRUE if we have a matching
573  * netgroup, else FALSE.
574  */
575 static int
576 sudo_ldap_check_user_netgroup(LDAP *ld, LDAPMessage *entry, char *user)
577 {
578     struct berval **bv, **p;
579     char *val;
580     int ret = FALSE;
581
582     if (!entry)
583         return ret;
584
585     /* get the values from the entry */
586     bv = ldap_get_values_len(ld, entry, "sudoUser");
587     if (bv == NULL)
588         return ret;
589
590     /* walk through values */
591     for (p = bv; *p != NULL && !ret; p++) {
592         val = (*p)->bv_val;
593         /* match any */
594         if (netgr_matches(val, NULL, NULL, user))
595             ret = TRUE;
596         DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val,
597             ret ? "MATCH!" : "not"), 2 + ((ret) ? 0 : 1));
598     }
599
600     ldap_value_free_len(bv);    /* cleanup */
601
602     return ret;
603 }
604
605 /*
606  * Walk through search results and return TRUE if we have a
607  * host match, else FALSE.
608  */
609 static int
610 sudo_ldap_check_host(LDAP *ld, LDAPMessage *entry)
611 {
612     struct berval **bv, **p;
613     char *val;
614     int ret = FALSE;
615
616     if (!entry)
617         return ret;
618
619     /* get the values from the entry */
620     bv = ldap_get_values_len(ld, entry, "sudoHost");
621     if (bv == NULL)
622         return ret;
623
624     /* walk through values */
625     for (p = bv; *p != NULL && !ret; p++) {
626         val = (*p)->bv_val;
627         /* match any or address or netgroup or hostname */
628         if (!strcmp(val, "ALL") || addr_matches(val) ||
629             netgr_matches(val, user_host, user_shost, NULL) ||
630             hostname_matches(user_shost, user_host, val))
631             ret = TRUE;
632         DPRINTF(("ldap sudoHost '%s' ... %s", val,
633             ret ? "MATCH!" : "not"), 2);
634     }
635
636     ldap_value_free_len(bv);    /* cleanup */
637
638     return ret;
639 }
640
641 static int
642 sudo_ldap_check_runas_user(LDAP *ld, LDAPMessage *entry)
643 {
644     struct berval **bv, **p;
645     char *val;
646     int ret = FALSE;
647
648     if (!runas_pw)
649         return UNSPEC;
650
651     /* get the runas user from the entry */
652     bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
653     if (bv == NULL)
654         bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */
655
656     /*
657      * BUG:
658      * 
659      * if runas is not specified on the command line, the only information
660      * as to which user to run as is in the runas_default option.  We should
661      * check to see if we have the local option present.  Unfortunately we
662      * don't parse these options until after this routine says yes or no.
663      * The query has already returned, so we could peek at the attribute
664      * values here though.
665      * 
666      * For now just require users to always use -u option unless its set
667      * in the global defaults. This behaviour is no different than the global
668      * /etc/sudoers.
669      * 
670      * Sigh - maybe add this feature later
671      */
672
673     /*
674      * If there are no runas entries, match runas_default against
675      * what the user specified on the command line.
676      */
677     if (bv == NULL)
678         return !strcasecmp(runas_pw->pw_name, def_runas_default);
679
680     /* walk through values returned, looking for a match */
681     for (p = bv; *p != NULL && !ret; p++) {
682         val = (*p)->bv_val;
683         switch (val[0]) {
684         case '+':
685             if (netgr_matches(val, NULL, NULL, runas_pw->pw_name))
686                 ret = TRUE;
687             break;
688         case '%':
689             if (usergr_matches(val, runas_pw->pw_name, runas_pw))
690                 ret = TRUE;
691             break;
692         case 'A':
693             if (strcmp(val, "ALL") == 0) {
694                 ret = TRUE;
695                 break;
696             }
697             /* FALLTHROUGH */
698         default:
699             if (strcasecmp(val, runas_pw->pw_name) == 0)
700                 ret = TRUE;
701             break;
702         }
703         DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val,
704             ret ? "MATCH!" : "not"), 2);
705     }
706
707     ldap_value_free_len(bv);    /* cleanup */
708
709     return ret;
710 }
711
712 static int
713 sudo_ldap_check_runas_group(LDAP *ld, LDAPMessage *entry)
714 {
715     struct berval **bv, **p;
716     char *val;
717     int ret = FALSE;
718
719     /* runas_gr is only set if the user specified the -g flag */
720     if (!runas_gr)
721         return UNSPEC;
722
723     /* get the values from the entry */
724     bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
725     if (bv == NULL)
726         return ret;
727
728     /* walk through values returned, looking for a match */
729     for (p = bv; *p != NULL && !ret; p++) {
730         val = (*p)->bv_val;
731         if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
732             ret = TRUE;
733         DPRINTF(("ldap sudoRunAsGroup '%s' ... %s", val,
734             ret ? "MATCH!" : "not"), 2);
735     }
736
737     ldap_value_free_len(bv);    /* cleanup */
738
739     return ret;
740 }
741
742 /*
743  * Walk through search results and return TRUE if we have a runas match,
744  * else FALSE.  RunAs info is optional.
745  */
746 static int
747 sudo_ldap_check_runas(LDAP *ld, LDAPMessage *entry)
748 {
749     int ret;
750
751     if (!entry)
752         return FALSE;
753
754     ret = sudo_ldap_check_runas_user(ld, entry) != FALSE &&
755         sudo_ldap_check_runas_group(ld, entry) != FALSE;
756
757     return ret;
758 }
759
760 /*
761  * Walk through search results and return TRUE if we have a command match,
762  * FALSE if disallowed and UNSPEC if not matched.
763  */
764 static int
765 sudo_ldap_check_command(LDAP *ld, LDAPMessage *entry, int *setenv_implied)
766 {
767     struct berval **bv, **p;
768     char *allowed_cmnd, *allowed_args, *val;
769     int foundbang, ret = UNSPEC;
770
771     if (!entry)
772         return ret;
773
774     bv = ldap_get_values_len(ld, entry, "sudoCommand");
775     if (bv == NULL)
776         return ret;
777
778     for (p = bv; *p != NULL && ret != FALSE; p++) {
779         val = (*p)->bv_val;
780         /* Match against ALL ? */
781         if (!strcmp(val, "ALL")) {
782             ret = TRUE;
783             if (setenv_implied != NULL)
784                 *setenv_implied = TRUE;
785             DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2);
786             continue;
787         }
788
789         /* check for !command */
790         if (*val == '!') {
791             foundbang = TRUE;
792             allowed_cmnd = estrdup(1 + val);    /* !command */
793         } else {
794             foundbang = FALSE;
795             allowed_cmnd = estrdup(val);        /* command */
796         }
797
798         /* split optional args away from command */
799         allowed_args = strchr(allowed_cmnd, ' ');
800         if (allowed_args)
801             *allowed_args++ = '\0';
802
803         /* check the command like normal */
804         if (command_matches(allowed_cmnd, allowed_args)) {
805             /*
806              * If allowed (no bang) set ret but keep on checking.
807              * If disallowed (bang), exit loop.
808              */
809             ret = foundbang ? FALSE : TRUE;
810         }
811         DPRINTF(("ldap sudoCommand '%s' ... %s", val,
812             ret == TRUE ? "MATCH!" : "not"), 2);
813
814         efree(allowed_cmnd);    /* cleanup */
815     }
816
817     ldap_value_free_len(bv);    /* more cleanup */
818
819     return ret;
820 }
821
822 /*
823  * Search for boolean "option" in sudoOption.
824  * Returns TRUE if found and allowed, FALSE if negated, else UNSPEC.
825  */
826 static int
827 sudo_ldap_check_bool(LDAP *ld, LDAPMessage *entry, char *option)
828 {
829     struct berval **bv, **p;
830     char ch, *var;
831     int ret = UNSPEC;
832
833     if (entry == NULL)
834         return UNSPEC;
835
836     bv = ldap_get_values_len(ld, entry, "sudoOption");
837     if (bv == NULL)
838         return ret;
839
840     /* walk through options */
841     for (p = bv; *p != NULL; p++) {
842         var = (*p)->bv_val;;
843         DPRINTF(("ldap sudoOption: '%s'", var), 2);
844
845         if ((ch = *var) == '!')
846             var++;
847         if (strcmp(var, option) == 0)
848             ret = (ch != '!');
849     }
850
851     ldap_value_free_len(bv);
852
853     return ret;
854 }
855
856 /*
857  * Read sudoOption and modify the defaults as we go.  This is used once
858  * from the cn=defaults entry and also once when a final sudoRole is matched.
859  */
860 static void
861 sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry)
862 {
863     struct berval **bv, **p;
864     char op, *var, *val;
865
866     if (entry == NULL)
867         return;
868
869     bv = ldap_get_values_len(ld, entry, "sudoOption");
870     if (bv == NULL)
871         return;
872
873     /* walk through options */
874     for (p = bv; *p != NULL; p++) {
875         var = estrdup((*p)->bv_val);
876         DPRINTF(("ldap sudoOption: '%s'", var), 2);
877
878         /* check for equals sign past first char */
879         val = strchr(var, '=');
880         if (val > var) {
881             *val++ = '\0';      /* split on = and truncate var */
882             op = *(val - 2);    /* peek for += or -= cases */
883             if (op == '+' || op == '-') {
884                 *(val - 2) = '\0';      /* found, remove extra char */
885                 /* case var+=val or var-=val */
886                 set_default(var, val, (int) op);
887             } else {
888                 /* case var=val */
889                 set_default(var, val, TRUE);
890             }
891         } else if (*var == '!') {
892             /* case !var Boolean False */
893             set_default(var + 1, NULL, FALSE);
894         } else {
895             /* case var Boolean True */
896             set_default(var, NULL, TRUE);
897         }
898         efree(var);
899     }
900
901     ldap_value_free_len(bv);
902 }
903
904 /*
905  * Build an LDAP timefilter.
906  *
907  * Stores a filter in the buffer that makes sure only entries
908  * are selected that have a sudoNotBefore in the past and a
909  * sudoNotAfter in the future, i.e. a filter of the following
910  * structure (spaced out a little more for better readability:
911  *
912  * (&
913  *   (|
914  *      (!(sudoNotAfter=*))
915  *      (sudoNotAfter>__now__)
916  *   )
917  *   (|
918  *      (!(sudoNotBefore=*))
919  *      (sudoNotBefore<__now__)
920  *   )
921  * )
922  *
923  * If either the sudoNotAfter or sudoNotBefore attributes are missing,
924  * no time restriction shall be imposed.
925  */
926 static int
927 sudo_ldap_timefilter(char *buffer, size_t buffersize)
928 {
929     struct tm *tp;
930     time_t now;
931     char timebuffer[16];
932     int bytes = 0;
933
934     /* Make sure we have a formatted timestamp for __now__. */
935     time(&now);
936     if ((tp = gmtime(&now)) == NULL) {
937         warning(_("unable to get GMT time"));
938         goto done;
939     }
940
941     /* Format the timestamp according to the RFC. */
942     if (strftime(timebuffer, sizeof(timebuffer), "%Y%m%d%H%M%SZ", tp) == 0) {
943         warning(_("unable to format timestamp"));
944         goto done;
945     }
946
947     /* Build filter. */
948     bytes = snprintf(buffer, buffersize, "(&(|(!(sudoNotAfter=*))(sudoNotAfter>=%s))(|(!(sudoNotBefore=*))(sudoNotBefore<=%s)))",
949         timebuffer, timebuffer);
950     if (bytes < 0 || bytes >= buffersize) {
951         warning(_("unable to build time filter"));
952         bytes = 0;
953     }
954
955 done:
956     return bytes;
957 }
958
959 /*
960  * Builds up a filter to search for default settings
961  */
962 static char *
963 sudo_ldap_build_default_filter()
964 {
965     char *filt;
966
967     if (ldap_conf.search_filter)
968         easprintf(&filt, "(&%s(cn=defaults))", ldap_conf.search_filter);
969     else
970         filt = estrdup("cn=defaults");
971     return filt;
972 }
973
974 /*
975  * Builds up a filter to check against LDAP.
976  */
977 static char *
978 sudo_ldap_build_pass1(struct passwd *pw)
979 {
980     struct group *grp;
981     char *buf, timebuffer[TIMEFILTER_LENGTH];
982     struct group_list *grlist;
983     size_t sz = 0;
984     int i;
985
986     /* Start with LDAP search filter length + 3 */
987     if (ldap_conf.search_filter)
988         sz += strlen(ldap_conf.search_filter) + 3;
989
990     /* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
991     sz += 29 + strlen(pw->pw_name);
992
993     /* Add space for primary and supplementary groups */
994     if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
995         sz += 12 + strlen(grp->gr_name);
996     }
997     if ((grlist = get_group_list(pw)) != NULL) {
998         for (i = 0; i < grlist->ngroups; i++) {
999             if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0)
1000                 continue;
1001             sz += 12 + strlen(grlist->groups[i]);
1002         }
1003     }
1004
1005     /* If timed, add space for time limits. */
1006     if (ldap_conf.timed)
1007         sz += TIMEFILTER_LENGTH;
1008     buf = emalloc(sz);
1009     *buf = '\0';
1010
1011     /*
1012      * If timed or using a search filter, start a global AND clause to
1013      * contain the search filter, search criteria, and time restriction.
1014      */
1015     if (ldap_conf.timed || ldap_conf.search_filter)
1016         (void) strlcpy(buf, "(&", sz);
1017
1018     if (ldap_conf.search_filter)
1019         (void) strlcat(buf, ldap_conf.search_filter, sz);
1020
1021     /* Global OR + sudoUser=user_name filter */
1022     (void) strlcat(buf, "(|(sudoUser=", sz);
1023     (void) strlcat(buf, pw->pw_name, sz);
1024     (void) strlcat(buf, ")", sz);
1025
1026     /* Append primary group */
1027     if (grp != NULL) {
1028         (void) strlcat(buf, "(sudoUser=%", sz);
1029         (void) strlcat(buf, grp->gr_name, sz);
1030         (void) strlcat(buf, ")", sz);
1031     }
1032
1033     /* Append supplementary groups */
1034     if (grlist != NULL) {
1035         for (i = 0; i < grlist->ngroups; i++) {
1036             if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0)
1037                 continue;
1038             (void) strlcat(buf, "(sudoUser=%", sz);
1039             (void) strlcat(buf, grlist->groups[i], sz);
1040             (void) strlcat(buf, ")", sz);
1041         }
1042     }
1043
1044     /* Done with groups. */
1045     if (grlist != NULL)
1046         grlist_delref(grlist);
1047     if (grp != NULL)
1048         gr_delref(grp);
1049
1050     /* Add ALL to list and end the global OR */
1051     if (strlcat(buf, "(sudoUser=ALL)", sz) >= sz)
1052         errorx(1, _("sudo_ldap_build_pass1 allocation mismatch"));
1053
1054     /* Add the time restriction, or simply end the global OR. */
1055     if (ldap_conf.timed) {
1056         strlcat(buf, ")", sz); /* closes the global OR */
1057         sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
1058         strlcat(buf, timebuffer, sz);
1059     } else if (ldap_conf.search_filter) {
1060         strlcat(buf, ")", sz); /* closes the global OR */
1061     }
1062     strlcat(buf, ")", sz); /* closes the global OR or the global AND */
1063
1064     return buf;
1065 }
1066
1067 /*
1068  * Builds up a filter to check against netgroup entries in LDAP.
1069  */
1070 static char *
1071 sudo_ldap_build_pass2(void)
1072 {
1073     char *filt, timebuffer[TIMEFILTER_LENGTH];
1074
1075     if (ldap_conf.timed)
1076         sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));
1077
1078     /*
1079      * Match all sudoUsers beginning with a '+'.
1080      * If a search filter or time restriction is specified, 
1081      * those get ANDed in to the expression.
1082      */
1083     easprintf(&filt, "%s%s(sudoUser=+*)%s%s",
1084         (ldap_conf.timed || ldap_conf.search_filter) ? "(&" : "",
1085         ldap_conf.search_filter ? ldap_conf.search_filter : "",
1086         ldap_conf.timed ? timebuffer : "",
1087         (ldap_conf.timed || ldap_conf.search_filter) ? ")" : "");
1088
1089     return filt;
1090 }
1091
1092 static void
1093 sudo_ldap_read_secret(const char *path)
1094 {
1095     FILE *fp;
1096     char buf[LINE_MAX], *cp;
1097
1098     if ((fp = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
1099         if (fgets(buf, sizeof(buf), fp) != NULL) {
1100             if ((cp = strchr(buf, '\n')) != NULL)
1101                 *cp = '\0';
1102             /* copy to bindpw and binddn */
1103             efree(ldap_conf.bindpw);
1104             ldap_conf.bindpw = estrdup(buf);
1105             efree(ldap_conf.binddn);
1106             ldap_conf.binddn = ldap_conf.rootbinddn;
1107             ldap_conf.rootbinddn = NULL;
1108         }
1109         fclose(fp);
1110     }
1111 }
1112
1113 static int
1114 sudo_ldap_read_config(void)
1115 {
1116     FILE *fp;
1117     char *cp, *keyword, *value;
1118     struct ldap_config_table *cur;
1119
1120     /* defaults */
1121     ldap_conf.version = 3;
1122     ldap_conf.port = -1;
1123     ldap_conf.tls_checkpeer = -1;
1124     ldap_conf.timelimit = -1;
1125     ldap_conf.timeout = -1;
1126     ldap_conf.bind_timelimit = -1;
1127     ldap_conf.use_sasl = -1;
1128     ldap_conf.rootuse_sasl = -1;
1129     ldap_conf.deref = -1;
1130
1131     if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL)
1132         return FALSE;
1133
1134     while ((cp = sudo_parseln(fp)) != NULL) {
1135         if (*cp == '\0')
1136             continue;           /* skip empty line */
1137
1138         /* split into keyword and value */
1139         keyword = cp;
1140         while (*cp && !isblank((unsigned char) *cp))
1141             cp++;
1142         if (*cp)
1143             *cp++ = '\0';       /* terminate keyword */
1144
1145         /* skip whitespace before value */
1146         while (isblank((unsigned char) *cp))
1147             cp++;
1148         value = cp;
1149
1150         /* Look up keyword in config table. */
1151         for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
1152             if (strcasecmp(keyword, cur->conf_str) == 0) {
1153                 switch (cur->type) {
1154                 case CONF_DEREF_VAL:
1155                     if (strcasecmp(value, "searching") == 0)
1156                         *(int *)(cur->valp) = LDAP_DEREF_SEARCHING;
1157                     else if (strcasecmp(value, "finding") == 0)
1158                         *(int *)(cur->valp) = LDAP_DEREF_FINDING;
1159                     else if (strcasecmp(value, "always") == 0)
1160                         *(int *)(cur->valp) = LDAP_DEREF_ALWAYS;
1161                     else
1162                         *(int *)(cur->valp) = LDAP_DEREF_NEVER;
1163                     break;
1164                 case CONF_BOOL:
1165                     *(int *)(cur->valp) = atobool(value) == TRUE;
1166                     break;
1167                 case CONF_INT:
1168                     *(int *)(cur->valp) = atoi(value);
1169                     break;
1170                 case CONF_STR:
1171                     efree(*(char **)(cur->valp));
1172                     *(char **)(cur->valp) = estrdup(value);
1173                     break;
1174                 case CONF_LIST_STR:
1175                     {
1176                         struct ldap_config_list_str **p;
1177                         size_t len = strlen(value);
1178
1179                         if (len > 0) {
1180                             p = (struct ldap_config_list_str **)cur->valp;
1181                             while (*p != NULL)
1182                                 p = &(*p)->next;
1183                             *p = emalloc(sizeof(struct ldap_config_list_str) + len);
1184                             memcpy((*p)->val, value, len + 1);
1185                             (*p)->next = NULL;
1186                         }
1187                     }
1188                     break;
1189                 }
1190                 break;
1191             }
1192         }
1193     }
1194     fclose(fp);
1195
1196     if (!ldap_conf.host)
1197         ldap_conf.host = estrdup("localhost");
1198
1199     if (ldap_conf.debug > 1) {
1200         sudo_printf(SUDO_CONV_ERROR_MSG, "LDAP Config Summary\n");
1201         sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n");
1202         if (ldap_conf.uri) {
1203             struct ldap_config_list_str *uri = ldap_conf.uri;
1204
1205             do {
1206                 sudo_printf(SUDO_CONV_ERROR_MSG, "uri              %s\n",
1207                     uri->val);
1208             } while ((uri = uri->next) != NULL);
1209         } else {
1210             sudo_printf(SUDO_CONV_ERROR_MSG, "host             %s\n",
1211                 ldap_conf.host ?  ldap_conf.host : "(NONE)");
1212             sudo_printf(SUDO_CONV_ERROR_MSG, "port             %d\n",
1213                 ldap_conf.port);
1214         }
1215         sudo_printf(SUDO_CONV_ERROR_MSG, "ldap_version     %d\n",
1216             ldap_conf.version);
1217
1218         if (ldap_conf.base) {
1219             struct ldap_config_list_str *base = ldap_conf.base;
1220             do {
1221                 sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base     %s\n",
1222                     base->val);
1223             } while ((base = base->next) != NULL);
1224         } else {
1225             sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base     %s\n",
1226                 "(NONE: LDAP disabled)");
1227         }
1228         if (ldap_conf.search_filter) {
1229             sudo_printf(SUDO_CONV_ERROR_MSG, "search_filter    %s\n",
1230                 ldap_conf.search_filter);
1231         }
1232         sudo_printf(SUDO_CONV_ERROR_MSG, "binddn           %s\n",
1233             ldap_conf.binddn ?  ldap_conf.binddn : "(anonymous)");
1234         sudo_printf(SUDO_CONV_ERROR_MSG, "bindpw           %s\n",
1235             ldap_conf.bindpw ?  ldap_conf.bindpw : "(anonymous)");
1236         if (ldap_conf.bind_timelimit > 0) {
1237             sudo_printf(SUDO_CONV_ERROR_MSG, "bind_timelimit   %d\n",
1238                 ldap_conf.bind_timelimit);
1239         }
1240         if (ldap_conf.timelimit > 0) {
1241             sudo_printf(SUDO_CONV_ERROR_MSG, "timelimit        %d\n",
1242                 ldap_conf.timelimit);
1243         }
1244         if (ldap_conf.deref != -1) {
1245             sudo_printf(SUDO_CONV_ERROR_MSG, "deref            %d\n",
1246                 ldap_conf.deref);
1247         }
1248         sudo_printf(SUDO_CONV_ERROR_MSG, "ssl              %s\n",
1249             ldap_conf.ssl ?  ldap_conf.ssl : "(no)");
1250         if (ldap_conf.tls_checkpeer != -1) {
1251             sudo_printf(SUDO_CONV_ERROR_MSG, "tls_checkpeer    %s\n",
1252                 ldap_conf.tls_checkpeer ?  "(yes)" : "(no)");
1253         }
1254         if (ldap_conf.tls_cacertfile != NULL) {
1255             sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cacertfile   %s\n",
1256                 ldap_conf.tls_cacertfile);
1257         }
1258         if (ldap_conf.tls_cacertdir != NULL) {
1259             sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cacertdir    %s\n",
1260                 ldap_conf.tls_cacertdir);
1261         }
1262         if (ldap_conf.tls_random_file != NULL) {
1263             sudo_printf(SUDO_CONV_ERROR_MSG, "tls_random_file  %s\n",
1264                 ldap_conf.tls_random_file);
1265         }
1266         if (ldap_conf.tls_cipher_suite != NULL) {
1267             sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cipher_suite %s\n",
1268                 ldap_conf.tls_cipher_suite);
1269         }
1270         if (ldap_conf.tls_certfile != NULL) {
1271             sudo_printf(SUDO_CONV_ERROR_MSG, "tls_certfile     %s\n",
1272                 ldap_conf.tls_certfile);
1273         }
1274         if (ldap_conf.tls_keyfile != NULL) {
1275             sudo_printf(SUDO_CONV_ERROR_MSG, "tls_keyfile      %s\n",
1276                 ldap_conf.tls_keyfile);
1277         }
1278 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1279         if (ldap_conf.use_sasl != -1) {
1280             sudo_printf(SUDO_CONV_ERROR_MSG, "use_sasl         %s\n",
1281                 ldap_conf.use_sasl ? "yes" : "no");
1282             sudo_printf(SUDO_CONV_ERROR_MSG, "sasl_auth_id     %s\n",
1283                 ldap_conf.sasl_auth_id ?  ldap_conf.sasl_auth_id : "(NONE)");
1284             sudo_printf(SUDO_CONV_ERROR_MSG, "rootuse_sasl     %d\n",
1285                 ldap_conf.rootuse_sasl);
1286             sudo_printf(SUDO_CONV_ERROR_MSG, "rootsasl_auth_id %s\n",
1287                 ldap_conf.rootsasl_auth_id ?  ldap_conf.rootsasl_auth_id : "(NONE)");
1288             sudo_printf(SUDO_CONV_ERROR_MSG, "sasl_secprops    %s\n",
1289                 ldap_conf.sasl_secprops ?  ldap_conf.sasl_secprops : "(NONE)");
1290             sudo_printf(SUDO_CONV_ERROR_MSG, "krb5_ccname      %s\n",
1291                 ldap_conf.krb5_ccname ?  ldap_conf.krb5_ccname : "(NONE)");
1292         }
1293 #endif
1294         sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n");
1295     }
1296     if (!ldap_conf.base)
1297         return FALSE;           /* if no base is defined, ignore LDAP */
1298
1299     if (ldap_conf.bind_timelimit > 0)
1300         ldap_conf.bind_timelimit *= 1000;       /* convert to ms */
1301
1302     /*
1303      * Interpret SSL option
1304      */
1305     if (ldap_conf.ssl != NULL) {
1306         if (strcasecmp(ldap_conf.ssl, "start_tls") == 0)
1307             ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS;
1308         else if (atobool(ldap_conf.ssl) == TRUE)
1309             ldap_conf.ssl_mode = SUDO_LDAP_SSL;
1310     }
1311
1312 #if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
1313     if (ldap_conf.tls_checkpeer != -1) {
1314         ldapssl_set_strength(NULL,
1315             ldap_conf.tls_checkpeer ? LDAPSSL_AUTH_CERT : LDAPSSL_AUTH_WEAK);
1316     }
1317 #endif
1318
1319 #ifndef HAVE_LDAP_INITIALIZE
1320     /* Convert uri list to host list if no ldap_initialize(). */
1321     if (ldap_conf.uri) {
1322         struct ldap_config_list_str *uri = ldap_conf.uri;
1323         if (sudo_ldap_parse_uri(uri) != 0)
1324             return FALSE;
1325         do {
1326             ldap_conf.uri = uri->next;
1327             efree(uri);
1328         } while ((uri = ldap_conf.uri));
1329         ldap_conf.port = LDAP_PORT;
1330     }
1331 #endif
1332
1333     if (!ldap_conf.uri) {
1334         /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
1335         if (ldap_conf.port < 0)
1336             ldap_conf.port =
1337                 ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
1338
1339 #ifdef HAVE_LDAP_CREATE
1340         /*
1341          * Cannot specify port directly to ldap_create(), each host must
1342          * include :port to override the default.
1343          */
1344         if (ldap_conf.port != LDAP_PORT)
1345             sudo_ldap_conf_add_ports();
1346 #endif
1347     }
1348
1349     /* If search filter is not parenthesized, make it so. */
1350     if (ldap_conf.search_filter && ldap_conf.search_filter[0] != '(') {
1351         size_t len = strlen(ldap_conf.search_filter);
1352         cp = ldap_conf.search_filter;
1353         ldap_conf.search_filter = emalloc(len + 3);
1354         ldap_conf.search_filter[0] = '(';
1355         memcpy(ldap_conf.search_filter + 1, cp, len);
1356         ldap_conf.search_filter[len + 1] = ')';
1357         ldap_conf.search_filter[len + 2] = '\0';
1358         efree(cp);
1359     }
1360
1361     /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
1362     if (ldap_conf.rootbinddn)
1363         sudo_ldap_read_secret(_PATH_LDAP_SECRET);
1364
1365 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1366     /*
1367      * Make sure we can open the file specified by krb5_ccname.
1368      */
1369     if (ldap_conf.krb5_ccname != NULL) {
1370         if (strncasecmp(ldap_conf.krb5_ccname, "FILE:", 5) == 0 ||
1371             strncasecmp(ldap_conf.krb5_ccname, "WRFILE:", 7) == 0) {
1372             value = ldap_conf.krb5_ccname +
1373                 (ldap_conf.krb5_ccname[4] == ':' ? 5 : 7);
1374             if ((fp = fopen(value, "r")) != NULL) {
1375                 DPRINTF(("using krb5 credential cache: %s", value), 1);
1376                 fclose(fp);
1377             } else {
1378                 /* Can't open it, just ignore the entry. */
1379                 DPRINTF(("unable to open krb5 credential cache: %s", value), 1);
1380                 efree(ldap_conf.krb5_ccname);
1381                 ldap_conf.krb5_ccname = NULL;
1382             }
1383         }
1384     }
1385 #endif
1386     return TRUE;
1387 }
1388
1389 /*
1390  * Extract the dn from an entry and return the first rdn from it.
1391  */
1392 static char *
1393 sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry)
1394 {
1395 #ifdef HAVE_LDAP_STR2DN
1396     char *dn, *rdn = NULL;
1397     LDAPDN tmpDN;
1398
1399     if ((dn = ldap_get_dn(ld, entry)) == NULL)
1400         return NULL;
1401     if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) {
1402         ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN);
1403         ldap_dnfree(tmpDN);
1404     }
1405     ldap_memfree(dn);
1406     return rdn;
1407 #else
1408     char *dn, **edn;
1409
1410     if ((dn = ldap_get_dn(ld, entry)) == NULL)
1411         return NULL;
1412     edn = ldap_explode_dn(dn, 1);
1413     ldap_memfree(dn);
1414     return edn ? edn[0] : NULL;
1415 #endif
1416 }
1417
1418 /*
1419  * Fetch and display the global Options.
1420  */
1421 static int
1422 sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
1423     struct lbuf *lbuf)
1424 {
1425     struct berval **bv, **p;
1426     struct timeval tv, *tvp = NULL;
1427     struct ldap_config_list_str *base;
1428     struct sudo_ldap_handle *handle = nss->handle;
1429     LDAP *ld;
1430     LDAPMessage *entry, *result;
1431     char *prefix, *filt;
1432     int rc, count = 0;
1433
1434     if (handle == NULL || handle->ld == NULL)
1435         goto done;
1436     ld = handle->ld;
1437
1438     filt = sudo_ldap_build_default_filter();
1439     for (base = ldap_conf.base; base != NULL; base = base->next) {
1440         if (ldap_conf.timeout > 0) {
1441             tv.tv_sec = ldap_conf.timeout;
1442             tv.tv_usec = 0;
1443             tvp = &tv;
1444         }
1445         result = NULL;
1446         rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
1447             filt, NULL, 0, NULL, NULL, tvp, 0, &result);
1448         if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
1449             bv = ldap_get_values_len(ld, entry, "sudoOption");
1450             if (bv != NULL) {
1451                 if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
1452                     prefix = "    ";
1453                 else
1454                     prefix = ", ";
1455                 for (p = bv; *p != NULL; p++) {
1456                     lbuf_append(lbuf, "%s%s", prefix, (*p)->bv_val);
1457                     prefix = ", ";
1458                     count++;
1459                 }
1460                 ldap_value_free_len(bv);
1461             }
1462         }
1463         if (result)
1464             ldap_msgfree(result);
1465     }
1466     efree(filt);
1467 done:
1468     return count;
1469 }
1470
1471 /*
1472  * STUB
1473  */
1474 static int
1475 sudo_ldap_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
1476     struct lbuf *lbuf)
1477 {
1478     return 0;
1479 }
1480
1481 /*
1482  * Print a record in the short form, ala file sudoers.
1483  */
1484 static int
1485 sudo_ldap_display_entry_short(LDAP *ld, LDAPMessage *entry, struct lbuf *lbuf)
1486 {
1487     struct berval **bv, **p;
1488     int count = 0;
1489
1490     lbuf_append(lbuf, "    (");
1491
1492     /* get the RunAsUser Values from the entry */
1493     bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
1494     if (bv == NULL)
1495         bv = ldap_get_values_len(ld, entry, "sudoRunAs");
1496     if (bv != NULL) {
1497         for (p = bv; *p != NULL; p++) {
1498             lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1499         }
1500         ldap_value_free_len(bv);
1501     } else
1502         lbuf_append(lbuf, "%s", def_runas_default);
1503
1504     /* get the RunAsGroup Values from the entry */
1505     bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
1506     if (bv != NULL) {
1507         lbuf_append(lbuf, " : ");
1508         for (p = bv; *p != NULL; p++) {
1509             lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1510         }
1511         ldap_value_free_len(bv);
1512     }
1513     lbuf_append(lbuf, ") ");
1514
1515     /* get the Option Values from the entry */
1516     bv = ldap_get_values_len(ld, entry, "sudoOption");
1517     if (bv != NULL) {
1518         for (p = bv; *p != NULL; p++) {
1519             char *cp = (*p)->bv_val;
1520             if (*cp == '!')
1521                 cp++;
1522             if (strcmp(cp, "authenticate") == 0)
1523                 lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
1524                     "NOPASSWD: " : "PASSWD: ");
1525             else if (strcmp(cp, "noexec") == 0)
1526                 lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
1527                     "EXEC: " : "NOEXEC: ");
1528             else if (strcmp(cp, "setenv") == 0)
1529                 lbuf_append(lbuf, (*p)->bv_val[0] == '!' ?
1530                     "NOSETENV: " : "SETENV: ");
1531         }
1532         ldap_value_free_len(bv);
1533     }
1534
1535     /* get the Command Values from the entry */
1536     bv = ldap_get_values_len(ld, entry, "sudoCommand");
1537     if (bv != NULL) {
1538         for (p = bv; *p != NULL; p++) {
1539             lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1540             count++;
1541         }
1542         ldap_value_free_len(bv);
1543     }
1544     lbuf_append(lbuf, "\n");
1545
1546     return count;
1547 }
1548
1549 /*
1550  * Print a record in the long form.
1551  */
1552 static int
1553 sudo_ldap_display_entry_long(LDAP *ld, LDAPMessage *entry, struct lbuf *lbuf)
1554 {
1555     struct berval **bv, **p;
1556     char *rdn;
1557     int count = 0;
1558
1559     /* extract the dn, only show the first rdn */
1560     rdn = sudo_ldap_get_first_rdn(ld, entry);
1561     if (rdn != NULL)
1562         lbuf_append(lbuf, _("\nLDAP Role: %s\n"), rdn);
1563     else
1564         lbuf_append(lbuf, _("\nLDAP Role: UNKNOWN\n"));
1565     if (rdn)
1566         ldap_memfree(rdn);
1567
1568     /* get the RunAsUser Values from the entry */
1569     lbuf_append(lbuf, "    RunAsUsers: ");
1570     bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
1571     if (bv == NULL)
1572         bv = ldap_get_values_len(ld, entry, "sudoRunAs");
1573     if (bv != NULL) {
1574         for (p = bv; *p != NULL; p++) {
1575             lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1576         }
1577         ldap_value_free_len(bv);
1578     } else
1579         lbuf_append(lbuf, "%s", def_runas_default);
1580     lbuf_append(lbuf, "\n");
1581
1582     /* get the RunAsGroup Values from the entry */
1583     bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
1584     if (bv != NULL) {
1585         lbuf_append(lbuf, "    RunAsGroups: ");
1586         for (p = bv; *p != NULL; p++) {
1587             lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1588         }
1589         ldap_value_free_len(bv);
1590         lbuf_append(lbuf, "\n");
1591     }
1592
1593     /* get the Option Values from the entry */
1594     bv = ldap_get_values_len(ld, entry, "sudoOption");
1595     if (bv != NULL) {
1596         lbuf_append(lbuf, "    Options: ");
1597         for (p = bv; *p != NULL; p++) {
1598             lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val);
1599         }
1600         ldap_value_free_len(bv);
1601         lbuf_append(lbuf, "\n");
1602     }
1603
1604     /*
1605      * Display order attribute if present.  This attribute is single valued,
1606      * so there is no need for a loop.
1607      */
1608     bv = ldap_get_values_len(ld, entry, "sudoOrder");
1609     if (bv != NULL) {
1610         if (*bv != NULL) {
1611             lbuf_append(lbuf, _("    Order: %s\n"), (*bv)->bv_val);
1612         }
1613         ldap_value_free_len(bv);
1614     }
1615
1616     /* Get the command values from the entry. */
1617     bv = ldap_get_values_len(ld, entry, "sudoCommand");
1618     if (bv != NULL) {
1619         lbuf_append(lbuf, _("    Commands:\n"));
1620         for (p = bv; *p != NULL; p++) {
1621             lbuf_append(lbuf, "\t%s\n", (*p)->bv_val);
1622             count++;
1623         }
1624         ldap_value_free_len(bv);
1625     }
1626
1627     return count;
1628 }
1629
1630 /*
1631  * Like sudo_ldap_lookup(), except we just print entries.
1632  */
1633 static int
1634 sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
1635     struct lbuf *lbuf)
1636 {
1637     struct sudo_ldap_handle *handle = nss->handle;
1638     LDAP *ld;
1639     struct ldap_result *lres;
1640     LDAPMessage *entry;
1641     int i, count = 0;
1642
1643     if (handle == NULL || handle->ld == NULL)
1644         goto done;
1645     ld = handle->ld;
1646
1647     DPRINTF(("ldap search for command list"), 1);
1648     lres = sudo_ldap_result_get(nss, pw);
1649
1650     /* Display all matching entries. */
1651     for (i = 0; i < lres->nentries; i++) {
1652         entry = lres->entries[i].entry;
1653         if (long_list)
1654             count += sudo_ldap_display_entry_long(ld, entry, lbuf);
1655         else
1656             count += sudo_ldap_display_entry_short(ld, entry, lbuf);
1657     }
1658
1659 done:
1660     return count;
1661 }
1662
1663 static int
1664 sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
1665 {
1666     struct sudo_ldap_handle *handle = nss->handle;
1667     LDAP *ld;
1668     struct ldap_result *lres;
1669     LDAPMessage *entry;
1670     int i, found = FALSE;
1671
1672     if (handle == NULL || handle->ld == NULL)
1673         goto done;
1674     ld = handle->ld;
1675
1676     /*
1677      * The sudo_ldap_result_get() function returns all nodes that match
1678      * the user and the host.
1679      */
1680     DPRINTF(("ldap search for command list"), 1);
1681     lres = sudo_ldap_result_get(nss, pw);
1682     for (i = 0; i < lres->nentries; i++) {
1683         entry = lres->entries[i].entry;
1684         if (sudo_ldap_check_command(ld, entry, NULL) &&
1685             sudo_ldap_check_runas(ld, entry)) {
1686             found = TRUE;
1687             goto done;
1688         }
1689     }
1690
1691 done:
1692     if (found)
1693         printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
1694             user_args ? " " : "", user_args ? user_args : "");
1695    return !found;
1696 }
1697
1698 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1699 static int
1700 sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags, void *_auth_id,
1701     void *_interact)
1702 {
1703     char *auth_id = (char *)_auth_id;
1704     sasl_interact_t *interact = (sasl_interact_t *)_interact;
1705
1706     for (; interact->id != SASL_CB_LIST_END; interact++) {
1707         if (interact->id != SASL_CB_USER)
1708             return LDAP_PARAM_ERROR;
1709
1710         if (auth_id != NULL)
1711             interact->result = auth_id;
1712         else if (interact->defresult != NULL)
1713             interact->result = interact->defresult;
1714         else
1715             interact->result = "";
1716
1717         interact->len = strlen(interact->result);
1718 #if SASL_VERSION_MAJOR < 2
1719         interact->result = estrdup(interact->result);
1720 #endif /* SASL_VERSION_MAJOR < 2 */
1721     }
1722     return LDAP_SUCCESS;
1723 }
1724 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
1725
1726 /*
1727  * Set LDAP options based on the config table.
1728  */
1729 static int
1730 sudo_ldap_set_options(LDAP *ld)
1731 {
1732     struct ldap_config_table *cur;
1733     int rc;
1734
1735     /* Set ber options */
1736 #ifdef LBER_OPT_DEBUG_LEVEL
1737     if (ldap_conf.ldap_debug)
1738         ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug);
1739 #endif
1740
1741     /* Set simple LDAP options */
1742     for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
1743         LDAP *conn;
1744         int ival;
1745         char *sval;
1746
1747         if (cur->opt_val == -1)
1748             continue;
1749
1750         conn = cur->connected ? ld : NULL;
1751         switch (cur->type) {
1752         case CONF_BOOL:
1753         case CONF_INT:
1754             ival = *(int *)(cur->valp);
1755             if (ival >= 0) {
1756                 rc = ldap_set_option(conn, cur->opt_val, &ival);
1757                 if (rc != LDAP_OPT_SUCCESS) {
1758                     warningx("ldap_set_option: %s -> %d: %s",
1759                         cur->conf_str, ival, ldap_err2string(rc));
1760                     return -1;
1761                 }
1762                 DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
1763             }
1764             break;
1765         case CONF_STR:
1766             sval = *(char **)(cur->valp);
1767             if (sval != NULL) {
1768                 rc = ldap_set_option(conn, cur->opt_val, sval);
1769                 if (rc != LDAP_OPT_SUCCESS) {
1770                     warningx("ldap_set_option: %s -> %s: %s",
1771                         cur->conf_str, sval, ldap_err2string(rc));
1772                     return -1;
1773                 }
1774                 DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
1775             }
1776             break;
1777         }
1778     }
1779
1780 #ifdef LDAP_OPT_TIMEOUT
1781     /* Convert timeout to a timeval */
1782     if (ldap_conf.timeout > 0) {
1783         struct timeval tv;
1784         tv.tv_sec = ldap_conf.timeout;
1785         tv.tv_usec = 0;
1786         rc = ldap_set_option(ld, LDAP_OPT_TIMEOUT, &tv);
1787         if (rc != LDAP_OPT_SUCCESS) {
1788             warningx("ldap_set_option(TIMEOUT, %ld): %s",
1789                 (long)tv.tv_sec, ldap_err2string(rc));
1790             return -1;
1791         }
1792         DPRINTF(("ldap_set_option(LDAP_OPT_TIMEOUT, %ld)",
1793             (long)tv.tv_sec), 1);
1794     }
1795 #endif
1796 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1797     /* Convert bind_timelimit to a timeval */
1798     if (ldap_conf.bind_timelimit > 0) {
1799         struct timeval tv;
1800         tv.tv_sec = ldap_conf.bind_timelimit / 1000;
1801         tv.tv_usec = 0;
1802         rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
1803         if (rc != LDAP_OPT_SUCCESS) {
1804             warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
1805                 (long)tv.tv_sec, ldap_err2string(rc));
1806             return -1;
1807         }
1808         DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)",
1809             (long)tv.tv_sec), 1);
1810     }
1811 #endif
1812
1813 #if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT)
1814     if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
1815         int val = LDAP_OPT_X_TLS_HARD;
1816         rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
1817         if (rc != LDAP_SUCCESS) {
1818             warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
1819                 ldap_err2string(rc));
1820             return -1;
1821         }
1822         DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)"), 1);
1823     }
1824 #endif
1825     return 0;
1826 }
1827
1828 /*
1829  * Create a new sudo_ldap_result structure.
1830  */
1831 static struct ldap_result *
1832 sudo_ldap_result_alloc(void)
1833 {
1834     struct ldap_result *result;
1835
1836     result = emalloc(sizeof(*result));
1837     result->searches = NULL;
1838     result->nentries = 0;
1839     result->entries = NULL;
1840     result->allocated_entries = 0;
1841     result->user_matches = FALSE;
1842     result->host_matches = FALSE;
1843     return result;
1844 }
1845
1846 /*
1847  * Free the ldap result structure
1848  */
1849 static void
1850 sudo_ldap_result_free(struct ldap_result *lres)
1851 {
1852     struct ldap_search_list *s;
1853
1854     if (lres != NULL) {
1855         if (lres->nentries) {
1856             efree(lres->entries);
1857             lres->entries = NULL;
1858         }
1859         if (lres->searches) {
1860             while ((s = lres->searches) != NULL) {
1861                 ldap_msgfree(s->searchresult);
1862                 lres->searches = s->next;
1863                 efree(s);
1864             }
1865         }
1866         efree(lres);
1867     }
1868 }
1869
1870 /*
1871  * Add a search result to the ldap_result structure.
1872  */
1873 static struct ldap_search_list *
1874 sudo_ldap_result_add_search(struct ldap_result *lres, LDAP *ldap,
1875     LDAPMessage *searchresult)
1876 {
1877     struct ldap_search_list *s, *news;
1878
1879     news = emalloc(sizeof(struct ldap_search_list));
1880     news->next = NULL;
1881     news->ldap = ldap;
1882     news->searchresult = searchresult;
1883
1884     /* Add entry to the end of the chain (XXX - tailq instead?). */
1885     if (lres->searches) {
1886         for (s = lres->searches; s->next != NULL; s = s->next)
1887             continue;
1888         s->next = news;
1889     } else {
1890         lres->searches = news;
1891     }
1892     return news;
1893 }
1894
1895 /*
1896  * Connect to the LDAP server specified by ld
1897  */
1898 static int
1899 sudo_ldap_bind_s(LDAP *ld)
1900 {
1901     int rc;
1902 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1903     const char *old_ccname = user_ccname;
1904 # ifdef HAVE_GSS_KRB5_CCACHE_NAME
1905     unsigned int status;
1906 # endif
1907 #endif
1908
1909 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
1910     if (ldap_conf.rootuse_sasl == TRUE ||
1911         (ldap_conf.rootuse_sasl != FALSE && ldap_conf.use_sasl == TRUE)) {
1912         void *auth_id = ldap_conf.rootsasl_auth_id ?
1913             ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id;
1914
1915         if (ldap_conf.krb5_ccname != NULL) {
1916 # ifdef HAVE_GSS_KRB5_CCACHE_NAME
1917             if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname)
1918                 != GSS_S_COMPLETE) {
1919                 old_ccname = NULL;
1920                 DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
1921             }
1922 # else
1923             setenv("KRB5CCNAME", ldap_conf.krb5_ccname, TRUE);
1924 # endif
1925         }
1926         rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI",
1927             NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id);
1928         if (ldap_conf.krb5_ccname != NULL) {
1929 # ifdef HAVE_GSS_KRB5_CCACHE_NAME
1930             if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE)
1931                     DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
1932 # else
1933             if (old_ccname != NULL)
1934                 setenv("KRB5CCNAME", old_ccname, TRUE);
1935             else
1936                 unsetenv("KRB5CCNAME");
1937 # endif
1938         }
1939         if (rc != LDAP_SUCCESS) {
1940             warningx("ldap_sasl_interactive_bind_s(): %s",
1941                 ldap_err2string(rc));
1942             return -1;
1943         }
1944         DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1);
1945     } else
1946 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
1947 #ifdef HAVE_LDAP_SASL_BIND_S
1948     {
1949         struct berval bv;
1950
1951         bv.bv_val = ldap_conf.bindpw ? ldap_conf.bindpw : "";
1952         bv.bv_len = strlen(bv.bv_val);
1953
1954         rc = ldap_sasl_bind_s(ld, ldap_conf.binddn, LDAP_SASL_SIMPLE, &bv,
1955             NULL, NULL, NULL);
1956         if (rc != LDAP_SUCCESS) {
1957             warningx("ldap_sasl_bind_s(): %s", ldap_err2string(rc));
1958             return -1;
1959         }
1960         DPRINTF(("ldap_sasl_bind_s() ok"), 1);
1961     }
1962 #else
1963     {
1964         rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw);
1965         if (rc != LDAP_SUCCESS) {
1966             warningx("ldap_simple_bind_s(): %s", ldap_err2string(rc));
1967             return -1;
1968         }
1969         DPRINTF(("ldap_simple_bind_s() ok"), 1);
1970     }
1971 #endif
1972     return 0;
1973 }
1974
1975 /*
1976  * Open a connection to the LDAP server.
1977  * Returns 0 on success and non-zero on failure.
1978  */
1979 static int
1980 sudo_ldap_open(struct sudo_nss *nss)
1981 {
1982     LDAP *ld;
1983     int rc, ldapnoinit = FALSE;
1984     struct sudo_ldap_handle     *handle;
1985
1986     if (!sudo_ldap_read_config())
1987         return -1;
1988
1989     /* Prevent reading of user ldaprc and system defaults. */
1990     if (getenv("LDAPNOINIT") == NULL) {
1991         ldapnoinit = TRUE;
1992         setenv("LDAPNOINIT", "1", TRUE);
1993     }
1994
1995     /* Connect to LDAP server */
1996 #ifdef HAVE_LDAP_INITIALIZE
1997     if (ldap_conf.uri != NULL) {
1998         char *buf = sudo_ldap_join_uri(ldap_conf.uri);
1999         DPRINTF(("ldap_initialize(ld, %s)", buf), 2);
2000         rc = ldap_initialize(&ld, buf);
2001         efree(buf);
2002     } else
2003 #endif
2004         rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);
2005     if (rc != LDAP_SUCCESS) {
2006         warningx(_("unable to initialize LDAP: %s"), ldap_err2string(rc));
2007         return -1;
2008     }
2009
2010     if (ldapnoinit)
2011         unsetenv("LDAPNOINIT");
2012
2013     /* Set LDAP options */
2014     if (sudo_ldap_set_options(ld) < 0)
2015         return -1;
2016
2017     if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
2018 #if defined(HAVE_LDAP_START_TLS_S)
2019         rc = ldap_start_tls_s(ld, NULL, NULL);
2020         if (rc != LDAP_SUCCESS) {
2021             warningx("ldap_start_tls_s(): %s", ldap_err2string(rc));
2022             return -1;
2023         }
2024         DPRINTF(("ldap_start_tls_s() ok"), 1);
2025 #elif defined(HAVE_LDAP_SSL_CLIENT_INIT) && defined(HAVE_LDAP_START_TLS_S_NP)
2026         if (ldap_ssl_client_init(NULL, NULL, 0, &rc) != LDAP_SUCCESS) {
2027             warningx("ldap_ssl_client_init(): %s", ldap_err2string(rc));
2028             return -1;
2029         }
2030         rc = ldap_start_tls_s_np(ld, NULL);
2031         if (rc != LDAP_SUCCESS) {
2032             warningx("ldap_start_tls_s_np(): %s", ldap_err2string(rc));
2033             return -1;
2034         }
2035         DPRINTF(("ldap_start_tls_s_np() ok"), 1);
2036 #else
2037         warningx(_("start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()"));
2038 #endif /* !HAVE_LDAP_START_TLS_S && !HAVE_LDAP_START_TLS_S_NP */
2039     }
2040
2041     /* Actually connect */
2042     if (sudo_ldap_bind_s(ld) != 0)
2043         return -1;
2044
2045     /* Create a handle container. */
2046     handle = emalloc(sizeof(struct sudo_ldap_handle));
2047     handle->ld = ld;
2048     handle->result = NULL;
2049     handle->username = NULL;
2050     handle->grlist = NULL;
2051     nss->handle = handle;
2052
2053     return 0;
2054 }
2055
2056 static int
2057 sudo_ldap_setdefs(struct sudo_nss *nss)
2058 {
2059     struct ldap_config_list_str *base;
2060     struct sudo_ldap_handle *handle = nss->handle;
2061     struct timeval tv, *tvp = NULL;
2062     LDAP *ld;
2063     LDAPMessage *entry, *result;
2064     char *filt;
2065     int rc;
2066
2067     if (handle == NULL || handle->ld == NULL)
2068         return -1;
2069     ld = handle->ld;
2070
2071     filt = sudo_ldap_build_default_filter();
2072     DPRINTF(("Looking for cn=defaults: %s", filt), 1);
2073
2074     for (base = ldap_conf.base; base != NULL; base = base->next) {
2075         if (ldap_conf.timeout > 0) {
2076             tv.tv_sec = ldap_conf.timeout;
2077             tv.tv_usec = 0;
2078             tvp = &tv;
2079         }
2080         result = NULL;
2081         rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
2082             filt, NULL, 0, NULL, NULL, tvp, 0, &result);
2083         if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
2084             DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
2085             sudo_ldap_parse_options(ld, entry);
2086         } else
2087             DPRINTF(("no default options found in %s", base->val), 1);
2088
2089         if (result)
2090             ldap_msgfree(result);
2091     }
2092     efree(filt);
2093
2094     return 0;
2095 }
2096
2097 /*
2098  * like sudoers_lookup() - only LDAP style
2099  */
2100 static int
2101 sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
2102 {
2103     struct sudo_ldap_handle *handle = nss->handle;
2104     LDAP *ld;
2105     LDAPMessage *entry;
2106     int i, rc, setenv_implied;
2107     struct ldap_result *lres = NULL;
2108
2109     if (handle == NULL || handle->ld == NULL)
2110         return ret;
2111     ld = handle->ld;
2112
2113     /* Fetch list of sudoRole entries that match user and host. */
2114     lres = sudo_ldap_result_get(nss, sudo_user.pw);
2115
2116     /*
2117      * The following queries are only determine whether or not a
2118      * password is required, so the order of the entries doesn't matter.
2119      */
2120     if (pwflag) {
2121         int doauth = UNSPEC;
2122         int matched = UNSPEC;
2123         enum def_tuple pwcheck = 
2124             (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
2125
2126         DPRINTF(("perform search for pwflag %d", pwflag), 1);
2127         for (i = 0; i < lres->nentries; i++) {
2128             entry = lres->entries[i].entry;
2129             if ((pwcheck == any && doauth != FALSE) ||
2130                 (pwcheck == all && doauth == FALSE)) {
2131                 doauth = sudo_ldap_check_bool(ld, entry, "authenticate");
2132             }
2133             /* Only check the command when listing another user. */
2134             if (user_uid == 0 || list_pw == NULL ||
2135                 user_uid == list_pw->pw_uid ||
2136                 sudo_ldap_check_command(ld, entry, NULL)) {
2137                 matched = TRUE;
2138                 break;
2139             }
2140         }
2141         if (matched || user_uid == 0) {
2142             SET(ret, VALIDATE_OK);
2143             CLR(ret, VALIDATE_NOT_OK);
2144             if (def_authenticate) {
2145                 switch (pwcheck) {
2146                     case always:
2147                         SET(ret, FLAG_CHECK_USER);
2148                         break;
2149                     case all:
2150                     case any:
2151                         if (doauth == FALSE)
2152                             def_authenticate = FALSE;
2153                         break;
2154                     case never:
2155                         def_authenticate = FALSE;
2156                         break;
2157                     default:
2158                         break;
2159                 }
2160             }
2161         }
2162         goto done;
2163     }
2164
2165     DPRINTF(("searching LDAP for sudoers entries"), 1);
2166
2167     setenv_implied = FALSE;
2168     for (i = 0; i < lres->nentries; i++) {
2169         entry = lres->entries[i].entry;
2170         if (!sudo_ldap_check_runas(ld, entry))
2171             continue;
2172         rc = sudo_ldap_check_command(ld, entry, &setenv_implied);
2173         if (rc != UNSPEC) {
2174             /* We have a match. */
2175             DPRINTF(("Command %sallowed", rc == TRUE ? "" : "NOT "), 1);
2176             if (rc == TRUE) {
2177                 DPRINTF(("LDAP entry: %p", entry), 1);
2178                 /* Apply entry-specific options. */
2179                 if (setenv_implied)
2180                     def_setenv = TRUE;
2181                 sudo_ldap_parse_options(ld, entry);
2182 #ifdef HAVE_SELINUX
2183                 /* Set role and type if not specified on command line. */
2184                 if (user_role == NULL)
2185                     user_role = def_role;
2186                 if (user_type == NULL)
2187                     user_type = def_type;
2188 #endif /* HAVE_SELINUX */
2189                 SET(ret, VALIDATE_OK);
2190                 CLR(ret, VALIDATE_NOT_OK);
2191             } else {
2192                 SET(ret, VALIDATE_NOT_OK);
2193                 CLR(ret, VALIDATE_OK);
2194             }
2195             break;
2196         }
2197     }
2198
2199 done:
2200     DPRINTF(("done with LDAP searches"), 1);
2201     DPRINTF(("user_matches=%d", lres->user_matches), 1);
2202     DPRINTF(("host_matches=%d", lres->host_matches), 1);
2203
2204     if (!ISSET(ret, VALIDATE_OK)) {
2205         /* No matching entries. */
2206         if (pwflag && list_pw == NULL)
2207             SET(ret, FLAG_NO_CHECK);
2208     }
2209     if (lres->user_matches)
2210         CLR(ret, FLAG_NO_USER);
2211     if (lres->host_matches)
2212         CLR(ret, FLAG_NO_HOST);
2213     DPRINTF(("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret), 1);
2214
2215     return ret;
2216 }
2217
2218 /*
2219  * Comparison function for ldap_entry_wrapper structures, descending order.
2220  */
2221 static int
2222 ldap_entry_compare(const void *a, const void *b)
2223 {
2224     const struct ldap_entry_wrapper *aw = a;
2225     const struct ldap_entry_wrapper *bw = b;
2226
2227     return bw->order < aw->order ? -1 :
2228         (bw->order > aw->order ? 1 : 0);
2229 }
2230
2231 /*
2232  * Find the last entry in the list of searches, usually the
2233  * one currently being used to add entries.
2234  * XXX - use a tailq instead?
2235  */
2236 static struct ldap_search_list *
2237 sudo_ldap_result_last_search(struct ldap_result *lres)
2238 {
2239     struct ldap_search_list *result = lres->searches;
2240
2241     if (result) {
2242         while (result->next)
2243             result = result->next;
2244     }
2245     return result;
2246 }
2247
2248 /*
2249  * Add an entry to the result structure.
2250  */
2251 static struct ldap_entry_wrapper *
2252 sudo_ldap_result_add_entry(struct ldap_result *lres, LDAPMessage *entry)
2253 {
2254     struct ldap_search_list *last;
2255     struct berval **bv;
2256     double order = 0.0;
2257     char *ep;
2258
2259     /* Determine whether the entry has the sudoOrder attribute. */
2260     last = sudo_ldap_result_last_search(lres);
2261     bv = ldap_get_values_len(last->ldap, entry, "sudoOrder");
2262     if (bv != NULL) {
2263         if (ldap_count_values_len(bv) > 0) {
2264             /* Get the value of this attribute, 0 if not present. */
2265             DPRINTF(("order attribute raw: %s", (*bv)->bv_val), 1);
2266             order = strtod((*bv)->bv_val, &ep);
2267             if (ep == (*bv)->bv_val || *ep != '\0') {
2268                 warningx(_("invalid sudoOrder attribute: %s"), (*bv)->bv_val);
2269                 order = 0.0;
2270             }
2271             DPRINTF(("order attribute: %f", order), 1);
2272         }
2273         ldap_value_free_len(bv);
2274     }
2275
2276     /*
2277      * Enlarge the array of entry wrappers as needed, preallocating blocks
2278      * of 100 entries to save on allocation time.
2279      */
2280     if (++lres->nentries > lres->allocated_entries) {
2281         lres->allocated_entries += ALLOCATION_INCREMENT;
2282         lres->entries = erealloc3(lres->entries, lres->allocated_entries,
2283             sizeof(lres->entries[0]));
2284     }
2285
2286     /* Fill in the new entry and return it. */
2287     lres->entries[lres->nentries - 1].entry = entry;
2288     lres->entries[lres->nentries - 1].order = order;
2289
2290     return &lres->entries[lres->nentries - 1];
2291 }
2292
2293 /*
2294  * Free the ldap result structure in the sudo_nss handle.
2295  */
2296 static void
2297 sudo_ldap_result_free_nss(struct sudo_nss *nss)
2298 {
2299     struct sudo_ldap_handle *handle = nss->handle;
2300
2301     if (handle->result != NULL) {
2302         DPRINTF(("removing reusable search result"), 1);
2303         sudo_ldap_result_free(handle->result);
2304         if (handle->username) {
2305             efree(handle->username);
2306             handle->username = NULL;
2307         }
2308         handle->grlist = NULL;
2309         handle->result = NULL;
2310     }
2311 }
2312
2313 /*
2314  * Perform the LDAP query for the user or return a cached query if
2315  * there is one for this user.
2316  */
2317 static struct ldap_result *
2318 sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
2319 {
2320     struct sudo_ldap_handle *handle = nss->handle;
2321     struct ldap_config_list_str *base;
2322     struct ldap_result *lres;
2323     struct timeval tv, *tvp = NULL;
2324     LDAPMessage *entry, *result;
2325     LDAP *ld = handle->ld;
2326     int do_netgr, rc;
2327     char *filt;
2328
2329     /*
2330      * If we already have a cached result, return it so we don't have to
2331      * have to contact the LDAP server again.
2332      */
2333     if (handle->result) {
2334         if (handle->grlist == user_group_list &&
2335             strcmp(pw->pw_name, handle->username) == 0) {
2336             DPRINTF(("reusing previous result (user %s) with %d entries",
2337                 handle->username, handle->result->nentries), 1);
2338             return handle->result;
2339         }
2340         /* User mismatch, cached result cannot be used. */
2341         DPRINTF(("removing result (user %s), new search (user %s)",
2342             handle->username, pw->pw_name), 1);
2343         sudo_ldap_result_free_nss(nss);
2344     }
2345
2346     /*
2347      * Okay - time to search for anything that matches this user
2348      * Lets limit it to only two queries of the LDAP server
2349      *
2350      * The first pass will look by the username, groups, and
2351      * the keyword ALL.  We will then inspect the results that
2352      * came back from the query.  We don't need to inspect the
2353      * sudoUser in this pass since the LDAP server already scanned
2354      * it for us.
2355      *
2356      * The second pass will return all the entries that contain
2357      * user netgroups.  Then we take the netgroups returned and
2358      * try to match them against the username.
2359      *
2360      * Since we have to sort the possible entries before we make a
2361      * decision, we perform the queries and store all of the results in
2362      * an ldap_result object.  The results are then sorted by sudoOrder.
2363      */
2364     lres = sudo_ldap_result_alloc();
2365     for (do_netgr = 0; do_netgr < 2; do_netgr++) {
2366         filt = do_netgr ? sudo_ldap_build_pass2() : sudo_ldap_build_pass1(pw);
2367         DPRINTF(("ldap search '%s'", filt), 1);
2368         for (base = ldap_conf.base; base != NULL; base = base->next) {
2369             DPRINTF(("searching from base '%s'", base->val), 1);
2370             if (ldap_conf.timeout > 0) {
2371                 tv.tv_sec = ldap_conf.timeout;
2372                 tv.tv_usec = 0;
2373                 tvp = &tv;
2374             }
2375             result = NULL;
2376             rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt,
2377                 NULL, 0, NULL, NULL, tvp, 0, &result);
2378             if (rc != LDAP_SUCCESS) {
2379                 DPRINTF(("nothing found for '%s'", filt), 1);
2380                 continue;
2381             }
2382             lres->user_matches = TRUE;
2383
2384             /* Add the seach result to list of search results. */
2385             DPRINTF(("adding search result"), 1);
2386             sudo_ldap_result_add_search(lres, ld, result);
2387             LDAP_FOREACH(entry, ld, result) {
2388                 if ((!do_netgr ||
2389                     sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
2390                     sudo_ldap_check_host(ld, entry)) {
2391                     lres->host_matches = TRUE;
2392                     sudo_ldap_result_add_entry(lres, entry);
2393                 }
2394             }
2395             DPRINTF(("result now has %d entries", lres->nentries), 1);
2396         }
2397         efree(filt);
2398     }
2399
2400     /* Sort the entries by the sudoOrder attribute. */
2401     DPRINTF(("sorting remaining %d entries", lres->nentries), 1);
2402     qsort(lres->entries, lres->nentries, sizeof(lres->entries[0]),
2403         ldap_entry_compare);
2404
2405     /* Store everything in the sudo_nss handle. */
2406     handle->result = lres;
2407     handle->username = estrdup(pw->pw_name);
2408     handle->grlist = user_group_list;
2409
2410     return lres;
2411 }
2412
2413 /*
2414  * Shut down the LDAP connection.
2415  */
2416 static int
2417 sudo_ldap_close(struct sudo_nss *nss)
2418 {
2419     struct sudo_ldap_handle *handle = nss->handle;
2420
2421     if (handle != NULL) {
2422         /* Free the result before unbinding; it may use the LDAP connection. */
2423         sudo_ldap_result_free_nss(nss);
2424
2425         /* Unbind and close the LDAP connection. */
2426         if (handle->ld != NULL) {
2427             ldap_unbind_ext_s(handle->ld, NULL, NULL);
2428             handle->ld = NULL;
2429         }
2430
2431         /* Free the handle container. */
2432         efree(nss->handle);
2433         nss->handle = NULL;
2434     }
2435     return 0;
2436 }
2437
2438 /*
2439  * STUB
2440  */
2441 static int
2442 sudo_ldap_parse(struct sudo_nss *nss)
2443 {
2444     return 0;
2445 }
2446
2447 #if 0
2448 /*
2449  * Create an ldap_result from an LDAP search result.
2450  *
2451  * This function is currently not used anywhere, it is left here as
2452  * an example of how to use the cached searches.
2453  */
2454 static struct ldap_result *
2455 sudo_ldap_result_from_search(LDAP *ldap, LDAPMessage *searchresult)
2456 {
2457     /*
2458      * An ldap_result is built from several search results, which are
2459      * organized in a list. The head of the list is maintained in the
2460      * ldap_result structure, together with the wrappers that point
2461      * to individual entries, this has to be initialized first.
2462      */
2463     struct ldap_result *result = sudo_ldap_result_alloc();
2464
2465     /*
2466      * Build a new list node for the search result, this creates the
2467      * list node.
2468      */
2469     struct ldap_search_list *last = sudo_ldap_result_add_search(result,
2470         ldap, searchresult);
2471
2472     /*
2473      * Now add each entry in the search result to the array of of entries
2474      * in the ldap_result object.
2475      */
2476     LDAPMessage *entry;
2477     LDAP_FOREACH(entry, last->ldap, last->searchresult) {
2478         sudo_ldap_result_add_entry(result, entry);
2479     }
2480     DPRINTF(("sudo_ldap_result_from_search: %d entries found",
2481         result->nentries), 2);
2482     return result;
2483 }
2484 #endif