[BACK]Return to ldap.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Annotation of src/usr.bin/sudo/ldap.c, Revision 1.5

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