diff options
| author | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
|---|---|---|
| committer | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
| commit | b2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch) | |
| tree | cf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/plugins/passthru | |
| download | ds-ldapserver7x.tar.gz ds-ldapserver7x.tar.xz ds-ldapserver7x.zip | |
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/plugins/passthru')
| -rw-r--r-- | ldap/servers/plugins/passthru/Makefile | 90 | ||||
| -rw-r--r-- | ldap/servers/plugins/passthru/PT-Notes | 30 | ||||
| -rw-r--r-- | ldap/servers/plugins/passthru/libpassthru.def | 14 | ||||
| -rw-r--r-- | ldap/servers/plugins/passthru/passthru.h | 131 | ||||
| -rw-r--r-- | ldap/servers/plugins/passthru/ptbind.c | 144 | ||||
| -rw-r--r-- | ldap/servers/plugins/passthru/ptconfig.c | 301 | ||||
| -rw-r--r-- | ldap/servers/plugins/passthru/ptconn.c | 420 | ||||
| -rw-r--r-- | ldap/servers/plugins/passthru/ptdebug.c | 23 | ||||
| -rw-r--r-- | ldap/servers/plugins/passthru/ptdllmain.c | 131 | ||||
| -rw-r--r-- | ldap/servers/plugins/passthru/ptpreop.c | 252 | ||||
| -rw-r--r-- | ldap/servers/plugins/passthru/ptutil.c | 111 |
11 files changed, 1647 insertions, 0 deletions
diff --git a/ldap/servers/plugins/passthru/Makefile b/ldap/servers/plugins/passthru/Makefile new file mode 100644 index 00000000..11540915 --- /dev/null +++ b/ldap/servers/plugins/passthru/Makefile @@ -0,0 +1,90 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# +# GNU Makefile for Directory Server "Pass Through Authentication" plugin +# +# + +LDAP_SRC = ../../.. +MCOM_ROOT = ../../../../.. + +NOSTDCLEAN=true # don't let nsconfig.mk define target clean +NOSTDSTRIP=true # don't let nsconfig.mk define target strip +NSPR20=true # probably should be defined somewhere else (not sure where) + +OBJDEST = $(OBJDIR)/lib/libpassthru +LIBDIR = $(LIB_RELDIR) + +include $(MCOM_ROOT)/ldapserver/nsconfig.mk +include $(LDAP_SRC)/nsldap.mk + +ifeq ($(ARCH), WINNT) +DEF_FILE:=./libpassthru.def +endif + +CFLAGS+=$(SLCFLAGS) + +INCLUDES += -I$(LDAP_SRC)/servers/slapd + +PASSTHRU_OBJS= ptbind.o ptconfig.o ptconn.o ptdebug.o ptpreop.o ptutil.o + +OBJS = $(addprefix $(OBJDEST)/, $(PASSTHRU_OBJS)) + +ifeq ($(ARCH), WINNT) +LIBPASSTHRU_DLL_OBJ = $(addprefix $(OBJDEST)/, ptdllmain.o) +endif + +LIBPASSTHRU= $(addprefix $(LIBDIR)/, $(PASSTHRU_DLL).$(DLL_SUFFIX)) + +ifeq ($(ARCH), WINNT) +EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) +EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(NSPR_DEP) +EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL) $(NSPRLINK) +endif + + +ifeq ($(ARCH), WINNT) +DLL_LDFLAGS += -def:"./libpassthru.def" +endif # WINNT + +ifeq ($(ARCH), AIX) +EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) +EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(NSPR_DEP) +EXTRA_LIBS += $(LIBSLAPDLINK) $(LDAP_SDK_LIBLDAP_DLL) $(NSPRLINK) +EXTRA_LIBS += $(DLL_EXTRA_LIBS) +LD=ld +endif + +ifeq ($(ARCH), HPUX) +EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP) +EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK) +endif + +clientSDK: + +all: $(OBJDEST) $(LIBDIR) $(LIBPASSTHRU) + +$(LIBPASSTHRU): $(OBJS) $(LIBPASSTHRU_DLL_OBJ) $(DEF_FILE) + $(LINK_DLL) $(LIBPASSTHRU_DLL_OBJ) $(PLATFORMLIBS) $(EXTRA_LIBS) + +veryclean: clean + +clean: + $(RM) $(OBJS) +ifeq ($(ARCH), WINNT) + $(RM) $(LIBPASSTHRU_DLL_OBJ) +endif + $(RM) $(LIBPASSTHRU) + +$(OBJDEST): + $(MKDIR) $(OBJDEST) + +# +# header file dependencies (incomplete) +# +$(OBJS): passthru.h diff --git a/ldap/servers/plugins/passthru/PT-Notes b/ldap/servers/plugins/passthru/PT-Notes new file mode 100644 index 00000000..2e3cea10 --- /dev/null +++ b/ldap/servers/plugins/passthru/PT-Notes @@ -0,0 +1,30 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + Pass Through Authentication Plugin Notes + +Key + r required feature + n nice-to-have + ? undecided whether this is a good idea or not + +Missing features: +n U/I for configuration. + +Loose ends: +n Resolve any remaining code that is marked with XXX. +n Put some thought into cases we do not handle (SASL, no DN, no passwd) and + make sure we do the right thing in terms of errors, letting server's + standard mechanism handle the bind, etc. +? Protect against server connecting back to itself recursively. + +Testing: +r Basic tests (all platforms: NT,Sol,IRIX,AIX,HP/UX,OSF/1). +r Controls (both coming (e.g., ?) and going (e.g., password policy). +r SSL connections to remote servers. +r LDAPv2/v3 compatiblity +r Stress tests. diff --git a/ldap/servers/plugins/passthru/libpassthru.def b/ldap/servers/plugins/passthru/libpassthru.def new file mode 100644 index 00000000..b08d907a --- /dev/null +++ b/ldap/servers/plugins/passthru/libpassthru.def @@ -0,0 +1,14 @@ +; BEGIN COPYRIGHT BLOCK +; Copyright 2001 Sun Microsystems, Inc. +; Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +; All rights reserved. +; END COPYRIGHT BLOCK +; +; +; +DESCRIPTION 'Netscape Directory Server 7 Pass Through Authentication Plugin' +;CODE SHARED READ EXECUTE +;DATA SHARED READ WRITE +EXPORTS + passthruauth_init @1 + plugin_init_debug_level @2 diff --git a/ldap/servers/plugins/passthru/passthru.h b/ldap/servers/plugins/passthru/passthru.h new file mode 100644 index 00000000..fdf30d65 --- /dev/null +++ b/ldap/servers/plugins/passthru/passthru.h @@ -0,0 +1,131 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * passthru.h - Pass Through Authentication shared definitions + * + */ + +#ifndef _PASSTHRU_H_ +#define _PASSTHRU_H_ + +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include "portable.h" +#include "slapi-plugin.h" +#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */ +#include "dirver.h" +#include <nspr.h> + +/* Private API: to get slapd_pr_strerror() and SLAPI_COMPONENT_NAME_NSPR */ +#include "slapi-private.h" + +/* + * macros + */ +#define PASSTHRU_PLUGIN_SUBSYSTEM "passthru-plugin" /* for logging */ + +#define PASSTHRU_ASSERT( expr ) PR_ASSERT( expr ) + +#define PASSTHRU_LDAP_CONN_ERROR( err ) ( (err) == LDAP_SERVER_DOWN || \ + (err) == LDAP_CONNECT_ERROR ) + +#define PASSTHRU_OP_NOT_HANDLED 0 +#define PASSTHRU_OP_HANDLED 1 + +#define PASSTHRU_CONN_TRIES 2 + +/* #define PASSTHRU_VERBOSE_LOGGING */ + +/* defaults */ +#define PASSTHRU_DEF_SRVR_MAXCONNECTIONS 3 +#define PASSTHRU_DEF_SRVR_MAXCONCURRENCY 5 +#define PASSTHRU_DEF_SRVR_TIMEOUT 300 /* seconds */ +#define PASSTHRU_DEF_SRVR_PROTOCOL_VERSION LDAP_VERSION3 +#define PASSTHRU_DEF_SRVR_CONNLIFETIME 0 /* seconds */ +#define PASSTHRU_DEF_SRVR_FAILOVERCONNLIFETIME 300 /* seconds */ + +/* + * structs + */ +typedef struct passthrusuffix { + int ptsuffix_len; + char *ptsuffix_normsuffix; /* not case normalized */ + struct passthrusuffix *ptsuffix_next; +} PassThruSuffix; + +typedef struct passthruconnection { + LDAP *ptconn_ld; + int ptconn_ldapversion; + int ptconn_usecount; +#define PASSTHRU_CONNSTATUS_OK 0 +#define PASSTHRU_CONNSTATUS_DOWN 1 +#define PASSTHRU_CONNSTATUS_STALE 2 + int ptconn_status; + time_t ptconn_opentime; + struct passthruconnection *ptconn_prev; + struct passthruconnection *ptconn_next; +} PassThruConnection; + +typedef struct passthruserver { + char *ptsrvr_url; /* copy from argv[i] */ + char *ptsrvr_hostname; + int ptsrvr_port; + int ptsrvr_secure; /* use SSL? */ + int ptsrvr_ldapversion; + int ptsrvr_maxconnections; + int ptsrvr_maxconcurrency; + int ptsrvr_connlifetime; /* in seconds */ + struct timeval *ptsrvr_timeout; /* for ldap_result() */ + PassThruSuffix *ptsrvr_suffixes; + Slapi_CondVar *ptsrvr_connlist_cv; + Slapi_Mutex *ptsrvr_connlist_mutex; /* protects connlist */ + int ptsrvr_connlist_count; + PassThruConnection *ptsrvr_connlist; + struct passthruserver *ptsrvr_next; +} PassThruServer; + +typedef struct passthruconfig { + PassThruServer *ptconfig_serverlist; +} PassThruConfig; + + +/* + * public functions + */ +/* + * ptbind.c: + */ +int passthru_simple_bind_s( Slapi_PBlock *pb, PassThruServer *srvr, int tries, + char *dn, struct berval *creds, LDAPControl **reqctrls, int *lderrnop, + char **matcheddnp, char **errmsgp, struct berval ***refurlsp, + LDAPControl ***resctrlsp ); + +/* + * ptconfig.c: + */ +int passthru_config( int argc, char **argv ); +PassThruConfig *passthru_get_config( void ); + +/* + * ptconn.c: + */ +int passthru_dn2server( PassThruConfig *cfg, char *normdn, + PassThruServer **srvrp ); +int passthru_get_connection( PassThruServer *srvr, LDAP **ldp ); +void passthru_release_connection( PassThruServer *srvr, LDAP *ld, int dispose ); +void passthru_close_all_connections( PassThruConfig *cfg ); + +/* + * ptutil.c: + */ +struct berval **passthru_strs2bervals( char **ss ); +char ** passthru_bervals2strs( struct berval **bvs ); +void passthru_free_bervals( struct berval **bvs ); +char *passthru_urlparse_err2string( int err ); + +#endif /* _PASSTHRU_H_ */ diff --git a/ldap/servers/plugins/passthru/ptbind.c b/ldap/servers/plugins/passthru/ptbind.c new file mode 100644 index 00000000..f9da57a1 --- /dev/null +++ b/ldap/servers/plugins/passthru/ptbind.c @@ -0,0 +1,144 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * ptbind.c - LDAP bind-related code for Pass Through Authentication + * + */ + +#include "passthru.h" + +static int +passthru_simple_bind_once_s( PassThruServer *srvr, char *dn, + struct berval *creds, LDAPControl **reqctrls, int *lderrnop, + char **matcheddnp, char **errmsgp, struct berval ***refurlsp, + LDAPControl ***resctrlsp ); + + +/* + * Attempt to chain a bind request off to "srvr." We return an LDAP error + * code that indicates whether we successfully got a response from the + * other server or not. If we succeed, we return LDAP_SUCCESS and *lderrnop + * is set to the result code from the remote server. + * + * Note that in the face of "ldap server down" or "ldap connect failed" errors + * we make up to "tries" attempts to bind to the remote server. Since we + * are only interested in recovering silently when the remote server is up + * but decided to close our connection, we retry without pausing between + * attempts. + */ +int +passthru_simple_bind_s( Slapi_PBlock *pb, PassThruServer *srvr, int tries, + char *dn, struct berval *creds, LDAPControl **reqctrls, int *lderrnop, + char **matcheddnp, char **errmsgp, struct berval ***refurlsp, + LDAPControl ***resctrlsp ) +{ + int rc; + + PASSTHRU_ASSERT( srvr != NULL ); + PASSTHRU_ASSERT( tries > 0 ); + PASSTHRU_ASSERT( creds != NULL ); + PASSTHRU_ASSERT( lderrnop != NULL ); + PASSTHRU_ASSERT( refurlsp != NULL ); + + do { + /* + * check to see if operation has been abandoned... + */ + if ( slapi_op_abandoned( pb )) { + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "operation abandoned\n" ); + rc = LDAP_USER_CANCELLED; + } else { + rc = passthru_simple_bind_once_s( srvr, dn, creds, reqctrls, + lderrnop, matcheddnp, errmsgp, refurlsp, resctrlsp ); + } + } while ( PASSTHRU_LDAP_CONN_ERROR( rc ) && --tries > 0 ); + + return( rc ); +} + + +/* + * like passthru_simple_bind_s() but only makes one attempt. + */ +static int +passthru_simple_bind_once_s( PassThruServer *srvr, char *dn, + struct berval *creds, LDAPControl **reqctrls, int *lderrnop, + char **matcheddnp, char **errmsgp, struct berval ***refurlsp, + LDAPControl ***resctrlsp ) +{ + int rc, msgid; + char **referrals; + struct timeval tv, *timeout; + LDAPMessage *result; + LDAP *ld; + + /* + * Grab an LDAP connection to use for this bind. + */ + ld = NULL; + if (( rc = passthru_get_connection( srvr, &ld )) != LDAP_SUCCESS ) { + goto release_and_return; + } + + /* + * Send the bind operation (need to retry on LDAP_SERVER_DOWN) + */ + if (( rc = ldap_sasl_bind( ld, dn, LDAP_SASL_SIMPLE, creds, reqctrls, + NULL, &msgid )) != LDAP_SUCCESS ) { + goto release_and_return; + } + + /* + * determine timeout value (how long we will wait for a response) + * if timeout is NULL or zero'd, we wait indefinitely. + */ + if ( srvr->ptsrvr_timeout == NULL || ( srvr->ptsrvr_timeout->tv_sec == 0 + && srvr->ptsrvr_timeout->tv_usec == 0 )) { + timeout = NULL; + } else { + tv = *srvr->ptsrvr_timeout; /* struct copy */ + timeout = &tv; + } + + /* + * Wait for a result. + */ + rc = ldap_result( ld, msgid, 1, timeout, &result ); + + /* + * Interpret the result. + */ + if ( rc == 0 ) { /* timeout */ + /* + * Timed out waiting for a reply from the server. + */ + rc = LDAP_TIMEOUT; + } else if ( rc < 0 ) { + /* + * Some other error occurred (no result received). + */ + rc = ldap_get_lderrno( ld, matcheddnp, errmsgp ); + } else { + /* + * Got a result from remote server -- parse it. + */ + rc = ldap_parse_result( ld, result, lderrnop, matcheddnp, errmsgp, + &referrals, resctrlsp, 1 ); + if ( referrals != NULL ) { + *refurlsp = passthru_strs2bervals( referrals ); + ldap_value_free( referrals ); + } + } + + +release_and_return: + if ( ld != NULL ) { + passthru_release_connection( srvr, ld, PASSTHRU_LDAP_CONN_ERROR( rc )); + } + + return( rc ); +} diff --git a/ldap/servers/plugins/passthru/ptconfig.c b/ldap/servers/plugins/passthru/ptconfig.c new file mode 100644 index 00000000..c3653f66 --- /dev/null +++ b/ldap/servers/plugins/passthru/ptconfig.c @@ -0,0 +1,301 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * ptconfig.c - configuration-related code for Pass Through Authentication + * + */ + +#include "passthru.h" + +/* + * Configuration is a bit complicated to fit into a single slapd config file + * line, but for now that's how it works. The format is: + * + * plugin preoperation on PTA NSHOME/passthru-plugin.so passthruauth_init ARGS + * + * where each ARGS provides configuration for one host. Each ARG should + * be of the form: + * + * "ldap://hosts/suffixes maxconns,maxconcurrency,timeout,ldver,connlifetime" + * OR + * "ldaps://hosts/suffixes maxconns,maxconcurrency,timeout,ldver,connlifetime" + * + * where: + * hosts is a space-separated list of remote servers (with optional port + * numbers) to be used. Each one is tried in order when opening an + * LDAP connection. + * suffixes is a semicolon separated list of DNs (if a DN contains a + * semicolon it must be represented \3B), + * maxconns is a limit on how many connections will be made, + * maxconcurrency is a limit on how many operations can share a connection, + * timeout is a time limit in seconds for bind operations to complete (use + * 0 to specify an infinite limit). + * ldver is the LDAP protocol version to use to talk to the server (2 or 3) + * connlifetime is a time limit time in seconds for a connection to be + * used before it is closed and reopened (use 0 to specify an infinite + * limit). connlifetime can be omitted in which case a default value + * is used; this is for compatibility with DS 4.0 which did not support + * connlifetime. + */ + + +/* + * function prototypes + */ +static char **get_backend_suffixes( void ); +static int is_underneath_backend_suffix( char *normdn, char **besuffixes ); + +/* + * static variables + */ +/* for now, there is only one configuration and it is global to the plugin */ +static PassThruConfig theConfig; +static int inited = 0; + + +/* + * Read configuration and create a configuration data structure. + * This is called after the server has configured itself so we can check + * for things like collisions between our suffixes and backend's suffixes. + * Returns an LDAP error code (LDAP_SUCCESS if all goes well). + * XXXmcs: this function leaks memory if any errors occur. + */ +int +passthru_config( int argc, char **argv ) +{ + int i, j, rc, tosecs, using_def_connlifetime; + char *p, **suffixarray; + PassThruServer *prevsrvr, *srvr; + PassThruSuffix *suffix, *prevsuffix; + LDAPURLDesc *ludp; + + if ( inited ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "only one pass through plugin instance can be used\n" ); + return( LDAP_PARAM_ERROR ); + } + + inited = 1; + + /* + * It doesn't make sense to configure a pass through plugin without + * providing at least one remote server. Return an error if attempted. + */ + if ( argc < 1 ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "no pass through servers found in configuration" + " (at least one must be listed)\n" ); + return( LDAP_PARAM_ERROR ); + } + + /* + * Parse argv[] values. + */ + prevsrvr = NULL; + for ( i = 0; i < argc; ++i ) { + srvr = (PassThruServer *)slapi_ch_calloc( 1, sizeof( PassThruServer )); + srvr->ptsrvr_url = slapi_ch_strdup( argv[i] ); + + if (( p = strchr( srvr->ptsrvr_url, ' ' )) == NULL ) { + /* + * use defaults for maxconnections, maxconcurrency, timeout, + * LDAP version, and connlifetime. + */ + srvr->ptsrvr_maxconnections = PASSTHRU_DEF_SRVR_MAXCONNECTIONS; + srvr->ptsrvr_maxconcurrency = PASSTHRU_DEF_SRVR_MAXCONCURRENCY; + srvr->ptsrvr_timeout = (struct timeval *)slapi_ch_calloc( 1, + sizeof( struct timeval )); + srvr->ptsrvr_timeout->tv_sec = PASSTHRU_DEF_SRVR_TIMEOUT; + srvr->ptsrvr_ldapversion = PASSTHRU_DEF_SRVR_PROTOCOL_VERSION; + using_def_connlifetime = 1; + } else { + /* + * parse parameters. format is: + * maxconnections,maxconcurrency,timeout,ldapversion + * OR maxconnections,maxconcurrency,timeout,ldapversion,lifetime + */ + *p++ = '\0'; + rc = sscanf( p, "%d,%d,%d,%d,%d", &srvr->ptsrvr_maxconnections, + &srvr->ptsrvr_maxconcurrency, &tosecs, + &srvr->ptsrvr_ldapversion, &srvr->ptsrvr_connlifetime ); + if ( rc < 4 ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "server parameters should be in the form " + "\"maxconnections,maxconcurrency,timeout,ldapversion," + "connlifetime\" (got \"%s\")\n", p ); + return( LDAP_PARAM_ERROR ); + } else if ( rc < 5 ) { + using_def_connlifetime = 1; + srvr->ptsrvr_connlifetime = PASSTHRU_DEF_SRVR_CONNLIFETIME; + } else { + using_def_connlifetime = 0; + } + + if ( srvr->ptsrvr_ldapversion != LDAP_VERSION2 + && srvr->ptsrvr_ldapversion != LDAP_VERSION3 ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "LDAP protocol version should be %d or %d (got %d)\n", + LDAP_VERSION2, LDAP_VERSION3, + srvr->ptsrvr_ldapversion ); + return( LDAP_PARAM_ERROR ); + } + + if ( srvr->ptsrvr_maxconnections <= 0 ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "maximum connections must be greater than " + "zero (got %d)\n", srvr->ptsrvr_maxconnections ); + return( LDAP_PARAM_ERROR ); + } + + if ( srvr->ptsrvr_maxconcurrency <= 0 ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "maximum concurrency must be greater than " + "zero (got %d)\n", srvr->ptsrvr_maxconcurrency ); + return( LDAP_PARAM_ERROR ); + } + + if ( tosecs <= 0 ) { + srvr->ptsrvr_timeout = NULL; + } else { + srvr->ptsrvr_timeout = (struct timeval *)slapi_ch_calloc( 1, + sizeof( struct timeval )); + srvr->ptsrvr_timeout->tv_sec = tosecs; + } + } + + /* + * parse the LDAP URL + */ + if (( rc = ldap_url_parse( srvr->ptsrvr_url, &ludp )) != 0 ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "unable to parse LDAP URL \"%s\" (%s)\n", + srvr->ptsrvr_url, passthru_urlparse_err2string( rc )); + return( LDAP_PARAM_ERROR ); + } + + if ( ludp->lud_dn == NULL || *ludp->lud_dn == '\0' ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "missing suffix in LDAP URL \"%s\"\n", + srvr->ptsrvr_url ); + return( LDAP_PARAM_ERROR ); + } + + srvr->ptsrvr_hostname = slapi_ch_strdup( ludp->lud_host ); + srvr->ptsrvr_port = ludp->lud_port; + srvr->ptsrvr_secure = + (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 ); + + /* + * If a space-separated list of hosts is configured for failover, + * use a different (non infinite) default for connection lifetime. + */ + if ( using_def_connlifetime && + strchr( srvr->ptsrvr_hostname, ' ' ) != NULL ) { + srvr->ptsrvr_connlifetime = + PASSTHRU_DEF_SRVR_FAILOVERCONNLIFETIME; + } + + /* + * split the DN into multiple suffixes (separated by ';') + */ + if (( suffixarray = ldap_str2charray( ludp->lud_dn, ";" )) == NULL ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "unable to parse suffix string \"%s\" within \"%s\"\n", + ludp->lud_dn, srvr->ptsrvr_url ); + return( LDAP_PARAM_ERROR ); + } + + /* + * free our LDAP URL descriptor + */ + ldap_free_urldesc( ludp ); + ludp = NULL; + + /* + * reorganize the suffixes into a linked list and normalize them + */ + prevsuffix = NULL; + for ( j = 0; suffixarray[ j ] != NULL; ++j ) { + + /* + * allocate a new PassThruSuffix structure and fill it in. + */ + suffix = (PassThruSuffix *)slapi_ch_malloc( + sizeof( PassThruSuffix )); + suffix->ptsuffix_normsuffix = + slapi_dn_normalize( suffixarray[ j ] ); + suffixarray[ j ] = NULL; + suffix->ptsuffix_len = strlen( suffix->ptsuffix_normsuffix ); + suffix->ptsuffix_next = NULL; + + /* + * add to end of list + */ + if ( prevsuffix == NULL ) { + srvr->ptsrvr_suffixes = suffix; + } else { + prevsuffix->ptsuffix_next = suffix; + } + prevsuffix = suffix; + } + ldap_memfree( suffixarray ); + + /* + * create mutexes and condition variables for this server + */ + if (( srvr->ptsrvr_connlist_mutex = slapi_new_mutex()) == NULL || + ( srvr->ptsrvr_connlist_cv = slapi_new_condvar( + srvr->ptsrvr_connlist_mutex )) == NULL ) { + return( LDAP_LOCAL_ERROR ); + } + + /* + * add this server to the end of our list + */ + if ( prevsrvr == NULL ) { + theConfig.ptconfig_serverlist = srvr; + } else { + prevsrvr->ptsrvr_next = srvr; + } + prevsrvr = srvr; + +#ifdef PASSTHRU_VERBOSE_LOGGING + /* + * log configuration for debugging purposes + */ + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "PTA server host: \"%s\", port: %d, secure: %d," + " maxconnections: %d, maxconcurrency: %d, timeout: %d," + " ldversion: %d, connlifetime: %d\n", + srvr->ptsrvr_hostname, srvr->ptsrvr_port, + srvr->ptsrvr_secure, srvr->ptsrvr_maxconnections, + srvr->ptsrvr_maxconcurrency, + srvr->ptsrvr_timeout == NULL ? -1 + : srvr->ptsrvr_timeout->tv_sec, srvr->ptsrvr_ldapversion, + srvr->ptsrvr_connlifetime ); + for ( prevsuffix = srvr->ptsrvr_suffixes; prevsuffix != NULL; + prevsuffix = prevsuffix->ptsuffix_next ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + " normalized suffix: \"%s\"\n", + prevsuffix->ptsuffix_normsuffix ); + } +#endif + + } + + return( LDAP_SUCCESS ); +} + + +/* + * Get the pass though configuration data. For now, there is only one + * configuration and it is global to the plugin. + */ +PassThruConfig * +passthru_get_config( void ) +{ + return( &theConfig ); +} diff --git a/ldap/servers/plugins/passthru/ptconn.c b/ldap/servers/plugins/passthru/ptconn.c new file mode 100644 index 00000000..56e2e0cc --- /dev/null +++ b/ldap/servers/plugins/passthru/ptconn.c @@ -0,0 +1,420 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * ptconn.c - LDAP connection-related code for Pass Through Authentication + * + */ + +#include "passthru.h" + +/* + * function prototypes + */ +static int dn_is_underneath_suffix( PassThruSuffix *suffix, char *normdn, + int dnlen ); +static void close_and_dispose_connection( PassThruConnection *conn ); +static void check_for_stale_connections( PassThruServer *srvr ); + + +/* + * Most of the complicated connection-related code lives in this file. Some + * general notes about how we manage our connections to "remote" LDAP servers: + * + * 1) Each server we have a relationship with is managed independently. + * + * 2) We may simultaneously issue multiple bind requests on a single LDAP + * connection. Each server has a "maxconcurrency" configuration + * parameter associated with it that caps the number of outstanding + * binds per connection. For each connection we maintain a "usecount" + * which is used to track the number of threads using the connection. + * + * 3) We may open more than one connection to a server. This is only done + * when "maxconcurrency" is exceeded for all the connections we already + * have open. Each server has a "maxconnections" configuration + * parameter associated with it that caps the number of connections. + * We also maintain a "connlist_count" for each server so we know when + * we have reached the maximum number of open connections allowed. + * + * 4) If no connection is available to service a request (and we have + * reached the limit of how many we are supposed to open), threads + * go to sleep on a condition variable and one is woken up each time + * a connection's "usecount" is decremented. + * + * 5) If we see an LDAP_CONNECT_ERROR or LDAP_SERVER_DOWN error on a + * session handle, we mark its status as PASSTHRU_CONNSTATUS_DOWN and + * close it as soon as all threads using it release it. Connections + * marked as "down" are not counted against the "maxconnections" limit. + * + * 6) We close and reopen connections that have been open for more than + * the server's configured connection lifetime. This is done to ensure + * that we reconnect to a primary server after failover occurs. If no + * lifetime is configured or it is set to 0, we never close and reopen + * connections. + */ + + +/* + * Given a normalized target dn, see if it we should "pass through" + * authentication to another LDAP server. The answer is "yes" if the + * target dn resides under one of the suffixes we have that is associated + * with an LDAP server we know about. + * + * This function assumes that normdn is normalized and the the suffixes in the + * cfg structure have also been normalized. + * + * Returns an LDAP error code, typically: + * LDAP_SUCCESS should pass though; *srvrp set. + * LDAP_NO_SUCH_OBJECT let this server handle the bind. + */ +int +passthru_dn2server( PassThruConfig *cfg, char *normdn, PassThruServer **srvrp ) +{ + PassThruServer *ptsrvr; + PassThruSuffix *ptsuffix; + int dnlen; + + PASSTHRU_ASSERT( cfg != NULL ); + PASSTHRU_ASSERT( normdn != NULL ); + PASSTHRU_ASSERT( srvrp != NULL ); + + dnlen = strlen( normdn ); + + for ( ptsrvr = cfg->ptconfig_serverlist; ptsrvr != NULL; + ptsrvr = ptsrvr->ptsrvr_next ) { + for ( ptsuffix = ptsrvr->ptsrvr_suffixes; ptsuffix != NULL; + ptsuffix = ptsuffix->ptsuffix_next ) { + if ( dn_is_underneath_suffix( ptsuffix, normdn, dnlen )) { + *srvrp = ptsrvr; + return( LDAP_SUCCESS ); /* got it */ + } + } + } + + *srvrp = NULL; + return( LDAP_NO_SUCH_OBJECT ); /* no match */ +} + + +/* + * Get an LDAP session handle for communicating with srvr. + * + * Returns an LDAP eror code, typically: + * LDAP_SUCCESS + * other + */ +int +passthru_get_connection( PassThruServer *srvr, LDAP **ldp ) +{ + int rc; + PassThruConnection *conn, *connprev; + LDAP *ld; + + PASSTHRU_ASSERT( srvr != NULL ); + PASSTHRU_ASSERT( ldp != NULL ); + + check_for_stale_connections( srvr ); + + slapi_lock_mutex( srvr->ptsrvr_connlist_mutex ); + rc = LDAP_SUCCESS; /* optimistic */ + + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "=> passthru_get_connection server %s:%d conns: %d maxconns: %d\n", + srvr->ptsrvr_hostname, srvr->ptsrvr_port, srvr->ptsrvr_connlist_count, + srvr->ptsrvr_maxconnections ); + + for ( ;; ) { + /* + * look for an available, already open connection + */ + connprev = NULL; + for ( conn = srvr->ptsrvr_connlist; conn != NULL; + conn = conn->ptconn_next ) { + if ( conn->ptconn_status == PASSTHRU_CONNSTATUS_OK + && conn->ptconn_usecount < srvr->ptsrvr_maxconcurrency ) { +#ifdef PASSTHRU_VERBOSE_LOGGING + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "<= passthru_get_connection server found " + "conn 0x%x to use)\n", conn->ptconn_ld ); +#endif + goto unlock_and_return; /* found one */ + } + connprev = conn; + } + + if ( srvr->ptsrvr_connlist_count < srvr->ptsrvr_maxconnections ) { + /* + * we have not exceeded the maximum number of connections allowed, + * so we initialize a new one and add it to the end of our list. + */ + if (( ld = slapi_ldap_init( srvr->ptsrvr_hostname, + srvr->ptsrvr_port, srvr->ptsrvr_secure, 1 )) == NULL ) { +#ifdef PASSTHRU_VERBOSE_LOGGING + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "<= passthru_get_connection slapi_ldap_init failed\n" ); +#endif + rc = LDAP_LOCAL_ERROR; + goto unlock_and_return; + } + + /* + * set protocol version to correct value for this server + */ + if ( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, + &srvr->ptsrvr_ldapversion ) != 0 ) { + slapi_ldap_unbind( ld ); + } + + conn = (PassThruConnection *)slapi_ch_malloc( + sizeof( PassThruConnection )); + conn->ptconn_ld = ld; + conn->ptconn_status = PASSTHRU_CONNSTATUS_OK; + time( &conn->ptconn_opentime ); + conn->ptconn_ldapversion = srvr->ptsrvr_ldapversion; + conn->ptconn_usecount = 0; + conn->ptconn_next = NULL; + conn->ptconn_prev = connprev; + if ( connprev == NULL ) { + srvr->ptsrvr_connlist = conn; + conn->ptconn_prev = NULL; + } else { + connprev->ptconn_next = conn; + conn->ptconn_prev = connprev; + } + + ++srvr->ptsrvr_connlist_count; + +#ifdef PASSTHRU_VERBOSE_LOGGING + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "<= passthru_get_connection added new conn 0x%x, " + "conn count now %d\n", ld, srvr->ptsrvr_connlist_count ); +#endif + goto unlock_and_return; /* got a new one */ + } + +#ifdef PASSTHRU_VERBOSE_LOGGING + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "... passthru_get_connection waiting for conn to free up\n" ); +#endif + slapi_wait_condvar( srvr->ptsrvr_connlist_cv, NULL ); + +#ifdef PASSTHRU_VERBOSE_LOGGING + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "... passthru_get_connection awake again\n" ); +#endif + } + +unlock_and_return: + if ( conn != NULL ) { + ++conn->ptconn_usecount; + *ldp = conn->ptconn_ld; + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "<= passthru_get_connection ld=0x%x (concurrency now %d)\n", + *ldp, conn->ptconn_usecount ); + } else { + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "<= passthru_get_connection error %d\n", rc ); + } + + slapi_unlock_mutex( srvr->ptsrvr_connlist_mutex ); + return( rc ); +} + + +/* + * Mark the connection ld is associated with as free to be used again. + * If dispose is non-zero, we mark the connection as "bad" and dispose + * of it and its ld once the use count becomes zero. + */ +void +passthru_release_connection( PassThruServer *srvr, LDAP *ld, int dispose ) +{ + PassThruConnection *conn, *connprev; + + PASSTHRU_ASSERT( srvr != NULL ); + PASSTHRU_ASSERT( ld != NULL ); + +#ifdef PASSTHRU_VERBOSE_LOGGING + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "=> passthru_release_connection ld=0x%x%s\n", ld, + dispose ? " (disposing)" : "" ); +#endif + + slapi_lock_mutex( srvr->ptsrvr_connlist_mutex ); + + /* + * find the connection structure this ld is part of + */ + connprev = NULL; + for ( conn = srvr->ptsrvr_connlist; conn != NULL; + conn = conn->ptconn_next ) { + if ( ld == conn->ptconn_ld ) { + break; + } + connprev = conn; + } + + if ( conn == NULL ) { /* ld not found -- unexpected */ + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "=> passthru_release_connection ld=0x%x not found\n", ld ); + } else { + PASSTHRU_ASSERT( conn->ptconn_usecount > 0 ); + --conn->ptconn_usecount; + if ( dispose ) { + conn->ptconn_status = PASSTHRU_CONNSTATUS_DOWN; + } + + if ( conn->ptconn_status != PASSTHRU_CONNSTATUS_OK + && conn->ptconn_usecount == 0 ) { + /* + * remove from server's connection list + */ + if ( connprev == NULL ) { + srvr->ptsrvr_connlist = conn->ptconn_next; + } else { + connprev->ptconn_next = conn->ptconn_next; + } + --srvr->ptsrvr_connlist_count; + + /* + * close connection and free memory + */ + close_and_dispose_connection( conn ); + } + } + + /* + * wake up a thread that is waiting for a connection (there may not be + * any but the slapi_notify_condvar() call should be cheap in any event). + */ + slapi_notify_condvar( srvr->ptsrvr_connlist_cv, 0 ); + + /* + * unlock and return + */ + slapi_unlock_mutex( srvr->ptsrvr_connlist_mutex ); +} + + +/* + * close all open connections in preparation for server shutdown, etc. + */ +void +passthru_close_all_connections( PassThruConfig *cfg ) +{ + PassThruServer *srvr; + PassThruConnection *conn, *nextconn; + + PASSTHRU_ASSERT( cfg != NULL ); + + for ( srvr = cfg->ptconfig_serverlist; srvr != NULL; + srvr = srvr->ptsrvr_next ) { + for ( conn = srvr->ptsrvr_connlist; conn != NULL; conn = nextconn ) { + nextconn = conn->ptconn_next; + close_and_dispose_connection( conn ); + } + } +} + + +/* + * return non-zero value if normdn falls underneath a suffix + */ +static int +dn_is_underneath_suffix( PassThruSuffix *suffix, char *normdn, int dnlen ) +{ + PASSTHRU_ASSERT( suffix != NULL ); + PASSTHRU_ASSERT( normdn != NULL ); + PASSTHRU_ASSERT( dnlen >= 0 ); + + return ( suffix->ptsuffix_len <= dnlen && + slapi_UTF8CASECMP( suffix->ptsuffix_normsuffix, + normdn + ( dnlen - suffix->ptsuffix_len )) == 0 ); +} + + +/* + * Unbind from server and dispose of a connection. + */ +static void +close_and_dispose_connection( PassThruConnection *conn ) +{ + PASSTHRU_ASSERT( conn != NULL ); + PASSTHRU_ASSERT( conn->ptconn_ld != NULL ); + + slapi_ldap_unbind( conn->ptconn_ld ); + conn->ptconn_ld = NULL; + slapi_ch_free( (void **)&conn ); +} + + +/* + * Close (or mark to be closed) any connections for this srvr that have + * exceeded the maximum connection lifetime. + */ +static void +check_for_stale_connections( PassThruServer *srvr ) +{ + PassThruConnection *conn, *prevconn, *nextconn; + time_t curtime; + + PASSTHRU_ASSERT( srvr != NULL ); + +#ifdef PASSTHRU_VERBOSE_LOGGING + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "check_for_stale_connections: server %s (lifetime %d secs)\n", + srvr->ptsrvr_url, srvr->ptsrvr_connlifetime ); +#endif + + + if ( srvr->ptsrvr_connlifetime <= 0 ) { + return; + } + + time( &curtime ); + + slapi_lock_mutex( srvr->ptsrvr_connlist_mutex ); + + prevconn = NULL; + for ( conn = srvr->ptsrvr_connlist; conn != NULL; conn = nextconn ) { + nextconn = conn->ptconn_next; + + if ( curtime - conn->ptconn_opentime > srvr->ptsrvr_connlifetime ) { + if ( conn->ptconn_usecount == 0 ) { + /* + * connection is idle and stale -- remove from server's list + */ +#ifdef PASSTHRU_VERBOSE_LOGGING + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "check_for_stale_connections: discarding idle, " + "stale connection 0x%x\n", conn->ptconn_ld ); +#endif + if ( prevconn == NULL ) { + srvr->ptsrvr_connlist = nextconn; + } else { + prevconn->ptconn_next = nextconn; + } + --srvr->ptsrvr_connlist_count; + close_and_dispose_connection( conn ); + } else { + /* + * connection is stale but in use -- mark to be disposed later + */ +#ifdef PASSTHRU_VERBOSE_LOGGING + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "check_for_stale_connections: marking connection 0x%x " + "stale (use count %d)\n", conn->ptconn_ld, + conn->ptconn_usecount ); +#endif + conn->ptconn_status = PASSTHRU_CONNSTATUS_STALE; + prevconn = conn; + } + } else { + prevconn = conn; + } + } + + slapi_unlock_mutex( srvr->ptsrvr_connlist_mutex ); +} diff --git a/ldap/servers/plugins/passthru/ptdebug.c b/ldap/servers/plugins/passthru/ptdebug.c new file mode 100644 index 00000000..0f01c4a7 --- /dev/null +++ b/ldap/servers/plugins/passthru/ptdebug.c @@ -0,0 +1,23 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * ptdebug.c - debugging-related code for Pass Through Authentication + * + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include "passthru.h" + +#ifdef _WIN32 +int *module_ldap_debug = 0; + +void plugin_init_debug_level(int *level_ptr) +{ + module_ldap_debug = level_ptr; +} +#endif diff --git a/ldap/servers/plugins/passthru/ptdllmain.c b/ldap/servers/plugins/passthru/ptdllmain.c new file mode 100644 index 00000000..0e9eaccf --- /dev/null +++ b/ldap/servers/plugins/passthru/ptdllmain.c @@ -0,0 +1,131 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#include "ldap.h" +#include "lber.h" +#include "passthru.h" + + +#ifdef _WIN32 +/* Lifted from Q125688 + * How to Port a 16-bit DLL to a Win32 DLL + * on the MSVC 4.0 CD + */ +BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved) +{ + WSADATA wsadata; + + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + /* Code from LibMain inserted here. Return TRUE to keep the + DLL loaded or return FALSE to fail loading the DLL. + + You may have to modify the code in your original LibMain to + account for the fact that it may be called more than once. + You will get one DLL_PROCESS_ATTACH for each process that + loads the DLL. This is different from LibMain which gets + called only once when the DLL is loaded. The only time this + is critical is when you are using shared data sections. + If you are using shared data sections for statically + allocated data, you will need to be careful to initialize it + only once. Check your code carefully. + + Certain one-time initializations may now need to be done for + each process that attaches. You may also not need code from + your original LibMain because the operating system may now + be doing it for you. + */ + /* + * 16 bit code calls UnlockData() + * which is mapped to UnlockSegment in windows.h + * in 32 bit world UnlockData is not defined anywhere + * UnlockSegment is mapped to GlobalUnfix in winbase.h + * and the docs for both UnlockSegment and GlobalUnfix say + * ".. function is oboslete. Segments have no meaning + * in the 32-bit environment". So we do nothing here. + */ + + if( errno = WSAStartup(0x0101, &wsadata ) != 0 ) + return FALSE; + + break; + + case DLL_THREAD_ATTACH: + /* Called each time a thread is created in a process that has + already loaded (attached to) this DLL. Does not get called + for each thread that exists in the process before it loaded + the DLL. + + Do thread-specific initialization here. + */ + break; + + case DLL_THREAD_DETACH: + /* Same as above, but called when a thread in the process + exits. + + Do thread-specific cleanup here. + */ + break; + + case DLL_PROCESS_DETACH: + /* Code from _WEP inserted here. This code may (like the + LibMain) not be necessary. Check to make certain that the + operating system is not doing it for you. + */ + WSACleanup(); + + break; + } + /* The return value is only used for DLL_PROCESS_ATTACH; all other + conditions are ignored. */ + return TRUE; // successful DLL_PROCESS_ATTACH +} +#else +int CALLBACK +LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine ) +{ + /*UnlockData( 0 );*/ + return( 1 ); +} +#endif + +#ifdef LDAP_DEBUG +#ifndef _WIN32 +#include <stdarg.h> +#include <stdio.h> + +void LDAPDebug( int level, char* fmt, ... ) +{ + static char debugBuf[1024]; + + if (module_ldap_debug && (*module_ldap_debug & level)) + { + va_list ap; + va_start (ap, fmt); + _snprintf (debugBuf, sizeof(debugBuf), fmt, ap); + va_end (ap); + + OutputDebugString (debugBuf); + } +} +#endif +#endif + +#ifndef _WIN32 + +/* The 16-bit version of the RTL does not implement perror() */ + +#include <stdio.h> + +void perror( const char *msg ) +{ + char buf[128]; + wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ; + OutputDebugString( buf ); +} + +#endif diff --git a/ldap/servers/plugins/passthru/ptpreop.c b/ldap/servers/plugins/passthru/ptpreop.c new file mode 100644 index 00000000..aaad0621 --- /dev/null +++ b/ldap/servers/plugins/passthru/ptpreop.c @@ -0,0 +1,252 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * ptpreop.c - bind pre-operation plugin for Pass Through Authentication + * + */ + +#include "passthru.h" + +static Slapi_PluginDesc pdesc = { "passthruauth", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, + "pass through authentication plugin" }; + +/* + * function prototypes + */ +static int passthru_bindpreop( Slapi_PBlock *pb ); +static int passthru_bindpreop_start( Slapi_PBlock *pb ); +static int passthru_bindpreop_close( Slapi_PBlock *pb ); + + +/* + * Plugin initialization function (which must be listed in the appropriate + * slapd config file). + */ +int +passthruauth_init( Slapi_PBlock *pb ) +{ + PASSTHRU_ASSERT( pb != NULL ); + + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "=> passthruauth_init\n" ); + + if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, + (void *)SLAPI_PLUGIN_VERSION_01 ) != 0 + || slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, + (void *)&pdesc ) != 0 + || slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, + (void *)passthru_bindpreop_start ) != 0 + || slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN, + (void *)passthru_bindpreop ) != 0 + || slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, + (void *)passthru_bindpreop_close ) != 0 ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "passthruauth_init failed\n" ); + return( -1 ); + } + + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "<= passthruauth_init succeeded\n" ); + + return( 0 ); +} + + +/* + * passthru_bindpreop_start() is called before the directory server + * is fully up. We parse our configuration and initialize any mutexes, etc. + */ +static int +passthru_bindpreop_start( Slapi_PBlock *pb ) +{ + int argc, rc; + char **argv; + + PASSTHRU_ASSERT( pb != NULL ); + + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "=> passthru_bindpreop_start\n" ); + + if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0 || + slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "unable to get arguments\n" ); + return( -1 ); + } + + if (( rc = passthru_config( argc, argv )) != LDAP_SUCCESS ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "configuration failed (%s)\n", ldap_err2string( rc )); + return( -1 ); + } + + return( 0 ); +} + + +/* + * Called right before the Directory Server shuts down. + */ +static int +passthru_bindpreop_close( Slapi_PBlock *pb ) +{ + PASSTHRU_ASSERT( pb != NULL ); + + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "=> passthru_bindpreop_close\n" ); + + /* + * close all our open connections. + * XXXmcs: free any memory, mutexes, etc. + */ + passthru_close_all_connections( passthru_get_config() ); + + return( 0 ); +} + + +static int +passthru_bindpreop( Slapi_PBlock *pb ) +{ + int rc, method; + char *normbinddn, *matcheddn; + char *libldap_errmsg, *pr_errmsg, *errmsg; + PassThruConfig *cfg; + PassThruServer *srvr; + struct berval *creds, **urls; + LDAPControl **reqctrls, **resctrls; + + PASSTHRU_ASSERT( pb != NULL ); + + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "=> passthru_bindpreop\n" ); + + /* + * retrieve parameters for bind operation + */ + if ( slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) != 0 || + slapi_pblock_get( pb, SLAPI_BIND_TARGET, &normbinddn ) != 0 || + slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &creds ) != 0 ) { + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "<= not handled (unable to retrieve bind parameters)\n" ); + return( PASSTHRU_OP_NOT_HANDLED ); + } + if ( normbinddn == NULL ) { + normbinddn = ""; + } + + /* + * We only handle simple bind requests that include non-NULL binddn and + * credentials. Let the Directory Server itself handle everything else. + */ + if ( method != LDAP_AUTH_SIMPLE || *normbinddn == '\0' + || creds->bv_len == 0 ) { + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "<= not handled (not simple bind or NULL dn/credentials)\n" ); + return( PASSTHRU_OP_NOT_HANDLED ); + } + + /* + * Get pass through authentication configuration. + */ + cfg = passthru_get_config(); + + /* + * Check to see if the target DN is one we should "pass through" to + * another server. + */ + if ( passthru_dn2server( cfg, normbinddn, &srvr ) != LDAP_SUCCESS ) { + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "<= not handled (not one of our suffixes)\n" ); + return( PASSTHRU_OP_NOT_HANDLED ); + } + + /* + * We are now committed to handling this bind request. + * Chain it off to another server. + */ + matcheddn = errmsg = libldap_errmsg = pr_errmsg = NULL; + urls = NULL; + resctrls = NULL; + if ( slapi_pblock_get( pb, SLAPI_REQCONTROLS, &reqctrls ) != 0 ) { + rc = LDAP_OPERATIONS_ERROR; + errmsg = "unable to retrieve bind controls"; + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, "%s\n", + errmsg ); + } else { + int lderrno; + + if (( rc = passthru_simple_bind_s( pb, srvr, PASSTHRU_CONN_TRIES, + normbinddn, creds, reqctrls, &lderrno, &matcheddn, + &libldap_errmsg, &urls, &resctrls )) == LDAP_SUCCESS ) { + rc = lderrno; + errmsg = libldap_errmsg; + } else if ( rc != LDAP_USER_CANCELLED ) { /* not abandoned */ + PRErrorCode prerr = PR_GetError(); + pr_errmsg = PR_smprintf( "error %d - %s %s (" + SLAPI_COMPONENT_NAME_NSPR " error %d - %s)", + rc, ldap_err2string( rc ), srvr->ptsrvr_url, + prerr, slapd_pr_strerror(prerr)); + if ( NULL != pr_errmsg ) { + errmsg = pr_errmsg; + } else { + errmsg = ldap_err2string( rc ); + } + rc = LDAP_OPERATIONS_ERROR; + } + } + + /* + * If bind succeeded, change authentication information associated + * with this connection. + */ + if ( rc == LDAP_SUCCESS ) { + char *ndn = slapi_ch_strdup( normbinddn ); + if (slapi_pblock_set(pb, SLAPI_CONN_DN, ndn) != 0 || + slapi_pblock_set(pb, SLAPI_CONN_AUTHMETHOD, + SLAPD_AUTH_SIMPLE) != 0) { + slapi_ch_free((void **)&ndn); + rc = LDAP_OPERATIONS_ERROR; + errmsg = "unable to set connection DN or AUTHTYPE"; + slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, + "%s\n", errmsg ); + } + } + + if ( rc != LDAP_USER_CANCELLED ) { /* not abandoned */ + /* + * Send a result to our client. + */ + if ( resctrls != NULL ) { + (void)slapi_pblock_set( pb, SLAPI_RESCONTROLS, &resctrls ); + } + slapi_send_ldap_result( pb, rc, matcheddn, errmsg, 0, urls ); + } + + /* + * Clean up -- free allocated memory, etc. + */ + if ( urls != NULL ) { + passthru_free_bervals( urls ); + } + if ( libldap_errmsg != NULL ) { + ldap_memfree( errmsg ); + } + if ( pr_errmsg != NULL ) { + PR_smprintf_free( pr_errmsg ); + } + if ( resctrls != NULL ) { + ldap_controls_free( resctrls ); + } + if ( matcheddn != NULL ) { + ldap_memfree( matcheddn ); + } + + slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, + "<= handled (error %d - %s)\n", rc, ldap_err2string( rc )); + + return( PASSTHRU_OP_HANDLED ); +} diff --git a/ldap/servers/plugins/passthru/ptutil.c b/ldap/servers/plugins/passthru/ptutil.c new file mode 100644 index 00000000..4a1b307b --- /dev/null +++ b/ldap/servers/plugins/passthru/ptutil.c @@ -0,0 +1,111 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * ptutil.c - utility functions for Pass Through Authentication + * + */ + +#include "passthru.h" + + +/* + * Convert a char * array into a struct berval * array. + * Always succeeds. + */ +struct berval ** +passthru_strs2bervals( char **ss ) +{ + int i; + struct berval **bvs; + + if ( ss == NULL || ss[0] == NULL ) { + return( NULL ); + } + + for ( i = 0; ss[i] != NULL; ++i ) { + ; + } + + bvs = (struct berval **)slapi_ch_calloc( i + 1, sizeof( struct berval * )); + for ( i = 0; ss[i] != NULL; ++i ) { + bvs[i] = (struct berval *)slapi_ch_malloc( sizeof( struct berval )); + bvs[i]->bv_val = slapi_ch_strdup( ss[i] ); + bvs[i]->bv_len = strlen( ss[i] ); + } + + return( bvs ); +} + + +/* + * Convert a struct berval * array into a char * array. + * Always succeeds. + */ +char ** +passthru_bervals2strs( struct berval **bvs ) +{ + int i; + char **strs; + + if ( bvs == NULL || bvs[0] == NULL ) { + return( NULL ); + } + + for ( i = 0; bvs[i] != NULL; ++i ) { + ; + } + + strs = (char **)slapi_ch_calloc( i + 1, sizeof( char * )); + for ( i = 0; bvs[i] != NULL; ++i ) { + strs[i] = slapi_ch_strdup( bvs[i]->bv_val ); + } + + return( strs ); +} + + +void +passthru_free_bervals( struct berval **bvs ) +{ + int i; + + if ( bvs != NULL ) { + for ( i = 0; bvs[ i ] != NULL; ++i ) { + slapi_ch_free( (void **)&bvs[ i ] ); + } + } + slapi_ch_free( (void **)&bvs ); +} + + +char * +passthru_urlparse_err2string( int err ) +{ + char *s; + + switch( err ) { + case 0: + s = "no error"; + break; + case LDAP_URL_ERR_NOTLDAP: + s = "missing ldap:// or ldaps://"; + break; + case LDAP_URL_ERR_NODN: + s = "missing suffix"; + break; + case LDAP_URL_ERR_BADSCOPE: + s = "invalid search scope"; + break; + case LDAP_URL_ERR_MEM: + s = "unable to allocate memory"; + break; + case LDAP_URL_ERR_PARAM: + s = "bad parameter to an LDAP URL function"; + break; + } + + return( s ); +} |
