--- /dev/null
+/*
+ * Copyright (c) 1996, 1998-2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 4. Products derived from this software may not be called "Sudo" nor
+ * may "Sudo" appear in their names without specific prior written
+ * permission from the author.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+# include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <ldap.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+
+#include "sudo.h"
+#include "parse.h"
+
+#ifndef lint
+static const char rcsid[] = "$Sudo$";
+#endif /* lint */
+
+/* LDAP code below */
+
+#ifndef LDAP_CONFIG
+#define LDAP_CONFIG "/etc/ldap.conf"
+#endif
+
+#ifndef BUF_SIZ
+#define BUF_SIZ 1024
+#endif
+
+extern int printmatches;
+
+/* ldap configuration structure */
+struct ldap_config {
+ char *host;
+ int port;
+ int version;
+ char *uri;
+ char *binddn;
+ char *bindpw;
+ char *base;
+ int debug;
+} ldap_conf;
+
+/*
+ * Walks through search result and returns true if we have a
+ * netgroup that matches our user
+ */
+
+
+int
+sudo_ldap_check_user_netgroup(ld,entry)
+ LDAP *ld;
+ LDAPMessage *entry;
+{
+ char **v=NULL;
+ char **p=NULL;
+
+ int ret=0;
+
+ if (!entry) return ret;
+
+ /* get the values from the entry */
+ v=ldap_get_values(ld,entry,"sudoUser");
+
+ /* walk through values */
+ for (p=v; p && *p && !ret;p++)
+ {
+ if (ldap_conf.debug>1) printf("ldap sudoUser netgroup '%s' ...",*p);
+
+ /* match any */
+ if (netgr_matches(*p,NULL,NULL,user_name)) ret=1;
+
+ if (ldap_conf.debug>1) printf(" %s\n",ret ? "MATCH!" : "not");
+ }
+
+ /* cleanup */
+ if (v) ldap_value_free(v);
+
+ /* all done */
+ return ret;
+}
+
+
+/*
+ * Walks through search result and returns true if we have a
+ * host match
+ */
+int
+sudo_ldap_check_host(ld,entry)
+ LDAP *ld;
+ LDAPMessage *entry;
+{
+ char **v=NULL;
+ char **p=NULL;
+
+ int ret=0;
+
+ if (!entry) return ret;
+
+ /* get the values from the entry */
+ v=ldap_get_values(ld,entry,"sudoHost");
+
+ /* walk through values */
+ for (p=v; p && *p && !ret;p++)
+ {
+ if (ldap_conf.debug>1) printf("ldap sudoHost '%s' ...",*p);
+
+ /* match any or address or netgroup or hostname */
+ if (
+ !strcasecmp(*p,"ALL") ||
+ addr_matches(*p) ||
+ netgr_matches(*p,user_host,user_shost,NULL) ||
+ !hostname_matches(user_shost,user_host,*p)
+ )
+ {
+ ret=1;
+ }
+
+
+ if (ldap_conf.debug>1) printf(" %s\n",ret ? "MATCH!" : "not");
+ }
+
+ /* cleanup */
+ if (v) ldap_value_free(v);
+
+ /* all done */
+ return ret;
+}
+
+/*
+ * Walks through search result and returns true if we have a
+ * runas match. Since the runas directive in /etc/sudoers is optional,
+ * so is the sudoRunAs attribute.
+ *
+ */
+
+int sudo_ldap_check_runas(ld,entry)
+ LDAP *ld;
+ LDAPMessage *entry;
+{
+ char **v=NULL;
+ char **p=NULL;
+
+ int ret=0;
+
+ if (!entry) return ret;
+
+ /* get the values from the entry */
+ v=ldap_get_values(ld,entry,"sudoRunAs");
+
+ /* BUG:
+ *
+ * if runas is not specified on the command line, the only information as
+ * to which user to run as is in the runas_default option.
+ * We should check check to see if we have the local option present.
+ * Unfortunately we don't parse these options until after this routine
+ * says yes * or no. The query has already returned, so we could peek at the
+ * attribute values here though.
+ *
+ * For now just require users to always use -u option unless its set
+ * in the global defaults. This behaviour is no different than the global
+ * /etc/sudoers.
+ *
+ * Sigh - maybe add this feature later
+ *
+ */
+
+ /* If there are no runas entries, then match the runas_default with
+ * whats on the command line
+ */
+ if (!v)
+ {
+ ret=!strcasecmp(*user_runas,def_runas_default);
+ }
+
+ /* what about the case where exactly one runas is specified in
+ * the config and the user forgets the -u option, should we
+ * switch it? - Probably not
+ */
+
+ /* walk through values returned, looking for a match*/
+ for (p=v; p && *p && !ret;p++)
+ {
+ if (ldap_conf.debug>1) printf("ldap sudoRunAs '%s' ...",*p);
+
+ if (
+ !strcasecmp(*p,*user_runas) ||
+ !strcasecmp(*p,"ALL")
+ )
+ {
+ ret = 1;
+ }
+
+ if (ldap_conf.debug>1) printf(" %s\n",ret ? "MATCH!" : "not");
+ }
+
+ /* cleanup */
+ if (v) ldap_value_free(v);
+
+ /* all done */
+ return ret;
+}
+
+/*
+ * Walks through search result and returns true if we have a
+ * command match
+ */
+int sudo_ldap_check_command(ld,entry)
+ LDAP *ld;
+ LDAPMessage *entry;
+{
+ char **v=NULL;
+ char **p=NULL;
+ char *allowed_cmnd;
+ char *allowed_args;
+ int ret=0;
+
+ if (!entry) return ret;
+
+ v=ldap_get_values(ld,entry,"sudoCommand");
+
+ /* get_first_entry */
+ for (p=v; p && *p && !ret;p++){
+ if (ldap_conf.debug>1) printf("ldap sudoCommand '%s' ...",*p);
+
+ /* Match against ALL ? */
+ if (!strcasecmp(*p,"ALL")) {
+ ret=1;
+ if (safe_cmnd) free (safe_cmnd);
+ safe_cmnd=estrdup(user_cmnd);
+ }
+
+ /* split optional args away from command */
+ allowed_cmnd=estrdup(*p);
+ allowed_args=strchr(allowed_cmnd,' ');
+ if (allowed_args) *allowed_args++='\0';
+
+ /* check the command like normal */
+ if (command_matches(user_cmnd, user_args,allowed_cmnd,allowed_args)) ret=1;
+
+ /* cleanup */
+ free(allowed_cmnd);
+ if (ldap_conf.debug>1) printf(" %s\n",ret ? "MATCH!" : "not");
+ }
+
+ /* more cleanup */
+ if (v) ldap_value_free(v);
+
+ /* all done */
+ return ret;
+}
+
+/*
+ * Read sudoOption, modify the defaults as we go.
+ * This is used once from the cn=defaults entry
+ * and also once when a final sudoRole is matched.
+ *
+ */
+void
+sudo_ldap_parse_options(ld,entry)
+ LDAP *ld;
+ LDAPMessage *entry;
+{
+ /* used to parse attributes */
+ char **v=NULL;
+ char **p=NULL;
+ char *var;
+ char *val;
+ char op;
+
+ if (!entry) return;
+
+ v=ldap_get_values(ld,entry,"sudoOption");
+
+ /* walk through options */
+ for (p=v; p && *p;p++){
+
+ if (ldap_conf.debug>1) printf("ldap sudoOption: '%s'\n",*p);
+ var=estrdup(*p);
+ /* check for = char */
+ val=strchr(var,'=');
+
+ /* check for equals sign past first char */
+ if (val>var){
+ *val++='\0'; /* split on = and truncate var */
+ op=*(val-2); /* peek for += or -= cases */
+ if (op == '+' || op == '-') {
+ *(val-2)='\0'; /* found, remove extra char */
+ /* case var+=val or var-=val */
+ set_default(var,val,(int)op);
+ } else {
+ /* case var=val */
+ set_default(var,val,TRUE);
+ }
+ } else if (*var=='!'){
+ /* case !var Boolean False */
+ set_default(var+1,NULL,FALSE);
+ } else {
+ /* case var Boolean True */
+ set_default(var,NULL,TRUE);
+ }
+ free(var);
+
+ }
+
+ if (v) ldap_value_free(v);
+
+}
+
+/*
+ * Concatenate strings, dynamically growing them as necessary.
+ * Strings can be arbitrarily long and are allocated/reallocated on
+ * the fly. Make sure to free them when you are done.
+ *
+ * Usage:
+ *
+ * char *s=NULL;
+ * size_t sz;
+ *
+ * ncat(&s,&sz,"This ");
+ * ncat(&s,&sz,"is ");
+ * ncat(&s,&sz,"an ");
+ * ncat(&s,&sz,"arbitrarily ");
+ * ncat(&s,&sz,"long ");
+ * ncat(&s,&sz,"string!");
+ *
+ * printf("String Value='%s', but has %d bytes allocated\n",s,sz);
+ *
+ */
+void
+ncat(s,sz,src)
+ char **s;
+ size_t *sz;
+ char *src;
+{
+ size_t nsz;
+
+ /* handle initial alloc */
+ if (*s == NULL){
+ *s=estrdup(src);
+ *sz=strlen(src)+1;
+ return;
+ }
+
+ /* handle realloc */
+ nsz= strlen(*s) + strlen(src) + 1;
+ if (*sz < nsz) *s=erealloc( (void *)*s , *sz=nsz*2);
+ strlcat(*s,src,*sz);
+}
+
+
+/*
+ * builds together a filter to check against ldap
+ */
+char *
+sudo_ldap_build_pass1()
+{
+ struct group *grp;
+ gid_t *grplist=NULL;
+ int ngrps;
+ int i;
+
+ char *b=NULL;
+ size_t sz;
+
+ /* global OR */
+ ncat(&b,&sz,"(|");
+
+ /* build filter sudoUser=user_name */
+ ncat(&b,&sz,"(sudoUser=");
+ ncat(&b,&sz,user_name);
+ ncat(&b,&sz,")");
+
+ /* Append primary group */
+ grp=getgrgid(getgid());
+ if (grp!=NULL){
+ ncat(&b,&sz,"(sudoUser=%");
+ ncat(&b,&sz,grp->gr_name);
+ ncat(&b,&sz,")");
+ }
+
+ /* handle arbitrary number of groups */
+ if (0<(ngrps=getgroups(0,NULL))){
+ grplist=calloc(ngrps,sizeof(gid_t));
+ if (grplist!=NULL && (0<getgroups(ngrps,grplist)))
+ for(i=0;i<ngrps;i++){
+ if((grp=getgrgid(grplist[i]))!=NULL){
+ ncat(&b,&sz,"(sudoUser=%");
+ ncat(&b,&sz,grp->gr_name);
+ ncat(&b,&sz,")");
+ }
+ }
+ }
+
+
+ /* Add ALL to list */
+ ncat(&b,&sz,"(sudoUser=ALL)");
+
+ /* End of OR List */
+ ncat(&b,&sz,")");
+ return b ;
+}
+
+
+int
+sudo_ldap_read_config()
+{
+ FILE *f;
+ char buf[BUF_SIZ];
+ char *c;
+ char *keyword;
+ char *value;
+
+ f=fopen(LDAP_CONFIG,"r");
+ if (!f) return 0;
+ while (f && fgets(buf,sizeof(buf)-1,f)){
+ c=buf;
+ if (*c == '#') continue; /* ignore comment */
+ if (*c == '\n') continue; /* skip newline */
+ if (!*c) continue; /* incomplete last line */
+
+ /* skip whitespace before keyword */
+ while (isspace(*c)) c++;
+ keyword=c;
+
+ /* properly terminate keyword string */
+ while (*c && !isspace(*c)) c++;
+ if (*c) {
+ *c='\0'; /* terminate keyword */
+ c++;
+ }
+
+ /* skip whitespace before value */
+ while (isspace(*c)) c++;
+ value=c;
+
+ /* trim whitespace after value */
+ while (*c) c++; /* wind to end */
+ while (--c > value && isspace(*c)) *c='\0';
+
+ /* The following macros make the code much more readable */
+
+#define MATCH_S(x,y) if (!strcasecmp(keyword,x)) \
+ { if (y) free(y); y=estrdup(value); }
+#define MATCH_I(x,y) if (!strcasecmp(keyword,x)) { y=atoi(value); }
+
+
+
+ /* parse values using a continues chain of
+ * if else if else if else if else ... */
+ MATCH_S("host", ldap_conf.host)
+ else MATCH_I("port", ldap_conf.port)
+ else MATCH_I("ldap_version", ldap_conf.version)
+ else MATCH_S("uri", ldap_conf.uri)
+ else MATCH_S("binddn", ldap_conf.binddn)
+ else MATCH_S("bindpw", ldap_conf.bindpw)
+ else MATCH_S("sudoers_base", ldap_conf.base)
+ else MATCH_I("sudoers_debug", ldap_conf.debug)
+ else {
+
+ /* The keyword was unrecognized. Since this config file is shared
+ * by multiple programs, it is appropriate to silently ignore options this
+ * program does not understand
+ */
+ }
+
+ } /* parse next line */
+
+ if (f) fclose(f);
+
+ /* defaults */
+ if (!ldap_conf.version) ldap_conf.version=3;
+ if (!ldap_conf.port) ldap_conf.port=389;
+ if (!ldap_conf.host) ldap_conf.host=estrdup("localhost");
+
+
+ if (ldap_conf.debug>1) {
+ printf("LDAP Config Summary\n");
+ printf("===================\n");
+ printf("host %s\n", ldap_conf.host ?
+ ldap_conf.host : "(NONE)");
+ printf("port %d\n", ldap_conf.port);
+ printf("ldap_version %d\n", ldap_conf.version);
+
+ printf("uri %s\n", ldap_conf.uri ?
+ ldap_conf.uri : "(NONE)");
+ printf("sudoers_base %s\n", ldap_conf.base ?
+ ldap_conf.base : "(NONE) <---Sudo will ignore ldap)");
+ printf("binddn %s\n", ldap_conf.binddn ?
+ ldap_conf.binddn : "(anonymous)");
+ printf("bindpw %s\n", ldap_conf.bindpw ?
+ ldap_conf.bindpw : "(anonymous)");
+ printf("===================\n");
+ }
+
+ /* if no base is defined, ignore LDAP */
+ if (!ldap_conf.base) return 0;
+ /* All is good */
+ return 1;
+}
+
+/*
+ like perl's join(sep,@ARGS)
+*/
+char *
+_ldap_join_values(sep,v)
+ char *sep;
+ char **v;
+{
+ char **p=NULL;
+ char *b=NULL;
+ size_t sz=0;
+
+ /* paste values together */
+ for (p=v; p && *p;p++){
+ if (p!=v && sep!=NULL) ncat(&b,&sz,sep); /* append seperator */
+ ncat(&b,&sz,*p); /* append value */
+ }
+
+ /* sanity check */
+ if (b[0]=='\0'){
+ /* something went wrong, put something here */
+ ncat(&b,&sz,"(empty list)"); /* append value */
+ }
+
+ /* all done */
+ return b;
+}
+
+char * sudo_ldap_cm_list=NULL;
+size_t sudo_ldap_cm_list_size;
+
+#define SAVE_LIST(x) ncat(&sudo_ldap_cm_list,&sudo_ldap_cm_list_size,(x))
+/*
+ * Walks through search result and returns true if we have a
+ * command match
+ */
+int
+sudo_ldap_add_match(ld,entry)
+ LDAP *ld;
+ LDAPMessage *entry;
+{
+ char **v=NULL;
+ char *dn;
+ char **edn;
+
+ /* if we are not collecting matches, then don't print them */
+ if (printmatches != TRUE) return 1;
+
+ /* collect the dn, only show the rdn */
+ dn=ldap_get_dn(ld,entry);
+ if (dn) edn=ldap_explode_dn(dn,1);
+ SAVE_LIST("\nLDAP Role: ");
+ SAVE_LIST((edn && *edn) ? *edn : "UNKNOWN");
+ SAVE_LIST("\n");
+ if (dn) ldap_memfree(dn);
+ if (edn) ldap_value_free(edn);
+
+ /* get the Runas Values from the entry */
+ v=ldap_get_values(ld,entry,"sudoRunAs");
+ if (v && *v){
+ SAVE_LIST(" RunAs: (");
+ SAVE_LIST(_ldap_join_values(", ",v));
+ SAVE_LIST(")\n");
+ }
+ if (v) ldap_value_free(v);
+
+ /* get the Command Values from the entry */
+ v=ldap_get_values(ld,entry,"sudoCommand");
+ if (v && *v){
+ SAVE_LIST(" Commands:\n ");
+ SAVE_LIST(_ldap_join_values("\n ",v));
+ SAVE_LIST("\n");
+ } else {
+ SAVE_LIST(" Commands: NONE\n");
+ }
+ if (v) ldap_value_free(v);
+
+ return 0; /* Don't stop at the first match */
+}
+#undef SAVE_LIST
+
+void
+sudo_ldap_list_matches()
+{
+ if (sudo_ldap_cm_list!=NULL) printf("%s",sudo_ldap_cm_list);
+}
+
+/*
+ * like sudoers_lookup() - only LDAP style
+ *
+ */
+
+int
+sudo_ldap_check(pwflag)
+int pwflag;
+{
+
+ LDAP *ld=NULL;
+
+ /* Used for searches */
+ LDAPMessage *result=NULL;
+ LDAPMessage *entry=NULL;
+ /* used to parse attributes */
+ char *filt;
+ /* temp/final return values */
+ int rc=0;
+ int ret=0;
+ int pass=0;
+ /* flags */
+ int ldap_user_matches=0;
+ int ldap_host_matches=0;
+
+ if (!sudo_ldap_read_config()) return VALIDATE_ERROR;
+
+
+ /* attempt connect */
+#ifdef HAVE_LDAP_INITIALIZE
+ if (ldap_conf.uri) {
+
+ if (ldap_conf.debug>1) fprintf(stderr,
+ "ldap_initialize(ld,%s)\n",ldap_conf.uri);
+
+ rc=ldap_initialize(&ld,ldap_conf.uri);
+ if(rc){
+ fprintf(stderr, "ldap_initialize()=%d : %s\n",
+ rc,ldap_err2string(rc));
+ return VALIDATE_ERROR;
+ }
+ } else
+#endif /* HAVE_LDAP_INITIALIZE */
+ if (ldap_conf.host) {
+
+ if (ldap_conf.debug>1) fprintf(stderr,
+ "ldap_init(%s,%d)\n",ldap_conf.host,ldap_conf.port);
+
+ ld=ldap_init(ldap_conf.host,ldap_conf.port);
+ if (!ld) {
+ fprintf(stderr, "ldap_init(): errno=%d : %s\n",
+ errno, strerror(errno));
+ return VALIDATE_ERROR;
+ }
+ }
+
+#ifdef LDAP_OPT_PROTOCOL_VERSION
+
+ /* Set the LDAP Protocol version */
+
+ rc=ldap_set_option(ld,LDAP_OPT_PROTOCOL_VERSION,&ldap_conf.version);
+ if(rc){
+ fprintf(stderr,"ldap_set_option(protocol=%d)=%d : %s\n",
+ ldap_conf.version, rc, ldap_err2string(rc));
+ return VALIDATE_ERROR ;
+ }
+
+#endif /* LDAP_OPT_PROTOCOL_VERSION */
+
+ /* Actually connect */
+
+ rc=ldap_simple_bind_s(ld,ldap_conf.binddn,ldap_conf.bindpw);
+ if(rc){
+ fprintf(stderr,"ldap_simple_bind_s()=%d : %s\n",
+ rc, ldap_err2string(rc));
+ return VALIDATE_ERROR ;
+ }
+
+ if (ldap_conf.debug) printf("ldap_bind() ok\n");
+
+
+ /* Parse Default Options */
+
+ rc=ldap_search_s(ld,ldap_conf.base,LDAP_SCOPE_ONELEVEL,
+ "cn=defaults",NULL,0,&result);
+ if (!rc && (entry=ldap_first_entry(ld,result))){
+ if (ldap_conf.debug) printf("found:%s\n",ldap_get_dn(ld,entry));
+ sudo_ldap_parse_options(ld,entry);
+ } else {
+ if (ldap_conf.debug) printf("no default options found!\n");
+ }
+
+ if (result) ldap_msgfree(result);
+ result=NULL;
+
+ /*
+ * Okay - time to search for anything that matches this user
+ * Lets limit it to only two queries of the LDAP server
+ *
+ * The first pass will look by the username, groups, and
+ * the keyword ALL. We will then inspect the results that
+ * came back from the query. We don't need to inspect the
+ * sudoUser in this pass since the LDAP server already scanned
+ * it for us.
+ *
+ * The second pass will return all the entries that contain
+ * user netgroups. Then we take the netgroups returned and
+ * try to match them against the username.
+ *
+ */
+
+ for(pass=1;!ret && pass<=2;pass++){
+
+ if (pass==1) {
+ /* Want the entries that match our usernames or groups */
+ filt=sudo_ldap_build_pass1();
+ } else { /* pass=2 */
+ /* Want the entries that have user netgroups in them. */
+ filt=strdup("sudoUser=+*");
+ }
+ if (ldap_conf.debug) printf("ldap search '%s'\n",filt);
+ rc=ldap_search_s(ld,ldap_conf.base,LDAP_SCOPE_ONELEVEL,
+ filt,NULL,0,&result);
+ if (rc) {
+ if (ldap_conf.debug) printf("nothing found for '%s'\n",filt);
+ }
+ if (filt) free (filt);
+ /* parse each entry returned from this most recent search */
+ for(
+ entry=rc ? NULL : ldap_first_entry(ld,result);
+ entry!=NULL;
+ entry=ldap_next_entry(ld,entry))
+ {
+ if (ldap_conf.debug) printf("found:%s\n",ldap_get_dn(ld,entry));
+ if (
+ /* first verify user netgroup matches - only if in pass 2 */
+ (pass!=2 || sudo_ldap_check_user_netgroup(ld,entry)) &&
+ /* remember that user matched */
+ (ldap_user_matches=-1) &&
+ /* verify host match */
+ sudo_ldap_check_host(ld,entry) &&
+ /* remember that host matched */
+ (ldap_host_matches=-1) &&
+ /* add matches for listing later */
+ sudo_ldap_add_match(ld,entry) &&
+ /* verify command match */
+ sudo_ldap_check_command(ld,entry) &&
+ /* verify runas match */
+ sudo_ldap_check_runas(ld,entry)
+ )
+ {
+ /* We have a match! */
+ if(ldap_conf.debug) printf("Perfect Matched!\n");
+ /* pick up any options */
+ sudo_ldap_parse_options(ld,entry);
+ /* make sure we dont reenter loop */
+ ret=VALIDATE_OK;
+ /* break from inside for loop */
+ break;
+ }
+
+ }
+ if (result) ldap_msgfree(result);
+ result=NULL;
+
+ }
+
+ /* shut down connection */
+ if (ld) ldap_unbind_s(ld);
+
+
+ if (ldap_conf.debug) printf("user_matches=%d\n",ldap_user_matches);
+ if (ldap_conf.debug) printf("host_matches=%d\n",ldap_host_matches);
+
+ /* Check for special case for -v, -k, -l options */
+ if (pwflag && ldap_user_matches && ldap_host_matches){
+ /*
+ * Handle verifypw & listpw
+ *
+ * To be extra paranoid, since we haven't read any NOPASSWD options
+ * in /etc/sudoers yet, but we have to make the decission now, lets
+ * assume the worst and prefer to prompt for password unless the setting
+ * is "never". (example verifypw=never or listpw=never)
+ *
+ */
+ if (pwflag<0) { /* -k */
+ ret=VALIDATE_OK; SET(ret,FLAG_NOPASS);
+ } else if (sudo_defs_table[pwflag].sd_un.tuple == never){ /* see note above */
+ ret=VALIDATE_OK; SET(ret,FLAG_NOPASS);
+ } else {
+ ret=VALIDATE_OK; /* extra paranoid */
+ }
+ }
+
+ if (ISSET(ret,VALIDATE_OK)) {
+ /* We have a match. Should we check the password? */
+ /* Note: This could be the global or a rule specific option */
+ if (!def_authenticate) SET(ret,FLAG_NOPASS);
+ /* Same logic with noexec */
+ if (def_noexec) SET(ret,FLAG_NOEXEC);
+ } else {
+ /* we do not have a match */
+ ret=VALIDATE_NOT_OK;
+ if (!ldap_user_matches) SET(ret,FLAG_NO_USER);
+ else if (!ldap_host_matches) SET(ret,FLAG_NO_HOST);
+ }
+
+ if (ldap_conf.debug) printf("sudo_ldap_check(%d)=0x%02x\n",pwflag,ret);
+
+ return ret ;
+}