/*
*
* ldap.c
*
* Complex LDAP searches, and string routines
*
* Author: Landon Fuller <landonf@go2net.com>
*
* 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 <stdlib.h>
#include <stdio.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#else
#include <string.h>
#endif
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <lber.h>
#include <ldap.h>
#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);
}
syntax highlighted by Code2HTML, v. 0.9.1