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