Imported Debian patch 1.6.8p9-2
[debian/sudo] / ldap.c
1 /*
2  * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include "config.h"
18
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/stat.h>
22 #include <stdio.h>
23 #ifdef STDC_HEADERS
24 # include <stdlib.h>
25 # include <stddef.h>
26 #else
27 # ifdef HAVE_STDLIB_H
28 #  include <stdlib.h>
29 # endif
30 #endif /* STDC_HEADERS */
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #else
34 # ifdef HAVE_STRINGS_H
35 #  include <strings.h>
36 # endif
37 #endif /* HAVE_STRING_H */
38 #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
39 # include <malloc.h>
40 #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif /* HAVE_UNISTD_H */
44 #include <ctype.h>
45 #include <pwd.h>
46 #include <grp.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <netdb.h>
50 #include <errno.h>
51 #ifdef HAVE_LBER_H
52 #include <lber.h>
53 #endif
54 #include <ldap.h>
55
56 #include "sudo.h"
57 #include "parse.h"
58
59 #ifndef lint
60 static const char rcsid[] = "$Sudo: ldap.c,v 1.14 2004/09/02 04:03:25 aaron Exp $";
61 #endif /* lint */
62
63 /* LDAP code below */
64
65 #ifndef BUF_SIZ
66 #define BUF_SIZ 1024
67 #endif
68
69 #ifndef LDAP_OPT_SUCCESS
70 #define LDAP_OPT_SUCCESS LDAP_SUCCESS
71 #endif
72
73 extern int printmatches;
74
75 /* ldap configuration structure */
76 struct ldap_config {
77   char *host;
78   int  port;
79   int  version;
80   char *uri;
81   char *binddn;
82   char *bindpw;
83   char *base;
84   char *ssl;
85   int  tls_checkpeer;
86   char *tls_cacertfile;
87   char *tls_cacertdir;
88   char *tls_random_file;
89   char *tls_cipher_suite;
90   char *tls_certfile;
91   char *tls_keyfile;
92   int debug;
93 } ldap_conf;
94
95 /*
96  * Walks through search result and returns true if we have a
97  * netgroup that matches our user
98  */
99
100
101 int
102 sudo_ldap_check_user_netgroup(ld,entry)
103   LDAP *ld;
104   LDAPMessage *entry;
105 {
106   char **v=NULL;
107   char **p=NULL;
108
109   int  ret=0;
110
111   if (!entry) return ret;
112
113   /* get the values from the entry */
114   v=ldap_get_values(ld,entry,"sudoUser");
115
116   /* walk through values */
117   for (p=v; p && *p && !ret;p++)
118   {
119     if (ldap_conf.debug>1) printf("ldap sudoUser netgroup '%s' ...",*p);
120
121     /* match any */
122     if (netgr_matches(*p,NULL,NULL,user_name)) ret=1;
123
124     if (ldap_conf.debug>1) printf(" %s\n",ret ? "MATCH!" : "not");
125   }
126
127   /* cleanup */
128   if (v) ldap_value_free(v);
129
130   /* all done */
131   return ret;
132 }
133
134
135 /*
136  * Walks through search result and returns true if we have a
137  * host match
138  */
139 int
140 sudo_ldap_check_host(ld,entry)
141   LDAP *ld;
142   LDAPMessage *entry;
143 {
144   char **v=NULL;
145   char **p=NULL;
146
147   int  ret=0;
148
149   if (!entry) return ret;
150
151   /* get the values from the entry */
152   v=ldap_get_values(ld,entry,"sudoHost");
153
154   /* walk through values */
155   for (p=v; p && *p && !ret;p++)
156   {
157     if (ldap_conf.debug>1) printf("ldap sudoHost '%s' ...",*p);
158
159     /* match any or address or netgroup or hostname */
160     if (
161          !strcasecmp(*p,"ALL") ||
162          addr_matches(*p) ||
163          netgr_matches(*p,user_host,user_shost,NULL) ||
164          !hostname_matches(user_shost,user_host,*p)
165        )
166     {
167        ret=1;
168     }
169
170
171     if (ldap_conf.debug>1) printf(" %s\n",ret ? "MATCH!" : "not");
172   }
173
174   /* cleanup */
175   if (v) ldap_value_free(v);
176
177   /* all done */
178   return ret;
179 }
180
181 /*
182  * Walks through search result and returns true if we have a
183  * runas match.  Since the runas directive in /etc/sudoers is optional,
184  * so is the sudoRunAs attribute.
185  *
186  */
187
188 int sudo_ldap_check_runas(ld,entry)
189   LDAP *ld;
190   LDAPMessage *entry;
191 {
192   char **v=NULL;
193   char **p=NULL;
194
195   int  ret=0;
196
197   if (!entry) return ret;
198
199   /* get the values from the entry */
200   v=ldap_get_values(ld,entry,"sudoRunAs");
201
202   /* BUG:
203    *
204    * if runas is not specified on the command line, the only information as
205    * to which user to run as is in the runas_default option.
206    * We should check check to see if we have the local option present.
207    * Unfortunately we don't parse these options until after this routine
208    * says yes * or no.  The query has already returned, so we could peek at the
209    * attribute values here though.
210    *
211    * For now just require users to always use -u option unless its set
212    * in the global defaults. This behaviour is no different than the global
213    * /etc/sudoers.
214    *
215    * Sigh - maybe add this feature later
216    *
217    */
218
219   /* If there are no runas entries, then match the runas_default with
220    * whats on the command line
221    */
222   if (!v)
223   {
224     ret=!strcasecmp(*user_runas,def_runas_default);
225   }
226
227   /* what about the case where exactly one runas is specified in
228    * the config and the user forgets the -u option, should we
229    * switch it?  - Probably not
230    */
231
232   /* walk through values returned, looking for a match*/
233   for (p=v; p && *p && !ret;p++)
234   {
235     if (ldap_conf.debug>1) printf("ldap sudoRunAs '%s' ...",*p);
236
237     if (
238          !strcasecmp(*p,*user_runas) ||
239          !strcasecmp(*p,"ALL")
240        )
241     {
242        ret = 1;
243     }
244
245     if (ldap_conf.debug>1) printf(" %s\n",ret ? "MATCH!" : "not");
246   }
247
248   /* cleanup */
249   if (v) ldap_value_free(v);
250
251   /* all done */
252   return ret;
253 }
254
255 /*
256  * Walks through search result and returns true if we have a
257  * command match
258  */
259 int sudo_ldap_check_command(ld,entry)
260   LDAP *ld;
261   LDAPMessage *entry;
262 {
263   char **v=NULL;
264   char **p=NULL;
265   char *allowed_cmnd;
266   char *allowed_args;
267   int  ret=0;
268   int  foundbang;
269
270   if (!entry) return ret;
271
272   v=ldap_get_values(ld,entry,"sudoCommand");
273
274   /* get_first_entry */
275   for (p=v; p && *p && ret>=0;p++){
276     if (ldap_conf.debug>1) printf("ldap sudoCommand '%s' ...",*p);
277
278     /* Match against ALL ? */
279     if (!strcasecmp(*p,"ALL")) {
280       ret=1;
281       if (ldap_conf.debug>1) printf(" MATCH!\n");
282       continue;
283     }
284
285     /* check for !command */
286     if (**p != '!'){
287       foundbang=0;
288       allowed_cmnd=estrdup(*p);  /* command */
289     } else {
290       foundbang=1;
291       allowed_cmnd=estrdup(1+*p); /* !command */
292     }
293
294     /* split optional args away from command */
295     allowed_args=strchr(allowed_cmnd,' ');
296     if (allowed_args) *allowed_args++='\0';
297
298     /* check the command like normal */
299     if (command_matches(allowed_cmnd,allowed_args)) {
300       if (!foundbang){
301         ret=1; /* allowed, but keep checking for a deny match */
302       } else {
303         ret=-1; /* denied by match, no need to check for more */
304       }
305       if (ldap_conf.debug>1) printf(" MATCH!\n");
306     } else {
307       if (ldap_conf.debug>1) printf(" not\n");
308     }
309
310     /* cleanup */
311     free(allowed_cmnd);
312   }
313
314   /* more cleanup */
315   if (v) ldap_value_free(v);
316
317   /* all done */
318   return ret > 0; /* say true if we found at least one ALLOW and no DENY */
319 }
320
321 /*
322  * Read sudoOption, modify the defaults as we go.
323  * This is used once from the cn=defaults entry
324  * and also once when a final sudoRole is matched.
325  *
326  */
327 void
328 sudo_ldap_parse_options(ld,entry)
329   LDAP *ld;
330   LDAPMessage *entry;
331 {
332   /* used to parse attributes */
333   char **v=NULL;
334   char **p=NULL;
335   char *var;
336   char *val;
337   char op;
338
339   if (!entry) return;
340
341   v=ldap_get_values(ld,entry,"sudoOption");
342
343   /* walk through options */
344   for (p=v; p && *p;p++){
345
346     if (ldap_conf.debug>1) printf("ldap sudoOption: '%s'\n",*p);
347     var=estrdup(*p);
348     /* check for = char */
349     val=strchr(var,'=');
350
351     /* check for equals sign past first char */
352     if (val>var){
353       *val++='\0'; /* split on = and truncate var */
354       op=*(val-2); /* peek for += or -= cases */
355       if (op == '+' || op == '-') {
356         *(val-2)='\0'; /* found, remove extra char */
357         /* case var+=val or var-=val */
358         set_default(var,val,(int)op);
359       } else {
360         /* case var=val */
361         set_default(var,val,TRUE);
362       }
363     } else if (*var=='!'){
364       /* case !var Boolean False */
365       set_default(var+1,NULL,FALSE);
366     }  else {
367       /* case var Boolean True */
368       set_default(var,NULL,TRUE);
369     }
370     free(var);
371
372   }
373
374   if (v) ldap_value_free(v);
375
376 }
377
378 /*
379  * Concatenate strings, dynamically growing them as necessary.
380  * Strings can be arbitrarily long and are allocated/reallocated on
381  * the fly.  Make sure to free them when you are done.
382  *
383  * Usage:
384  *
385  * char *s=NULL;
386  * size_t sz;
387  *
388  * ncat(&s,&sz,"This ");
389  * ncat(&s,&sz,"is ");
390  * ncat(&s,&sz,"an ");
391  * ncat(&s,&sz,"arbitrarily ");
392  * ncat(&s,&sz,"long ");
393  * ncat(&s,&sz,"string!");
394  *
395  * printf("String Value='%s', but has %d bytes allocated\n",s,sz);
396  *
397  */
398 void
399 ncat(s,sz,src)
400   char **s;
401   size_t *sz;
402   char *src;
403 {
404   size_t nsz;
405
406   /* handle initial alloc */
407   if (*s == NULL){
408     *s=estrdup(src);
409     *sz=strlen(src)+1;
410     return;
411   }
412
413   /* handle realloc */
414   nsz= strlen(*s) + strlen(src) + 1;
415   if (*sz < nsz) *s=erealloc( (void *)*s , *sz=nsz*2);
416   strlcat(*s,src,*sz);
417 }
418
419
420 /*
421  * builds together a filter to check against ldap
422  */
423 char *
424 sudo_ldap_build_pass1()
425 {
426   struct group *grp;
427   gid_t *grplist=NULL;
428   int ngrps;
429   int i;
430
431   char *b=NULL;
432   size_t sz;
433
434   /* global OR */
435   ncat(&b,&sz,"(|");
436
437   /* build filter sudoUser=user_name */
438   ncat(&b,&sz,"(sudoUser=");
439   ncat(&b,&sz,user_name);
440   ncat(&b,&sz,")");
441
442   /* Append primary group */
443   grp=getgrgid(getgid());
444   if (grp!=NULL){
445     ncat(&b,&sz,"(sudoUser=%");
446     ncat(&b,&sz,grp->gr_name);
447     ncat(&b,&sz,")");
448   }
449
450   /* handle arbitrary number of groups */
451   if (0<(ngrps=getgroups(0,NULL))){
452     grplist=calloc(ngrps,sizeof(gid_t));
453     if (grplist!=NULL && (0<getgroups(ngrps,grplist)))
454       for(i=0;i<ngrps;i++){
455         if((grp=getgrgid(grplist[i]))!=NULL){
456           ncat(&b,&sz,"(sudoUser=%");
457           ncat(&b,&sz,grp->gr_name);
458           ncat(&b,&sz,")");
459         }
460       }
461   }
462
463
464   /* Add ALL to list */
465   ncat(&b,&sz,"(sudoUser=ALL)");
466
467   /* End of OR List */
468   ncat(&b,&sz,")");
469   return b ;
470 }
471
472 /*
473  * Map yes/true/on to 1, no/false/off to 0, else -1
474  */
475 int
476 _atobool(s)
477   char *s;
478 {
479   if (!strcasecmp(s,"yes") || !strcasecmp(s,"true")  || !strcasecmp(s,"on"))
480     return 1;
481   if (!strcasecmp(s,"no")  || !strcasecmp(s,"false") || !strcasecmp(s,"off"))
482     return 0;
483   return -1;
484 }
485
486 int
487 sudo_ldap_read_config()
488 {
489   FILE *f;
490   char buf[BUF_SIZ];
491   char *c;
492   char *keyword;
493   char *value;
494
495   ldap_conf.tls_checkpeer=-1; /* default */
496
497   f=fopen(_PATH_LDAP_CONF,"r");
498   if (!f) return 0;
499   while (f && fgets(buf,sizeof(buf)-1,f)){
500     c=buf;
501     if (*c == '#')  continue; /* ignore comment */
502     if (*c == '\n') continue; /* skip newline */
503     if (!*c)        continue; /* incomplete last line */
504
505     /* skip whitespace before keyword */
506     while (isspace(*c)) c++;
507     keyword=c;
508
509     /* properly terminate keyword string */
510     while (*c && !isspace(*c)) c++;
511     if (*c) {
512       *c='\0'; /* terminate keyword */
513       c++;
514     }
515
516     /* skip whitespace before value */
517     while (isspace(*c)) c++;
518     value=c;
519
520     /* trim whitespace after value */
521     while (*c) c++; /* wind to end */
522     while (--c > value && isspace(*c)) *c='\0';
523
524     /* The following macros make the code much more readable */
525
526 #define MATCH_S(x,y) if (!strcasecmp(keyword,x)) \
527     { if (y) free(y); y=estrdup(value); }
528 #define MATCH_I(x,y) if (!strcasecmp(keyword,x)) { y=atoi(value); }
529 #define MATCH_B(x,y) if (!strcasecmp(keyword,x)) { y=_atobool(value); }
530
531
532
533     /* parse values using a continues chain of
534      * if else if else if else if else ... */
535          MATCH_S("host",    ldap_conf.host)
536     else MATCH_I("port",    ldap_conf.port)
537     else MATCH_S("ssl",     ldap_conf.ssl)
538     else MATCH_B("tls_checkpeer",   ldap_conf.tls_checkpeer)
539     else MATCH_S("tls_cacertfile",  ldap_conf.tls_cacertfile)
540     else MATCH_S("tls_cacertdir",   ldap_conf.tls_cacertdir)
541     else MATCH_S("tls_randfile",    ldap_conf.tls_random_file)
542     else MATCH_S("tls_ciphers",     ldap_conf.tls_cipher_suite)
543     else MATCH_S("tls_cert",        ldap_conf.tls_certfile)
544     else MATCH_S("tls_key",         ldap_conf.tls_keyfile)
545     else MATCH_I("ldap_version", ldap_conf.version)
546     else MATCH_S("uri",     ldap_conf.uri)
547     else MATCH_S("binddn",  ldap_conf.binddn)
548     else MATCH_S("bindpw",  ldap_conf.bindpw)
549     else MATCH_S("sudoers_base",    ldap_conf.base)
550     else MATCH_I("sudoers_debug",   ldap_conf.debug)
551     else {
552
553     /* The keyword was unrecognized.  Since this config file is shared
554      * by multiple programs, it is appropriate to silently ignore options this
555      * program does not understand
556      */
557     }
558
559   } /* parse next line */
560
561   if (f) fclose(f);
562
563   /* defaults */
564   if (!ldap_conf.version) ldap_conf.version=3;
565   if (!ldap_conf.port) ldap_conf.port=389;
566   if (!ldap_conf.host) ldap_conf.host=estrdup("localhost");
567
568
569   if (ldap_conf.debug>1) {
570     printf("LDAP Config Summary\n");
571     printf("===================\n");
572 #ifdef HAVE_LDAP_INITIALIZE
573     if (ldap_conf.uri){
574       printf("uri          %s\n", ldap_conf.uri);
575     } else
576 #endif
577     {
578     printf("host         %s\n", ldap_conf.host ?
579                  ldap_conf.host   : "(NONE)");
580     printf("port         %d\n", ldap_conf.port);
581     }
582     printf("ldap_version %d\n", ldap_conf.version);
583
584     printf("sudoers_base %s\n", ldap_conf.base ?
585                  ldap_conf.base : "(NONE) <---Sudo will ignore ldap)");
586     printf("binddn       %s\n", ldap_conf.binddn ?
587                  ldap_conf.binddn : "(anonymous)");
588     printf("bindpw       %s\n", ldap_conf.bindpw ?
589                  ldap_conf.bindpw : "(anonymous)");
590 #ifdef HAVE_LDAP_START_TLS_S
591     printf("ssl          %s\n", ldap_conf.ssl ?
592                  ldap_conf.ssl    : "(no)");
593 #endif
594     printf("===================\n");
595   }
596
597   /* if no base is defined, ignore LDAP */
598   if (!ldap_conf.base) return 0;
599   /* All is good */
600   return 1;
601 }
602
603 /*
604   like perl's join(sep,@ARGS)
605 */
606 char *
607 _ldap_join_values(sep,v)
608   char *sep;
609   char **v;
610 {
611   char **p=NULL;
612   char *b=NULL;
613   size_t sz=0;
614
615   /* paste values together */
616   for (p=v; p && *p;p++){
617     if (p!=v && sep!=NULL) ncat(&b,&sz,sep); /* append seperator */
618     ncat(&b,&sz,*p); /* append value */
619   }
620
621   /* sanity check */
622   if (b[0]=='\0'){
623     /* something went wrong, put something here */
624     ncat(&b,&sz,"(empty list)"); /* append value */
625   }
626
627   /* all done */
628   return b;
629 }
630
631 char * sudo_ldap_cm_list=NULL;
632 size_t sudo_ldap_cm_list_size;
633
634 #define SAVE_LIST(x) ncat(&sudo_ldap_cm_list,&sudo_ldap_cm_list_size,(x))
635 /*
636  * Walks through search result and returns true if we have a
637  * command match
638  */
639 int
640 sudo_ldap_add_match(ld,entry)
641   LDAP *ld;
642   LDAPMessage *entry;
643 {
644   char **v=NULL;
645   char *dn;
646   char **edn;
647
648   /* if we are not collecting matches, then don't print them */
649   if (printmatches != TRUE) return 1;
650
651   /* collect the dn, only show the rdn */
652   dn=ldap_get_dn(ld,entry);
653   edn=dn ? ldap_explode_dn(dn,1) : NULL;
654   SAVE_LIST("\nLDAP Role: ");
655   SAVE_LIST((edn && *edn) ? *edn : "UNKNOWN");
656   SAVE_LIST("\n");
657   if (dn)  ldap_memfree(dn);
658   if (edn) ldap_value_free(edn);
659
660   /* get the Runas Values from the entry */
661   v=ldap_get_values(ld,entry,"sudoRunAs");
662   if (v && *v){
663     SAVE_LIST("  RunAs: (");
664     SAVE_LIST(_ldap_join_values(", ",v));
665     SAVE_LIST(")\n");
666   }
667   if (v) ldap_value_free(v);
668
669   /* get the Command Values from the entry */
670   v=ldap_get_values(ld,entry,"sudoCommand");
671   if (v && *v){
672     SAVE_LIST("  Commands:\n    ");
673     SAVE_LIST(_ldap_join_values("\n    ",v));
674     SAVE_LIST("\n");
675   } else {
676     SAVE_LIST("  Commands: NONE\n");
677   }
678   if (v) ldap_value_free(v);
679
680   return 0; /* Don't stop at the first match */
681 }
682 #undef SAVE_LIST
683
684 void
685 sudo_ldap_list_matches()
686 {
687   if (sudo_ldap_cm_list!=NULL) printf("%s",sudo_ldap_cm_list);
688 }
689
690 /*
691  * like sudoers_lookup() - only LDAP style
692  *
693  */
694
695 int
696 sudo_ldap_check(pwflag)
697 int pwflag;
698 {
699
700   LDAP *ld=NULL;
701
702   /* Used for searches */
703   LDAPMessage *result=NULL;
704   LDAPMessage *entry=NULL;
705   /* used to parse attributes */
706   char *filt;
707   /* temp/final return values */
708   int rc=0;
709   int ret=0;
710   int pass=0;
711   /* flags */
712   int ldap_user_matches=0;
713   int ldap_host_matches=0;
714
715   if (!sudo_ldap_read_config())  return VALIDATE_ERROR;
716
717   /* macro to set option, error on failure plus consistent debugging */
718 #define SET_OPT(opt,optname,val) \
719   if (ldap_conf.val!=NULL) { \
720     if (ldap_conf.debug>1) fprintf(stderr, \
721            "ldap_set_option(LDAP_OPT_%s,\"%s\")\n",optname,ldap_conf.val); \
722     rc=ldap_set_option(ld,opt,ldap_conf.val); \
723     if(rc != LDAP_OPT_SUCCESS){ \
724       fprintf(stderr,"ldap_set_option(LDAP_OPT_%s,\"%s\")=%d: %s\n", \
725            optname, ldap_conf.val, rc, ldap_err2string(rc)); \
726       return VALIDATE_ERROR ; \
727     } \
728   } \
729
730   /* like above, but assumes val is in int */
731 #define SET_OPTI(opt,optname,val) \
732     if (ldap_conf.debug>1) fprintf(stderr, \
733            "ldap_set_option(LDAP_OPT_%s,0x%02x)\n",optname,ldap_conf.val); \
734     rc=ldap_set_option(ld,opt,&ldap_conf.val); \
735     if(rc != LDAP_OPT_SUCCESS){ \
736       fprintf(stderr,"ldap_set_option(LDAP_OPT_%s,0x%02x)=%d: %s\n", \
737            optname, ldap_conf.val, rc, ldap_err2string(rc)); \
738       return VALIDATE_ERROR ; \
739     } \
740
741   /* attempt to setup ssl options */
742 #ifdef    LDAP_OPT_X_TLS_CACERTFILE
743   SET_OPT(LDAP_OPT_X_TLS_CACERTFILE,   "X_TLS_CACERTFILE",   tls_cacertfile);
744 #endif /* LDAP_OPT_X_TLS_CACERTFILE */
745
746 #ifdef    LDAP_OPT_X_TLS_CACERTDIR
747   SET_OPT(LDAP_OPT_X_TLS_CACERTDIR,    "X_TLS_CACERTDIR",    tls_cacertdir);
748 #endif /* LDAP_OPT_X_TLS_CACERTDIR */
749
750 #ifdef    LDAP_OPT_X_TLS_CERTFILE
751   SET_OPT(LDAP_OPT_X_TLS_CERTFILE,     "X_TLS_CERTFILE",     tls_certfile);
752 #endif /* LDAP_OPT_X_TLS_CERTFILE */
753
754 #ifdef    LDAP_OPT_X_TLS_KEYFILE
755   SET_OPT(LDAP_OPT_X_TLS_KEYFILE,      "X_TLS_KEYFILE",      tls_keyfile);
756 #endif /* LDAP_OPT_X_TLS_KEYFILE */
757
758 #ifdef    LDAP_OPT_X_TLS_CIPHER_SUITE
759   SET_OPT(LDAP_OPT_X_TLS_CIPHER_SUITE, "X_TLS_CIPHER_SUITE", tls_cipher_suite);
760 #endif /* LDAP_OPT_X_TLS_CIPHER_SUITE */
761
762 #ifdef    LDAP_OPT_X_TLS_RANDOM_FILE
763   SET_OPT(LDAP_OPT_X_TLS_RANDOM_FILE,  "X_TLS_RANDOM_FILE",  tls_random_file);
764 #endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
765
766 #ifdef    LDAP_OPT_X_TLS_REQUIRE_CERT
767   /* check the server certificate? */
768   if (ldap_conf.tls_checkpeer!=-1){
769    SET_OPTI(LDAP_OPT_X_TLS_REQUIRE_CERT,"X_TLS_REQUIRE_CERT",tls_checkpeer);
770   }
771 #endif /* LDAP_OPT_X_TLS_REQUIRE_CERT */
772
773   /* attempt connect */
774 #ifdef HAVE_LDAP_INITIALIZE
775   if (ldap_conf.uri) {
776
777     if (ldap_conf.debug>1) fprintf(stderr,
778            "ldap_initialize(ld,%s)\n",ldap_conf.uri);
779
780     rc=ldap_initialize(&ld,ldap_conf.uri);
781     if(rc){
782       fprintf(stderr, "ldap_initialize()=%d : %s\n",
783            rc,ldap_err2string(rc));
784       return VALIDATE_ERROR;
785     }
786   } else
787 #endif /* HAVE_LDAP_INITIALIZE */
788   if (ldap_conf.host) {
789
790     if (ldap_conf.debug>1) fprintf(stderr,
791            "ldap_init(%s,%d)\n",ldap_conf.host,ldap_conf.port);
792
793     ld=ldap_init(ldap_conf.host,ldap_conf.port);
794     if (!ld) {
795       fprintf(stderr, "ldap_init(): errno=%d : %s\n",
796                  errno, strerror(errno));
797       return VALIDATE_ERROR;
798     }
799   }
800
801 #ifdef LDAP_OPT_PROTOCOL_VERSION
802
803   /* Set the LDAP Protocol version */
804   SET_OPTI(LDAP_OPT_PROTOCOL_VERSION,"PROTOCOL_VERSION", version);
805
806 #endif /* LDAP_OPT_PROTOCOL_VERSION */
807
808 #ifdef HAVE_LDAP_START_TLS_S
809   /* Turn on TLS */
810   if (ldap_conf.ssl && !strcasecmp(ldap_conf.ssl, "start_tls")){
811     rc = ldap_start_tls_s(ld, NULL, NULL);
812     if (rc != LDAP_SUCCESS) {
813       fprintf(stderr, "ldap_start_tls_s(): %d: %s\n", rc, ldap_err2string(rc));
814       ldap_unbind(ld);
815       return VALIDATE_ERROR;
816     }
817
818     if (ldap_conf.debug) printf("ldap_start_tls_s() ok\n");
819   }
820 #endif /* HAVE_LDAP_START_TLS_S */
821
822   /* Actually connect */
823
824   rc=ldap_simple_bind_s(ld,ldap_conf.binddn,ldap_conf.bindpw);
825   if(rc){
826     fprintf(stderr,"ldap_simple_bind_s()=%d : %s\n",
827            rc, ldap_err2string(rc));
828     return VALIDATE_ERROR ;
829   }
830
831   if (ldap_conf.debug) printf("ldap_bind() ok\n");
832
833
834   /* Parse Default Options */
835
836   rc=ldap_search_s(ld,ldap_conf.base,LDAP_SCOPE_ONELEVEL,
837              "cn=defaults",NULL,0,&result);
838   if (!rc && (entry=ldap_first_entry(ld,result))){
839     if (ldap_conf.debug) printf("found:%s\n",ldap_get_dn(ld,entry));
840     sudo_ldap_parse_options(ld,entry);
841   } else {
842     if (ldap_conf.debug) printf("no default options found!\n");
843   }
844
845   if (result) ldap_msgfree(result);
846   result=NULL;
847
848   /*
849    * Okay - time to search for anything that matches this user
850    * Lets limit it to only two queries of the LDAP server
851    *
852    * The first pass will look by the username, groups, and
853    * the keyword ALL.  We will then inspect the results that
854    * came back from the query.  We don't need to inspect the
855    * sudoUser in this pass since the LDAP server already scanned
856    * it for us.
857    *
858    * The second pass will return all the entries that contain
859    * user netgroups.  Then we take the netgroups returned and
860    * try to match them against the username.
861    *
862    */
863
864   for(pass=1;!ret && pass<=2;pass++){
865
866     if (pass==1) {
867       /* Want the entries that match our usernames or groups */
868       filt=sudo_ldap_build_pass1();
869     } else { /* pass=2 */
870       /* Want the entries that have user netgroups in them. */
871       filt=strdup("sudoUser=+*");
872     }
873     if (ldap_conf.debug) printf("ldap search '%s'\n",filt);
874     rc=ldap_search_s(ld,ldap_conf.base,LDAP_SCOPE_ONELEVEL,
875                filt,NULL,0,&result);
876     if (rc) {
877       if (ldap_conf.debug) printf("nothing found for '%s'\n",filt);
878     }
879     if (filt) free (filt);
880     /* parse each entry returned from this most recent search */
881     for(
882         entry=rc ? NULL : ldap_first_entry(ld,result);
883         entry!=NULL;
884         entry=ldap_next_entry(ld,entry))
885     {
886       if (ldap_conf.debug) printf("found:%s\n",ldap_get_dn(ld,entry));
887       if (
888           /* first verify user netgroup matches - only if in pass 2 */
889           (pass!=2 || sudo_ldap_check_user_netgroup(ld,entry)) &&
890        /* remember that user matched */
891        (ldap_user_matches=-1) &&
892           /* verify host match */
893           sudo_ldap_check_host(ld,entry) &&
894        /* remember that host matched */
895        (ldap_host_matches=-1) &&
896           /* add matches for listing later */
897           sudo_ldap_add_match(ld,entry) &&
898           /* verify command match */
899           sudo_ldap_check_command(ld,entry) &&
900           /* verify runas match */
901           sudo_ldap_check_runas(ld,entry)
902       )
903       {
904         /* We have a match! */
905         if(ldap_conf.debug) printf("Perfect Matched!\n");
906         /* pick up any options */
907         sudo_ldap_parse_options(ld,entry);
908         /* make sure we dont reenter loop */
909         ret=VALIDATE_OK;
910         /* break from inside for loop */
911         break;
912       }
913
914     }
915     if (result) ldap_msgfree(result);
916     result=NULL;
917
918   }
919
920   /* shut down connection */
921   if (ld) ldap_unbind_s(ld);
922
923
924   if (ldap_conf.debug) printf("user_matches=%d\n",ldap_user_matches);
925   if (ldap_conf.debug) printf("host_matches=%d\n",ldap_host_matches);
926
927   /* Check for special case for -v, -k, -l options */
928   if (pwflag && ldap_user_matches && ldap_host_matches){
929     /*
930      * Handle verifypw & listpw
931      *
932      * To be extra paranoid, since we haven't read any NOPASSWD options
933      * in /etc/sudoers yet, but we have to make the decission now, lets
934      * assume the worst and prefer to prompt for password unless the setting
935      * is "never". (example verifypw=never or listpw=never)
936      *
937      */
938     if (pwflag<0) { /* -k */
939       ret=VALIDATE_OK; SET(ret,FLAG_NOPASS);
940     } else if (sudo_defs_table[pwflag].sd_un.tuple == never){ /* see note above */
941       ret=VALIDATE_OK; SET(ret,FLAG_NOPASS);
942     } else {
943       ret=VALIDATE_OK; /* extra paranoid */
944     }
945   }
946
947   if (ISSET(ret,VALIDATE_OK)) {
948     /* We have a match.  Should we check the password? */
949     /* Note: This could be the global or a rule specific option */
950     if (!def_authenticate) SET(ret,FLAG_NOPASS);
951     /* Same logic with noexec */
952     if (def_noexec)        SET(ret,FLAG_NOEXEC);
953   } else {
954     /* we do not have a match */
955     ret=VALIDATE_NOT_OK;
956     if (!ldap_user_matches) SET(ret,FLAG_NO_USER);
957     else if (!ldap_host_matches) SET(ret,FLAG_NO_HOST);
958   }
959
960   if (ldap_conf.debug) printf("sudo_ldap_check(%d)=0x%02x\n",pwflag,ret);
961
962   return ret ;
963 }