Annotation of embedaddon/sudo/plugins/sudoers/ldap.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>