c4fbfbf6008bb8383f234ab359aa1d306f2d2d25
[debian/sudo] / ldap.c
1 /*
2  * Copyright (c) 2003-2008 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * This code is derived from software contributed by Aaron Spangler.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include <config.h>
20
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <sys/param.h>
24 #include <sys/stat.h>
25 #include <stdio.h>
26 #ifdef STDC_HEADERS
27 # include <stdlib.h>
28 # include <stddef.h>
29 #else
30 # ifdef HAVE_STDLIB_H
31 #  include <stdlib.h>
32 # endif
33 #endif /* STDC_HEADERS */
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #else
37 # ifdef HAVE_STRINGS_H
38 #  include <strings.h>
39 # endif
40 #endif /* HAVE_STRING_H */
41 #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
42 # include <malloc.h>
43 #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
44 #ifdef HAVE_UNISTD_H
45 # include <unistd.h>
46 #endif /* HAVE_UNISTD_H */
47 #include <ctype.h>
48 #include <limits.h>
49 #include <pwd.h>
50 #include <grp.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <netdb.h>
54 #ifdef HAVE_ERR_H
55 # include <err.h>
56 #else
57 # include "emul/err.h"
58 #endif /* HAVE_ERR_H */
59 #include <errno.h>
60 #ifdef HAVE_LBER_H
61 # include <lber.h>
62 #endif
63 #include <ldap.h>
64
65 #include "sudo.h"
66 #include "parse.h"
67
68 #ifndef lint
69 __unused static const char rcsid[] = "$Sudo: ldap.c,v 1.11.2.32 2008/01/05 23:27:10 millert Exp $";
70 #endif /* lint */
71
72 #ifndef LINE_MAX
73 # define LINE_MAX 2048
74 #endif
75
76 #ifndef LDAP_OPT_SUCCESS
77 # define LDAP_OPT_SUCCESS LDAP_SUCCESS
78 #endif
79
80 #define DPRINTF(args, level)    if (ldap_conf.debug >= level) warnx args
81
82 #define CONF_BOOL       0
83 #define CONF_INT        1
84 #define CONF_STR        2
85
86 #define SUDO_LDAP_SSL           1
87 #define SUDO_LDAP_STARTTLS      2
88
89 struct ldap_config_table {
90     const char *conf_str;       /* config file string */
91     short type;                 /* CONF_BOOL, CONF_INT, CONF_STR */
92     short connected;            /* connection-specific value? */
93     int opt_val;                /* LDAP_OPT_* (or -1 for sudo internal) */
94     void *valp;                 /* pointer into ldap_conf */
95 };
96
97 /* ldap configuration structure */
98 struct ldap_config {
99     int port;
100     int version;
101     int debug;
102     int ldap_debug;
103     int tls_checkpeer;
104     int timelimit;
105     int bind_timelimit;
106     int ssl_mode;
107     char *host;
108     char *uri;
109     char *binddn;
110     char *bindpw;
111     char *rootbinddn;
112     char *base;
113     char *ssl;
114     char *tls_cacertfile;
115     char *tls_cacertdir;
116     char *tls_random_file;
117     char *tls_cipher_suite;
118     char *tls_certfile;
119     char *tls_keyfile;
120 } ldap_conf;
121
122 struct ldap_config_table ldap_conf_table[] = {
123     { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug },
124     { "host", CONF_STR, FALSE, -1, &ldap_conf.host },
125     { "port", CONF_INT, FALSE, -1, &ldap_conf.port },
126     { "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl },
127     { "sslpath", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
128     { "uri", CONF_STR, FALSE, -1, &ldap_conf.uri },
129 #ifdef LDAP_OPT_DEBUG_LEVEL
130     { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
131 #endif
132 #ifdef LDAP_OPT_PROTOCOL_VERSION
133     { "ldap_version", CONF_INT, TRUE, LDAP_OPT_PROTOCOL_VERSION,
134         &ldap_conf.version },
135 #endif
136 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
137     { "tls_checkpeer", CONF_BOOL, FALSE, LDAP_OPT_X_TLS_REQUIRE_CERT,
138         &ldap_conf.tls_checkpeer },
139 #endif
140 #ifdef LDAP_OPT_X_TLS_CACERTFILE
141     { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
142         &ldap_conf.tls_cacertfile },
143 #endif
144 #ifdef LDAP_OPT_X_TLS_CACERTDIR
145     { "tls_cacertdir", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTDIR,
146         &ldap_conf.tls_cacertdir },
147 #endif
148 #ifdef LDAP_OPT_X_TLS_RANDOM_FILE
149     { "tls_randfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_RANDOM_FILE,
150         &ldap_conf.tls_random_file },
151 #endif
152 #ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
153     { "tls_ciphers", CONF_STR, FALSE, LDAP_OPT_X_TLS_CIPHER_SUITE,
154         &ldap_conf.tls_cipher_suite },
155 #endif
156 #ifdef LDAP_OPT_X_TLS_CERTFILE
157     { "tls_cert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CERTFILE,
158         &ldap_conf.tls_certfile },
159 #else
160     { "tls_cert", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
161 #endif
162 #ifdef LDAP_OPT_X_TLS_KEYFILE
163     { "tls_key", CONF_STR, FALSE, LDAP_OPT_X_TLS_KEYFILE,
164         &ldap_conf.tls_keyfile },
165 #else
166     { "tls_key", CONF_STR, FALSE, -1, &ldap_conf.tls_keyfile },
167 #endif
168 #ifdef LDAP_OPT_NETWORK_TIMEOUT
169     { "bind_timelimit", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
170         &ldap_conf.bind_timelimit },
171 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
172     { "bind_timelimit", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT,
173         &ldap_conf.bind_timelimit },
174 #endif
175     { "timelimit", CONF_INT, TRUE, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit },
176     { "binddn", CONF_STR, FALSE, -1, &ldap_conf.binddn },
177     { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw },
178     { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
179     { "sudoers_base", CONF_STR, FALSE, -1, &ldap_conf.base },
180     { NULL }
181 };
182
183 static void sudo_ldap_update_defaults __P((LDAP *));
184 static void sudo_ldap_close __P((LDAP *));
185 static LDAP *sudo_ldap_open __P((void));
186
187 #ifndef HAVE_LDAP_INITIALIZE
188 /*
189  * For each uri, convert to host:port pairs.  For ldaps:// enable SSL
190  * Accepts: uris of the form ldap:/// or ldap://hostname:portnum/
191  * where the trailing slash is optional.
192  */
193 static int
194 sudo_ldap_parse_uri(uri_list)
195     const char *uri_list;
196 {
197     char *buf, *uri, *host, *cp, *port;
198     char hostbuf[LINE_MAX];
199     int nldap = 0, nldaps = 0;
200     int rc = -1;
201
202     buf = estrdup(uri_list);
203     hostbuf[0] = '\0';
204     for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
205         if (strncasecmp(uri, "ldap://", 7) == 0) {
206             nldap++;
207             host = uri + 7;
208         } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
209             nldaps++;
210             host = uri + 8;
211         } else {
212             warnx("unsupported LDAP uri type: %s", uri);
213             goto done;
214         }
215
216         /* trim optional trailing slash */
217         if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
218             *cp = '\0';
219         }
220
221         if (hostbuf[0] != '\0') {
222             if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
223                 goto toobig;
224         }
225
226         if (*host == '\0')
227             host = "localhost";         /* no host specified, use localhost */
228
229         if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
230             goto toobig;
231
232         /* If using SSL and no port specified, add port 636 */
233         if (nldaps) {
234             if ((port = strrchr(host, ':')) == NULL || !isdigit(port[1]))
235                 if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
236                     goto toobig;
237         }
238     }
239     if (hostbuf[0] == '\0') {
240         warnx("invalid uri: %s", uri_list);
241         goto done;
242     }
243
244     if (nldaps != 0) {
245         if (nldap != 0) {
246             warnx("cannot mix ldap and ldaps URIs");
247             goto done;
248         }
249         if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
250             warnx("cannot mix ldaps and starttls");
251             goto done;
252         }
253         ldap_conf.ssl_mode = SUDO_LDAP_SSL;
254     }
255
256     free(ldap_conf.host);
257     ldap_conf.host = estrdup(hostbuf);
258     rc = 0;
259
260 done:
261     efree(buf);
262     return(rc);
263
264 toobig:
265     errx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
266 }
267 #endif /* HAVE_LDAP_INITIALIZE */
268
269 static int
270 sudo_ldap_init(ldp, host, port)
271     LDAP **ldp;
272     const char *host;
273     int port;
274 {
275     LDAP *ld = NULL;
276     int rc = LDAP_CONNECT_ERROR;
277
278 #ifdef HAVE_LDAPSSL_INIT
279     if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
280         DPRINTF(("ldapssl_clientauth_init(%s, %s)",
281             ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
282             ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
283         rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
284             ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
285         if (rc != LDAP_SUCCESS) {
286             warnx("unable to initialize SSL cert and key db: %s",
287                 ldapssl_err2string(rc));
288             goto done;
289         }
290
291         DPRINTF(("ldapssl_init(%s, %d, 1)", host, port), 2);
292         if ((ld = ldapssl_init(host, port, 1)) == NULL)
293             goto done;
294     } else
295 #endif
296     {
297         DPRINTF(("ldap_init(%s, %d)", host, port), 2);
298         if ((ld = ldap_init(host, port)) == NULL)
299             goto done;
300     }
301     rc = LDAP_SUCCESS;
302
303 done:
304     *ldp = ld;
305     return(rc);
306 }
307
308 /*
309  * Walk through search results and return TRUE if we have a matching
310  * netgroup, else FALSE.
311  */
312 int
313 sudo_ldap_check_user_netgroup(ld, entry)
314     LDAP *ld;
315     LDAPMessage *entry;
316 {
317     char **v = NULL, **p = NULL;
318     int ret = FALSE;
319
320     if (!entry)
321         return(ret);
322
323     /* get the values from the entry */
324     v = ldap_get_values(ld, entry, "sudoUser");
325
326     /* walk through values */
327     for (p = v; p && *p && !ret; p++) {
328         /* match any */
329         if (netgr_matches(*p, NULL, NULL, user_name))
330             ret = TRUE;
331         DPRINTF(("ldap sudoUser netgroup '%s' ... %s", *p,
332             ret ? "MATCH!" : "not"), 2);
333     }
334
335     if (v)
336         ldap_value_free(v);     /* cleanup */
337
338     return(ret);
339 }
340
341 /*
342  * Walk through search results and return TRUE if we have a
343  * host match, else FALSE.
344  */
345 int
346 sudo_ldap_check_host(ld, entry)
347     LDAP *ld;
348     LDAPMessage *entry;
349 {
350     char **v = NULL, **p = NULL;
351     int ret = FALSE;
352
353     if (!entry)
354         return(ret);
355
356     /* get the values from the entry */
357     v = ldap_get_values(ld, entry, "sudoHost");
358
359     /* walk through values */
360     for (p = v; p && *p && !ret; p++) {
361         /* match any or address or netgroup or hostname */
362         if (!strcmp(*p, "ALL") || addr_matches(*p) ||
363             netgr_matches(*p, user_host, user_shost, NULL) ||
364             !hostname_matches(user_shost, user_host, *p))
365             ret = TRUE;
366         DPRINTF(("ldap sudoHost '%s' ... %s", *p,
367             ret ? "MATCH!" : "not"), 2);
368     }
369
370     if (v)
371         ldap_value_free(v);     /* cleanup */
372
373     return(ret);
374 }
375
376 /*
377  * Walk through search results and return TRUE if we have a runas match,
378  * else FALSE.
379  * Since the runas directive in /etc/sudoers is optional, so is sudoRunAs.
380  */
381 int
382 sudo_ldap_check_runas(ld, entry)
383     LDAP *ld;
384     LDAPMessage *entry;
385 {
386     char **v = NULL, **p = NULL;
387     int ret = FALSE;
388
389     if (!entry)
390         return(ret);
391
392     /* get the values from the entry */
393     v = ldap_get_values(ld, entry, "sudoRunAs");
394
395     /*
396      * BUG:
397      * 
398      * if runas is not specified on the command line, the only information
399      * as to which user to run as is in the runas_default option.  We should
400      * check to see if we have the local option present.  Unfortunately we
401      * don't parse these options until after this routine says yes or no.
402      * The query has already returned, so we could peek at the attribute
403      * values here though.
404      * 
405      * For now just require users to always use -u option unless its set
406      * in the global defaults. This behaviour is no different than the global
407      * /etc/sudoers.
408      *
409      * Sigh - maybe add this feature later
410      *
411      */
412
413     /*
414      * If there are no runas entries, match runas_default against
415      * what the user specified on the command line.
416      */
417     if (!v)
418         ret = !strcasecmp(runas_pw->pw_name, def_runas_default);
419
420     /* walk through values returned, looking for a match */
421     for (p = v; p && *p && !ret; p++) {
422         switch (*p[0]) {
423         case '+':
424             if (netgr_matches(*p, NULL, NULL, runas_pw->pw_name))
425                 ret = TRUE;
426             break;
427         case '%':
428             if (usergr_matches(*p, runas_pw->pw_name, runas_pw))
429                 ret = TRUE;
430             break;
431         case 'A':
432             if (strcmp(*p, "ALL") == 0) {
433                 ret = TRUE;
434                 break;
435             }
436             /* FALLTHROUGH */
437         default:
438             if (strcasecmp(*p, runas_pw->pw_name) == 0)
439                 ret = TRUE;
440             break;
441         }
442         DPRINTF(("ldap sudoRunAs '%s' ... %s", *p,
443             ret ? "MATCH!" : "not"), 2);
444     }
445
446     if (v)
447         ldap_value_free(v);     /* cleanup */
448
449     return(ret);
450 }
451
452 /*
453  * Walk through search results and return TRUE if we have a command match.
454  */
455 int
456 sudo_ldap_check_command(ld, entry, setenv_implied)
457     LDAP *ld;
458     LDAPMessage *entry;
459     int *setenv_implied;
460 {
461     char *allowed_cmnd, *allowed_args, **v = NULL, **p = NULL;
462     int foundbang, ret = FALSE;
463
464     if (!entry)
465         return(ret);
466
467     v = ldap_get_values(ld, entry, "sudoCommand");
468
469     /* get_first_entry */
470     for (p = v; p && *p && ret >= 0; p++) {
471         /* Match against ALL ? */
472         if (!strcmp(*p, "ALL")) {
473             ret = TRUE;
474             if (setenv_implied != NULL)
475                 *setenv_implied = TRUE;
476             DPRINTF(("ldap sudoCommand '%s' ... MATCH!", *p), 2);
477             continue;
478         }
479
480         /* check for !command */
481         if (**p == '!') {
482             foundbang = TRUE;
483             allowed_cmnd = estrdup(1 + *p);     /* !command */
484         } else {
485             foundbang = FALSE;
486             allowed_cmnd = estrdup(*p);         /* command */
487         }
488
489         /* split optional args away from command */
490         allowed_args = strchr(allowed_cmnd, ' ');
491         if (allowed_args)
492             *allowed_args++ = '\0';
493
494         /* check the command like normal */
495         if (command_matches(allowed_cmnd, allowed_args)) {
496             /*
497              * If allowed (no bang) set ret but keep on checking.
498              * If disallowed (bang), exit loop.
499              */
500             ret = foundbang ? -1 : TRUE;
501         }
502         DPRINTF(("ldap sudoCommand '%s' ... %s", *p,
503             ret == TRUE ? "MATCH!" : "not"), 2);
504
505         efree(allowed_cmnd);    /* cleanup */
506     }
507
508     if (v)
509         ldap_value_free(v);     /* more cleanup */
510
511     /* return TRUE if we found at least one ALLOW and no DENY */
512     return(ret > 0);
513 }
514
515 /*
516  * Read sudoOption and modify the defaults as we go.  This is used once
517  * from the cn=defaults entry and also once when a final sudoRole is matched.
518  */
519 void
520 sudo_ldap_parse_options(ld, entry)
521     LDAP *ld;
522     LDAPMessage *entry;
523 {
524     char op, *var, *val, **v = NULL, **p = NULL;
525
526     if (!entry)
527         return;
528
529     v = ldap_get_values(ld, entry, "sudoOption");
530
531     /* walk through options */
532     for (p = v; p && *p; p++) {
533
534         DPRINTF(("ldap sudoOption: '%s'", *p), 2);
535         var = estrdup(*p);
536
537         /* check for equals sign past first char */
538         val = strchr(var, '=');
539         if (val > var) {
540             *val++ = '\0';      /* split on = and truncate var */
541             op = *(val - 2);    /* peek for += or -= cases */
542             if (op == '+' || op == '-') {
543                 *(val - 2) = '\0';      /* found, remove extra char */
544                 /* case var+=val or var-=val */
545                 set_default(var, val, (int) op);
546             } else {
547                 /* case var=val */
548                 set_default(var, val, TRUE);
549             }
550         } else if (*var == '!') {
551             /* case !var Boolean False */
552             set_default(var + 1, NULL, FALSE);
553         } else {
554             /* case var Boolean True */
555             set_default(var, NULL, TRUE);
556         }
557         efree(var);
558     }
559
560     if (v)
561         ldap_value_free(v);
562 }
563
564 /*
565  * Concatenate strings, dynamically growing them as necessary.
566  * Strings can be arbitrarily long and are allocated/reallocated on
567  * the fly.  Make sure to free them when you are done.
568  *
569  * Usage:
570  *
571  * char *s=NULL;
572  * size_t sz;
573  *
574  * ncat(&s,&sz,"This ");
575  * ncat(&s,&sz,"is ");
576  * ncat(&s,&sz,"an ");
577  * ncat(&s,&sz,"arbitrarily ");
578  * ncat(&s,&sz,"long ");
579  * ncat(&s,&sz,"string!");
580  *
581  * printf("String Value='%s', but has %d bytes allocated\n",s,sz);
582  *
583  */
584 void
585 ncat(s, sz, src)
586     char **s;
587     size_t *sz;
588     char *src;
589 {
590     size_t nsz;
591
592     /* handle initial alloc */
593     if (*s == NULL) {
594         *s = estrdup(src);
595         *sz = strlen(src) + 1;
596         return;
597     }
598     /* handle realloc */
599     nsz = strlen(*s) + strlen(src) + 1;
600     if (*sz < nsz)
601         *s = erealloc((void *) *s, *sz = nsz * 2);
602     strlcat(*s, src, *sz);
603 }
604
605 /*
606  * builds together a filter to check against ldap
607  */
608 char *
609 sudo_ldap_build_pass1()
610 {
611     struct group *grp;
612     size_t sz;
613     char *b = NULL;
614     int i;
615
616     /* global OR */
617     ncat(&b, &sz, "(|");
618
619     /* build filter sudoUser=user_name */
620     ncat(&b, &sz, "(sudoUser=");
621     ncat(&b, &sz, user_name);
622     ncat(&b, &sz, ")");
623
624     /* Append primary group */
625     grp = getgrgid(user_gid);
626     if (grp != NULL) {
627         ncat(&b, &sz, "(sudoUser=%");
628         ncat(&b, &sz, grp -> gr_name);
629         ncat(&b, &sz, ")");
630     }
631
632     /* Append supplementary groups */
633     for (i = 0; i < user_ngroups; i++) {
634         if (user_groups[i] == user_gid)
635             continue;
636         if ((grp = getgrgid(user_groups[i])) != NULL) {
637             ncat(&b, &sz, "(sudoUser=%");
638             ncat(&b, &sz, grp -> gr_name);
639             ncat(&b, &sz, ")");
640         }
641     }
642
643     /* Add ALL to list */
644     ncat(&b, &sz, "(sudoUser=ALL)");
645
646     /* End of OR List */
647     ncat(&b, &sz, ")");
648
649     return(b);
650 }
651
652 /*
653  * Map yes/true/on to TRUE, no/false/off to FALSE, else -1
654  */
655 int
656 _atobool(s)
657     const char *s;
658 {
659     switch (*s) {
660         case 'y':
661         case 'Y':
662             if (strcasecmp(s, "yes") == 0)
663                 return(TRUE);
664             break;
665         case 't':
666         case 'T':
667             if (strcasecmp(s, "true") == 0)
668                 return(TRUE);
669             break;
670         case 'o':
671         case 'O':
672             if (strcasecmp(s, "on") == 0)
673                 return(TRUE);
674             if (strcasecmp(s, "off") == 0)
675                 return(FALSE);
676             break;
677         case 'n':
678         case 'N':
679             if (strcasecmp(s, "no") == 0)
680                 return(FALSE);
681             break;
682         case 'f':
683         case 'F':
684             if (strcasecmp(s, "false") == 0)
685                 return(FALSE);
686             break;
687     }
688     return(-1);
689 }
690
691 int
692 sudo_ldap_read_config()
693 {
694     FILE *f;
695     char buf[LINE_MAX], *c, *keyword, *value;
696     struct ldap_config_table *cur;
697
698     /* defaults */
699     ldap_conf.version = 3;
700     ldap_conf.port = -1;
701     ldap_conf.tls_checkpeer = -1;
702     ldap_conf.timelimit = -1;
703     ldap_conf.bind_timelimit = -1;
704
705     if ((f = fopen(_PATH_LDAP_CONF, "r")) == NULL)
706         return(FALSE);
707
708     while (fgets(buf, sizeof(buf), f)) {
709         /* ignore text after comment character */
710         if ((c = strchr(buf, '#')) != NULL)
711             *c = '\0';
712
713         /* skip leading whitespace */
714         for (c = buf; isspace((unsigned char) *c); c++)
715             /* nothing */;
716
717         if (*c == '\0' || *c == '\n')
718             continue;           /* skip empty line */
719
720         /* properly terminate keyword string */
721         keyword = c;
722         while (*c && !isspace((unsigned char) *c))
723             c++;
724         if (*c)
725             *c++ = '\0';        /* terminate keyword */
726
727         /* skip whitespace before value */
728         while (isspace((unsigned char) *c))
729             c++;
730         value = c;
731
732         /* trim whitespace after value */
733         while (*c)
734             c++;                /* wind to end */
735         while (--c > value && isspace((unsigned char) *c))
736             *c = '\0';
737
738         /* Look up keyword in config table. */
739         for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
740             if (strcasecmp(keyword, cur->conf_str) == 0) {
741                 switch (cur->type) {
742                 case CONF_BOOL:
743                     *(int *)(cur->valp) = _atobool(value);
744                     break;
745                 case CONF_INT:
746                     *(int *)(cur->valp) = atoi(value);
747                     break;
748                 case CONF_STR:
749                     efree(*(char **)(cur->valp));
750                     *(char **)(cur->valp) = estrdup(value);
751                     break;
752                 }
753                 break;
754             }
755         }
756     }
757     fclose(f);
758
759     if (!ldap_conf.host)
760         ldap_conf.host = "localhost";
761
762     if (ldap_conf.bind_timelimit > 0)
763         ldap_conf.bind_timelimit *= 1000;       /* convert to ms */
764
765     if (ldap_conf.debug > 1) {
766         fprintf(stderr, "LDAP Config Summary\n");
767         fprintf(stderr, "===================\n");
768         if (ldap_conf.uri) {
769             fprintf(stderr, "uri          %s\n", ldap_conf.uri);
770         } else {
771             fprintf(stderr, "host         %s\n", ldap_conf.host ?
772                 ldap_conf.host : "(NONE)");
773             fprintf(stderr, "port         %d\n", ldap_conf.port);
774         }
775         fprintf(stderr, "ldap_version %d\n", ldap_conf.version);
776
777         fprintf(stderr, "sudoers_base %s\n", ldap_conf.base ?
778             ldap_conf.base : "(NONE) <---Sudo will ignore ldap)");
779         fprintf(stderr, "binddn       %s\n", ldap_conf.binddn ?
780             ldap_conf.binddn : "(anonymous)");
781         fprintf(stderr, "bindpw       %s\n", ldap_conf.bindpw ?
782             ldap_conf.bindpw : "(anonymous)");
783         if (ldap_conf.bind_timelimit > 0)
784             fprintf(stderr, "bind_timelimit  %d\n", ldap_conf.bind_timelimit);
785         if (ldap_conf.timelimit > 0)
786             fprintf(stderr, "timelimit    %d\n", ldap_conf.timelimit);
787         fprintf(stderr, "ssl          %s\n", ldap_conf.ssl ?
788             ldap_conf.ssl : "(no)");
789         if (ldap_conf.tls_checkpeer != -1)
790             fprintf(stderr, "tls_checkpeer    %s\n", ldap_conf.tls_checkpeer ?
791                 "(yes)" : "(no)");
792         if (ldap_conf.tls_cacertfile != NULL)
793             fprintf(stderr, "tls_cacertfile   %s\n", ldap_conf.tls_cacertfile);
794         if (ldap_conf.tls_cacertdir != NULL)
795             fprintf(stderr, "tls_cacertdir    %s\n", ldap_conf.tls_cacertdir);
796         if (ldap_conf.tls_random_file != NULL)
797             fprintf(stderr, "tls_random_file  %s\n", ldap_conf.tls_random_file);
798         if (ldap_conf.tls_cipher_suite != NULL)
799             fprintf(stderr, "tls_cipher_suite %s\n", ldap_conf.tls_cipher_suite);
800         if (ldap_conf.tls_certfile != NULL)
801             fprintf(stderr, "tls_certfile     %s\n", ldap_conf.tls_certfile);
802         if (ldap_conf.tls_keyfile != NULL)
803             fprintf(stderr, "tls_keyfile      %s\n", ldap_conf.tls_keyfile);
804         fprintf(stderr, "===================\n");
805     }
806     if (!ldap_conf.base)
807         return(FALSE);          /* if no base is defined, ignore LDAP */
808
809     /*
810      * Interpret SSL option
811      */
812     if (ldap_conf.ssl != NULL) {
813             if (strcasecmp(ldap_conf.ssl, "start_tls") == 0)
814                 ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS;
815             else if (_atobool(ldap_conf.ssl))
816                 ldap_conf.ssl_mode = SUDO_LDAP_SSL;
817     }
818
819 #ifndef HAVE_LDAP_INITIALIZE
820     /* Convert uri list to host list if no ldap_initialize(). */
821     if (ldap_conf.uri) {
822         if (sudo_ldap_parse_uri(ldap_conf.uri) != 0)
823             return(FALSE);
824         free(ldap_conf.uri);
825         ldap_conf.uri = NULL;
826         ldap_conf.port = LDAP_PORT;
827     }
828 #endif
829
830     /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
831     if (!ldap_conf.uri && ldap_conf.port < 0)
832         ldap_conf.port =
833             ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
834
835     /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
836     if (ldap_conf.rootbinddn) {
837         if ((f = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
838             if (fgets(buf, sizeof(buf), f) != NULL) {
839                 /* removing trailing newlines */
840                 for (c = buf; *c != '\0'; c++)
841                     continue;
842                 while (--c > buf && *c == '\n')
843                     *c = '\0';
844                 /* copy to bindpw and binddn */
845                 efree(ldap_conf.bindpw);
846                 ldap_conf.bindpw = estrdup(buf);
847                 efree(ldap_conf.binddn);
848                 ldap_conf.binddn = ldap_conf.rootbinddn;
849                 ldap_conf.rootbinddn = NULL;
850             }
851             fclose(f);
852         }
853     }
854     return(TRUE);
855 }
856
857 /*
858  * like perl's join(sep,@ARGS)
859  */
860 char *
861  _ldap_join_values(sep, v)
862     char *sep;
863     char **v;
864 {
865     char *b = NULL, **p = NULL;
866     size_t sz = 0;
867
868     /* paste values together */
869     for (p = v; p && *p; p++) {
870         if (p != v && sep != NULL)
871             ncat(&b, &sz, sep); /* append separator */
872         ncat(&b, &sz, *p);      /* append value */
873     }
874
875     /* sanity check */
876     if (b[0] == '\0') {
877         /* something went wrong, put something here */
878         ncat(&b, &sz, "(empty list)");  /* append value */
879     }
880
881     return(b);
882 }
883
884 char *sudo_ldap_cm_list = NULL;
885 size_t sudo_ldap_cm_list_size;
886
887 #define SAVE_LIST(x) ncat(&sudo_ldap_cm_list,&sudo_ldap_cm_list_size,(x))
888 /*
889  * Walks through search result and returns TRUE if we have a
890  * command match
891  */
892 int
893 sudo_ldap_add_match(ld, entry, pwflag)
894     LDAP *ld;
895     LDAPMessage *entry;
896     int pwflag;
897 {
898     char *dn, **edn, **v = NULL;
899
900     /* if we are not collecting matches, then don't save them */
901     if (pwflag != I_LISTPW)
902         return(TRUE);
903
904     /* collect the dn, only show the rdn */
905     dn = ldap_get_dn(ld, entry);
906     edn = dn ? ldap_explode_dn(dn, 1) : NULL;
907     SAVE_LIST("\nLDAP Role: ");
908     SAVE_LIST((edn && *edn) ? *edn : "UNKNOWN");
909     SAVE_LIST("\n");
910     if (dn)
911         ldap_memfree(dn);
912     if (edn)
913         ldap_value_free(edn);
914
915     /* get the Runas Values from the entry */
916     v = ldap_get_values(ld, entry, "sudoRunAs");
917     if (v && *v) {
918         SAVE_LIST("  RunAs: (");
919         SAVE_LIST(_ldap_join_values(", ", v));
920         SAVE_LIST(")\n");
921     }
922     if (v)
923         ldap_value_free(v);
924
925     /* get the Command Values from the entry */
926     v = ldap_get_values(ld, entry, "sudoCommand");
927     if (v && *v) {
928         SAVE_LIST("  Commands:\n    ");
929         SAVE_LIST(_ldap_join_values("\n    ", v));
930         SAVE_LIST("\n");
931     } else {
932         SAVE_LIST("  Commands: NONE\n");
933     }
934     if (v)
935         ldap_value_free(v);
936
937     return(FALSE);              /* Don't stop at the first match */
938 }
939 #undef SAVE_LIST
940
941 void
942 sudo_ldap_list_matches()
943 {
944     if (sudo_ldap_cm_list != NULL)
945         printf("%s", sudo_ldap_cm_list);
946 }
947
948 /*
949  * Set LDAP options based on the config table.
950  */
951 int
952 sudo_ldap_set_options(ld)
953     LDAP *ld;
954 {
955     struct ldap_config_table *cur;
956     int rc;
957
958     /* Set ber options */
959 #ifdef LBER_OPT_DEBUG_LEVEL
960     if (ldap_conf.ldap_debug)
961         ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug);
962 #endif
963
964     /* Set simple LDAP options */
965     for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
966         LDAP *conn;
967         int ival;
968         char *sval;
969
970         if (cur->opt_val == -1)
971             continue;
972
973         conn = cur->connected ? ld : NULL;
974         switch (cur->type) {
975         case CONF_BOOL:
976         case CONF_INT:
977             ival = *(int *)(cur->valp);
978             if (ival >= 0) {
979                 rc = ldap_set_option(conn, cur->opt_val, &ival);
980                 if (rc != LDAP_OPT_SUCCESS) {
981                     warnx("ldap_set_option: %s -> %d: %s",
982                         cur->conf_str, ival, ldap_err2string(rc));
983                     return(-1);
984                 }
985                 DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
986             }
987             break;
988         case CONF_STR:
989             sval = *(char **)(cur->valp);
990             if (sval != NULL) {
991                 rc = ldap_set_option(conn, cur->opt_val, sval);
992                 if (rc != LDAP_OPT_SUCCESS) {
993                     warnx("ldap_set_option: %s -> %s: %s",
994                         cur->conf_str, sval, ldap_err2string(rc));
995                     return(-1);
996                 }
997                 DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
998             }
999             break;
1000         }
1001     }
1002
1003 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1004     /* Convert bind_timelimit to a timeval */
1005     if (ldap_conf.bind_timelimit > 0) {
1006         struct timeval tv;
1007         tv.tv_sec = ldap_conf.bind_timelimit / 1000;
1008         tv.tv_usec = 0;
1009         rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
1010         if (rc != LDAP_OPT_SUCCESS) {
1011             warnx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
1012                 (long)tv.tv_sec, ldap_err2string(rc));
1013             return(-1);
1014         }
1015         DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)\n",
1016             (long)tv.tv_sec), 1);
1017     }
1018 #endif
1019
1020 #if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT)
1021     if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
1022         int val = LDAP_OPT_X_TLS_HARD;
1023         rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
1024         if (rc != LDAP_SUCCESS) {
1025             warnx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
1026                 ldap_err2string(rc));
1027             return(-1);
1028         }
1029         DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)\n"), 1);
1030     }
1031 #endif
1032     return(0);
1033 }
1034
1035 /*
1036  * Open a connection to the LDAP server.
1037  */
1038 static LDAP *
1039 sudo_ldap_open()
1040 {
1041     LDAP *ld = NULL;
1042     int rc;
1043
1044     if (!sudo_ldap_read_config())
1045         return(NULL);
1046
1047     /* Connect to LDAP server */
1048 #ifdef HAVE_LDAP_INITIALIZE
1049     if (ldap_conf.uri != NULL) {
1050         DPRINTF(("ldap_initialize(ld, %s)", ldap_conf.uri), 2);
1051         rc = ldap_initialize(&ld, ldap_conf.uri);
1052     } else
1053 #endif /* HAVE_LDAP_INITIALIZE */
1054         rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);
1055     if (rc != LDAP_SUCCESS) {
1056         warnx("unable to initialize LDAP: %s", ldap_err2string(rc));
1057         return(NULL);
1058     }
1059
1060     /* Set LDAP options */
1061     if (sudo_ldap_set_options(ld) < 0)
1062         return(NULL);
1063
1064     if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
1065 #ifdef HAVE_LDAP_START_TLS_S
1066         rc = ldap_start_tls_s(ld, NULL, NULL);
1067         if (rc != LDAP_SUCCESS) {
1068             warnx("ldap_start_tls_s(): %s", ldap_err2string(rc));
1069             ldap_unbind(ld);
1070             return(NULL);
1071         }
1072         DPRINTF(("ldap_start_tls_s() ok"), 1);
1073 #else
1074         warnx("start_tls specified but LDAP libs do not support ldap_start_tls_s()");
1075 #endif /* HAVE_LDAP_START_TLS_S */
1076     }
1077
1078     /* Actually connect */
1079     if ((rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw))) {
1080         warnx("ldap_simple_bind_s: %s", ldap_err2string(rc));
1081         return(NULL);
1082     }
1083     DPRINTF(("ldap_simple_bind_s() ok"), 1);
1084
1085     return(ld);
1086 }
1087
1088 static void
1089 sudo_ldap_update_defaults(ld)
1090     LDAP *ld;
1091 {
1092     LDAPMessage *entry = NULL, *result = NULL;   /* used for searches */
1093     int rc;                                      /* temp return value */
1094
1095     rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
1096         "cn=defaults", NULL, 0, &result);
1097     if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
1098         DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
1099         sudo_ldap_parse_options(ld, entry);
1100     } else
1101         DPRINTF(("no default options found!"), 1);
1102
1103     if (result)
1104         ldap_msgfree(result);
1105 }
1106
1107 /*
1108  * like sudoers_lookup() - only LDAP style
1109  */
1110 int
1111 sudo_ldap_check(pwflag)
1112     int pwflag;
1113 {
1114     LDAP *ld;
1115     LDAPMessage *entry = NULL, *result = NULL;  /* used for searches */
1116     char *filt;                                 /* used to parse attributes */
1117     int rc, ret = FALSE, do_netgr;              /* temp/final return values */
1118     int setenv_implied;
1119     int ldap_user_matches = FALSE, ldap_host_matches = FALSE; /* flags */
1120
1121     /* Open a connection to the LDAP server. */
1122     if ((ld = sudo_ldap_open()) == NULL)
1123         return(VALIDATE_ERROR);
1124
1125     /* Parse Default options. */
1126     sudo_ldap_update_defaults(ld);
1127
1128     /*
1129      * Okay - time to search for anything that matches this user
1130      * Lets limit it to only two queries of the LDAP server
1131      *
1132      * The first pass will look by the username, groups, and
1133      * the keyword ALL.  We will then inspect the results that
1134      * came back from the query.  We don't need to inspect the
1135      * sudoUser in this pass since the LDAP server already scanned
1136      * it for us.
1137      *
1138      * The second pass will return all the entries that contain
1139      * user netgroups.  Then we take the netgroups returned and
1140      * try to match them against the username.
1141      */
1142     setenv_implied = FALSE;
1143     for (do_netgr = 0; !ret && do_netgr < 2; do_netgr++) {
1144         filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1();
1145         DPRINTF(("ldap search '%s'", filt), 1);
1146         rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
1147             NULL, 0, &result);
1148         if (rc != LDAP_SUCCESS)
1149             DPRINTF(("nothing found for '%s'", filt), 1);
1150         efree(filt);
1151
1152         /* parse each entry returned from this most recent search */
1153         entry = rc ? NULL : ldap_first_entry(ld, result);
1154         while (entry != NULL) {
1155             DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
1156             if (
1157             /* first verify user netgroup matches - only if in pass 2 */
1158                 (!do_netgr || sudo_ldap_check_user_netgroup(ld, entry)) &&
1159             /* remember that user matched */
1160                 (ldap_user_matches = -1) &&
1161             /* verify host match */
1162                 sudo_ldap_check_host(ld, entry) &&
1163             /* remember that host matched */
1164                 (ldap_host_matches = -1) &&
1165             /* add matches for listing later */
1166                 sudo_ldap_add_match(ld, entry, pwflag) &&
1167             /* verify command match */
1168                 sudo_ldap_check_command(ld, entry, &setenv_implied) &&
1169             /* verify runas match */
1170                 sudo_ldap_check_runas(ld, entry)
1171                 ) {
1172                 /* We have a match! */
1173                 DPRINTF(("Perfect Matched!"), 1);
1174                 /* pick up any options */
1175                 if (setenv_implied)
1176                     def_setenv = TRUE;
1177                 sudo_ldap_parse_options(ld, entry);
1178                 /* make sure we don't reenter loop */
1179                 ret = VALIDATE_OK;
1180                 /* break from inside for loop */
1181                 break;
1182             }
1183             entry = ldap_next_entry(ld, entry);
1184         }
1185         if (result)
1186             ldap_msgfree(result);
1187         result = NULL;
1188     }
1189
1190     sudo_ldap_close(ld);                /* shut down connection */
1191
1192     DPRINTF(("user_matches=%d", ldap_user_matches), 1);
1193     DPRINTF(("host_matches=%d", ldap_host_matches), 1);
1194
1195     /* Check for special case for -v, -k, -l options */
1196     if (pwflag && ldap_user_matches && ldap_host_matches) {
1197         /*
1198          * Handle verifypw & listpw
1199          *
1200          * To be extra paranoid, since we haven't read any NOPASSWD options
1201          * in /etc/sudoers yet, but we have to make the decission now, lets
1202          * assume the worst and prefer to prompt for password unless the setting
1203          * is "never". (example verifypw=never or listpw=never)
1204          *
1205          */
1206         ret = VALIDATE_OK;
1207         if (pwflag == -1) {
1208             SET(ret, FLAG_NOPASS);              /* -k or -K */
1209         } else {
1210             switch (sudo_defs_table[pwflag].sd_un.tuple) {
1211             case never:
1212                 SET(ret, FLAG_NOPASS);
1213                 break;
1214             case always:
1215                 if (def_authenticate)
1216                     SET(ret, FLAG_CHECK_USER);
1217                 break;
1218             default:
1219                 break;
1220             }
1221         }
1222     }
1223     if (ISSET(ret, VALIDATE_OK)) {
1224         /* we have a match, should we check the password? */
1225         if (!def_authenticate)
1226             SET(ret, FLAG_NOPASS);
1227         if (def_noexec)
1228             SET(ret, FLAG_NOEXEC);
1229         if (def_setenv)
1230             SET(ret, FLAG_SETENV);
1231     } else {
1232         /* we do not have a match */
1233         ret = VALIDATE_NOT_OK;
1234         if (pwflag)
1235             SET(ret, FLAG_NO_CHECK);
1236         else if (!ldap_user_matches)
1237             SET(ret, FLAG_NO_USER);
1238         else if (!ldap_host_matches)
1239             SET(ret, FLAG_NO_HOST);
1240     }
1241     DPRINTF(("sudo_ldap_check(%d)=0x%02x", pwflag, ret), 1);
1242
1243     return(ret);
1244 }
1245
1246 /*
1247  * shut down LDAP connection
1248  */
1249 static void
1250 sudo_ldap_close(LDAP *ld)
1251 {
1252     if (ld)
1253         ldap_unbind_s(ld);
1254 }