/* * * ldap.c * * Complex LDAP searches, and string routines * * Author: Landon Fuller * * Copyright (c) 2000-2001 InfoSpace, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by InfoSpace, Inc. * and its contributors. * 4. Neither the name of InfoSpace, Inc nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "../../../autoconf.h" #include #include #ifdef HAVE_STRINGS_H #include #else #include #endif #include #include #include #include #include #include "yp.h" #include "../../../include/config.h" #include "ldap.h" #include "cache.h" #define CONFIG_FILE CONFDIR "/ldap.conf" /* #define MAPS "auto.home auto_home amd.home passwd.byname passwd.byuid group.byname group.bygid" */ #define MAPS "auto.home auto_home amd.home master.passwd.byname master.passwd.byuid passwd.byname passwd.byuid group.byname group.bygid" struct ldaprefs ldaprefs; typedef enum { CACHE, HOST, PORT, BASEDN, BINDDN, PASS, BADOPTION } ConfigOptions; static struct { const char *name; ConfigOptions opcode; } keywords [] = { { "cache", CACHE }, { "host", HOST }, { "port", PORT }, { "basedn", BASEDN }, { "binddn", BINDDN }, { "password", PASS }, { NULL, 0 } }; static void init_config (void) { ldaprefs.cache = 0; ldaprefs.host = NULL; ldaprefs.port = 0; ldaprefs.basedn = NULL; ldaprefs.binddn = NULL; ldaprefs.pass = NULL; ldaprefs.dflag = 0; ldaprefs.perr = 1; } static int fill_config (void) { if (ldaprefs.host == NULL) { log("Missing required %s directive in config file\n", keywords[HOST].name); return (1); } if (ldaprefs.port == 0) ldaprefs.port = LDAP_PORT; if (ldaprefs.basedn == NULL) { log("Missing required %s directive in config file\n", keywords[BASEDN].name); return (1); } if (ldaprefs.binddn == NULL) { log("Missing required %s directive in config file\n", keywords[BINDDN].name); return (1); } if (ldaprefs.pass == NULL) { log("Missing required %s directive in config file\n", keywords[PASS].name); return (1); } return (0); } static ConfigOptions parse_opcode (const char *cp, const char *filename, int linenum) { unsigned int i; for (i = 0; keywords[i].name; i++) if (strcasecmp(cp, keywords[i].name) == 0) return(keywords[i].opcode); log("%s: line %d: Bad configuration option: %s\n", filename, linenum, cp); return(BADOPTION); } static int read_server_config (char *filename) { FILE *config; char line[1024]; char *cp; int linenum = 0; int bad_options = 0; ConfigOptions opcode; config = fopen(filename, "r"); if (!config) { log("Failed to open config file %s for reading\n", CONFIG_FILE); return(1); } while (fgets(line, sizeof(line), config) != NULL) { linenum++; cp = line + strspn(line, WHITESPACE); if (!*cp || *cp == '#') continue; cp = strtok(cp, WHITESPACE); opcode = parse_opcode(cp, filename, linenum); switch (opcode) { char *endptr; case BADOPTION: bad_options++; continue; case CACHE: cp = strtok(NULL, WHITESPACE); if (!cp) log("%s line %d: missing cache size\n", filename, linenum); ldaprefs.cache = strtol(cp, &endptr, 10); if (*endptr != '\0') log("Invalid cache size: %s\n", cp); break; case HOST: cp = strtok(NULL, WHITESPACE); if (!cp) log("%s line %d: missing LDAP host\n", filename, linenum); ldaprefs.host = safe_strdup(cp); break; case PORT: cp = strtok(NULL, WHITESPACE); if (!cp) log("%s line %d: missing LDAP port\n", filename, linenum); ldaprefs.port = strtol(cp, &endptr, 10); if (*endptr != '\0' || ldaprefs.port > 65535) log("Invalid port: %s\n", cp); break; case BASEDN: cp = strtok(NULL, WHITESPACE); if (!cp) log("%s line %d: missing base DN\n", filename, linenum); ldaprefs.basedn = safe_strdup(cp); break; case BINDDN: cp = strtok(NULL, WHITESPACE); if (!cp) log("%s line %d: missing bind DN\n", filename, linenum); ldaprefs.binddn = safe_strdup(cp); break; case PASS: cp = strtok(NULL, WHITESPACE); if (!cp) log("%s line %d: missing password\n", filename, linenum); ldaprefs.pass = safe_strdup(cp); break; default: log("%s line %d: Missing handler for config opcode %s (%d)\n", filename, linenum, cp, opcode); } if (strtok(NULL, WHITESPACE) != NULL) log("%s line %d: garbage at end of line.\n", filename, linenum); } fclose(config); if (bad_options > 0) { log("%s: terminating, %d bad configuration options\n", filename, bad_options); return (1); } return (0); } static bool_t yp_ldapconnect(void) { if(ldaprefs.ldap != NULL) ldap_unbind(ldaprefs.ldap); if ((ldaprefs.ldap = ldap_init(ldaprefs.host, (int) ldaprefs.port)) == NULL) { log("ldap init failure for server %s, port %d: %s\n", ldaprefs.host, ldaprefs.port, strerror(errno)); return (1); } if ((ldap_bind_s(ldaprefs.ldap, ldaprefs.binddn, ldaprefs.pass, LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) { #if defined(LDAP_API_VERSION) && LDAP_API_VERSION > 1823 int error; if(ldap_get_option (ldaprefs.ldap, LDAP_OPT_ERROR_NUMBER, &error) != 0) { log("ldap bind failure for server %s, port %d\n", ldaprefs.host, ldaprefs.port); } else { log("ldap bind failure for server %s, port %d: %s\n", ldaprefs.host, ldaprefs.port, ldap_err2string(error)); } #else log("ldap bind failure for server %s, port %d: %s\n", ldaprefs.host, ldaprefs.port, ldap_err2string(ldaprefs.ldap->ld_errno)); #endif return (1); } if (ldaprefs.cache != 0) { if ((ldap_enable_cache(ldaprefs.ldap, 300, ldaprefs.cache * 1024)) == -1) log("ldap caching memory allocation failed. Caching will not be enabled\n"); } return (0); } /* getbykey will pull data directly from LDAP. This will be used to update internal * maps cached for the other YP calls */ ypstat yp_getbykey(keydat *key, mapname *map, valdat *val) { ypstat rval; rval = yp_get_record(key, map, val); return (rval); } ypstat yp_firstbykey(keydat *key, mapname *map, valdat *val) { ypstat rval; rval = yp_first_record(key, map, val); return (rval); } ypstat yp_nextbykey(keydat *key, mapname *map, valdat *val) { ypstat rval; rval = yp_next_record(key, map, val); return (rval); } int yp_clear (void) { ldap_flush_cache(ldaprefs.ldap); return (0); } bool_t init(struct ypmodulelist *yp_modulelist) { char *maps; pthread_t cache_thread; bool_t result = 0; ldaprefs.yp_moduledata = yp_modulelist->yp_moduledata; log ("LDAP module: initializing\n"); /* XXX Supported maps? */ maps = safe_strdup(MAPS); yp_modulelist->maps = yp_maplist_create(maps); free(maps); init_config(); if(read_server_config(CONFIG_FILE)) return (1); if(fill_config()) return (1); if(yp_ldapconnect()) return (1); log ("LDAP module: building cache\n"); ldaprefs.mapcache = create_cache(yp_modulelist->maps); log ("LDAP module: cache built.\n"); pthread_create ( &cache_thread, NULL, (void *) &maintain_cache, NULL); return (result); }