summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/passthru
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/plugins/passthru
downloadds-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/Makefile90
-rw-r--r--ldap/servers/plugins/passthru/PT-Notes30
-rw-r--r--ldap/servers/plugins/passthru/libpassthru.def14
-rw-r--r--ldap/servers/plugins/passthru/passthru.h131
-rw-r--r--ldap/servers/plugins/passthru/ptbind.c144
-rw-r--r--ldap/servers/plugins/passthru/ptconfig.c301
-rw-r--r--ldap/servers/plugins/passthru/ptconn.c420
-rw-r--r--ldap/servers/plugins/passthru/ptdebug.c23
-rw-r--r--ldap/servers/plugins/passthru/ptdllmain.c131
-rw-r--r--ldap/servers/plugins/passthru/ptpreop.c252
-rw-r--r--ldap/servers/plugins/passthru/ptutil.c111
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 );
+}