[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: (ITS#4750) libldap initialization of ~/.ldaprc and setuid



--pf9I7BMVVzbSWLtt
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline


Hi,

OpenLDAP issue ITS#4750 is still unresolved (it affects current
versions of nss_ldap and pam_ldap), and I consider it to be pretty
serious:
- Even security-conscious applications like pam_ldap still parse
  files from unsafe locations, including the current directory.
- Attempting to read from a file in the current directory can
  cause problems on its own, e.g. when the directory is an autofs
  mountpoint (In fact, I became aware of this issue by investigating
  deadlocks occurring in such a situation)
- If an application uses LDAP in more than one context, like a
  program using LDAP while also linking to nss_ldap and pam_ldap,
  the settings can interfere (unless very much care is taken, see
  below).  This is bad, as the very purpose of nss and pam is to
  make the underlying mechanisms completely transparent to the
  application.
- The existing LDAPNOINIT mechanism is only effective for the first
  call which initializes the global option structure. Thus, almost
  no one can reliably use it: the options may already have been
  initialized e.g. by nss_ldap which nearly every program might
  link to.

The suggested workaround so far is to force nss_ldap, pam_ldap, and
possibly others, to override all relevant options with safe values.
To me, this seems to be quite error-prone and not a satisfactory
solution:
- it requires duplication of much of the configuration parsing code,
  which needs to be kept in sync with OpenLDAP's syntax and semantics
  (or worse, allow the syntax to diverge), and
- it requires users to think of and nail down each and every potentially
  relevant option separately (note that current versions of libldap and
  pam_ldap silently ignore syntax errors in the config file, so one may
  very easily be in a false sense of security).
- It does not stop libldap from opening files it shouldn't open in the
  first place.
As Kurt Zeilenga already noted, a proper solution will require some
redesign, so...

I include 3 patches: one for libldap (against HEAD as of 20070216), and
corresponding patches for nss_ldap-254 and pam_ldap-183.

The first lines of the openldap patch (the changes to ldap.h) and
the nss_ldap patch should tell you how it is supposed to work:
libraries can obtain a private copy of the "globaloptions",
in an opaque "LDAPContext" object, to be initialized in a safe way
and independently from other copies of that structure.
The existing struct globaloptions is used by default to stay compatible
with existing programs.

I'm willing to write more documentation too but I would like to get
some some feedback on it first,

Regards,

Timo Felbinger


--pf9I7BMVVzbSWLtt
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="openldap.patch"

This patch file is derived from OpenLDAP Software. All of the modifications to
OpenLDAP Software represented in the following patch(es) were developed by
Timo Felbinger <timo@physik.uni-potsdam.de>.
These modifications are not subject to any license of University of Potsdam.

I, Timo Felbinger, hereby place the following modifications to OpenLDAP Software
(and only these modifications) into the public domain.
Hence, these modifications may be freely used and/or redistributed for any purpose
with or without attribution and/or other notice. 

diff -Nru openldap-src/include/ldap.h openldap-src-context/include/ldap.h
--- openldap-src/include/ldap.h	2007-02-12 10:53:59.000000000 +0000
+++ openldap-src-context/include/ldap.h	2007-02-17 13:22:45.000000000 +0000
@@ -696,6 +696,8 @@
  */
 typedef struct ldap LDAP;
 
+typedef struct ldapoptions LDAPContext;
+
 #define LDAP_DEREF_NEVER		0x00
 #define LDAP_DEREF_SEARCHING	0x01
 #define LDAP_DEREF_FINDING		0x02
@@ -890,6 +892,12 @@
 	int option,
 	LDAP_CONST void *invalue));
 
+LDAP_F( int )
+ldap_set_option_in_context LDAP_P((
+	LDAPContext *context,
+	int option,
+	LDAP_CONST void *invalue));
+
 /* V3 REBIND Function Callback Prototype */
 typedef int (LDAP_REBIND_PROC) LDAP_P((
 	LDAP *ld, LDAP_CONST char *url,
@@ -1382,10 +1390,30 @@
 	LDAP **ldp ));
 
 LDAP_F( int )
+ldap_create_in_context LDAP_P((
+	LDAP **ldp,
+	LDAPContext *context ));
+
+LDAP_F( int )
 ldap_initialize LDAP_P((
 	LDAP **ldp,
 	LDAP_CONST char *url ));
 
+LDAP_F( int )
+ldap_initialize_in_context LDAP_P((
+	LDAP **ldp,
+	LDAP_CONST char *url,
+	LDAPContext *context ));
+
+LDAP_F( int )
+ldap_create_context LDAP_P((
+	LDAPContext **context,
+	char **directives ));
+
+LDAP_F( int )
+ldap_destroy_context LDAP_P((
+	LDAPContext *context ));
+
 /*
  * in tls.c
  */
diff -Nru openldap-src/include/ldap_pvt.h openldap-src-context/include/ldap_pvt.h
--- openldap-src/include/ldap_pvt.h	2007-02-12 03:20:24.000000000 +0000
+++ openldap-src-context/include/ldap_pvt.h	2007-02-17 13:22:45.000000000 +0000
@@ -278,6 +278,8 @@
 	int option, void *arg ));
 LDAP_F (int) ldap_pvt_tls_set_option LDAP_P(( struct ldap *ld,
 	int option, void *arg ));
+LDAP_F (int) ldap_pvt_tls_set_option_2 LDAP_P(( struct ldapoptions *lo, struct ldap *ld,
+	int option, void *arg ));
 
 LDAP_F (void) ldap_pvt_tls_destroy LDAP_P(( void ));
 LDAP_F (int) ldap_pvt_tls_init LDAP_P(( void ));
diff -Nru openldap-src/libraries/libldap/init.c openldap-src-context/libraries/libldap/init.c
--- openldap-src/libraries/libldap/init.c	2007-02-05 19:32:44.000000000 +0000
+++ openldap-src-context/libraries/libldap/init.c	2007-02-17 13:22:45.000000000 +0000
@@ -124,6 +124,7 @@
 #define MAX_LDAP_ENV_PREFIX_LEN 8
 
 static void openldap_ldap_init_w_conf(
+	struct ldapoptions *gopts,
 	const char *file, int userconf )
 {
 	char linebuf[ AC_LINE_MAX ];
@@ -131,10 +132,11 @@
 	int i;
 	char *cmd, *opt;
 	char *start, *end;
-	struct ldapoptions *gopts;
 
-	if ((gopts = LDAP_INT_GLOBAL_OPT()) == NULL) {
-		return;			/* Could not allocate mem for global options */
+	if( ! gopts ) {
+		if ((gopts = LDAP_INT_GLOBAL_OPT()) == NULL) {
+			return;			/* Could not allocate mem for global options */
+		}
 	}
 
 	if (file == NULL) {
@@ -244,7 +246,7 @@
 				* (char**) p = LDAP_STRDUP(opt);
 				break;
 			case ATTR_OPTION:
-				ldap_set_option( NULL, attrs[i].offset, opt );
+				ldap_set_option_in_context( gopts, attrs[i].offset, opt );
 				break;
 			case ATTR_SASL:
 #ifdef HAVE_CYRUS_SASL
@@ -253,7 +255,7 @@
 				break;
 			case ATTR_TLS:
 #ifdef HAVE_TLS
-			   	ldap_int_tls_config( NULL, attrs[i].offset, opt );
+			   	ldap_int_tls_config_in_context( gopts, attrs[i].offset, opt );
 #endif
 				break;
 			case ATTR_OPT_TV: {
@@ -285,7 +287,7 @@
 
 static void openldap_ldap_init_w_sysconf(const char *file)
 {
-	openldap_ldap_init_w_conf( file, 0 );
+	openldap_ldap_init_w_conf( NULL, file, 0 );
 }
 
 static void openldap_ldap_init_w_userconf(const char *file)
@@ -314,11 +316,11 @@
 
 		/* try ~/file */
 		sprintf(path, "%s" LDAP_DIRSEP "%s", home, file);
-		openldap_ldap_init_w_conf(path, 1);
+		openldap_ldap_init_w_conf(NULL, path, 1);
 
 		/* try ~/.file */
 		sprintf(path, "%s" LDAP_DIRSEP ".%s", home, file);
-		openldap_ldap_init_w_conf(path, 1);
+		openldap_ldap_init_w_conf(NULL, path, 1);
 	}
 
 	if(path != NULL) {
@@ -326,7 +328,7 @@
 	}
 
 	/* try file */
-	openldap_ldap_init_w_conf(file, 1);
+	openldap_ldap_init_w_conf(NULL, file, 1);
 }
 
 static void openldap_ldap_init_w_env(
@@ -466,9 +468,10 @@
 void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl )
 {
 	if (dbglvl)
-	    gopts->ldo_debug = *dbglvl;
+      /* FIXME: currently ldo_debug is an always global option only, so we set both places: */
+	    gopts->ldo_debug = LDAP_INT_GLOBAL_OPT()->ldo_debug = *dbglvl;
 	else
-		gopts->ldo_debug = 0;
+		gopts->ldo_debug = LDAP_INT_GLOBAL_OPT()->ldo_debug = 0;
 
 	gopts->ldo_version   = LDAP_VERSION2;
 	gopts->ldo_deref     = LDAP_DEREF_NEVER;
@@ -531,7 +534,10 @@
 char * ldap_int_hostname = NULL;
 #endif
 
-void ldap_int_initialize( struct ldapoptions *gopts, int *dbglvl )
+void ldap_int_initialize(
+	struct ldapoptions *gopts,
+	int *dbglvl,
+	char **directives )
 {
 	if ( gopts->ldo_valid == LDAP_INITIALIZED ) {
 		return;
@@ -593,6 +599,19 @@
 
 	ldap_int_initialize_global_options(gopts, NULL);
 
+	if( directives ) {
+		for( ; *directives; ++directives ) {
+			if( ! strncmp( *directives, "file=", 5 ) ) {
+				openldap_ldap_init_w_conf( gopts, *directives + 5, 1 );
+				continue;
+			}
+			/* add more directives here... */
+			gopts->ldo_valid = LDAP_TRASHED_SESSION;
+			return;
+		}
+		return;
+	}
+
 	if( getenv("LDAPNOINIT") != NULL ) {
 		return;
 	}
diff -Nru openldap-src/libraries/libldap/ldap-int.h openldap-src-context/libraries/libldap/ldap-int.h
--- openldap-src/libraries/libldap/ldap-int.h	2007-02-15 00:42:23.000000000 +0000
+++ openldap-src-context/libraries/libldap/ldap-int.h	2007-02-17 13:22:45.000000000 +0000
@@ -417,7 +417,7 @@
 
 LDAP_V ( struct ldapoptions ) ldap_int_global_options;
 
-LDAP_F ( void ) ldap_int_initialize LDAP_P((struct ldapoptions *, int *));
+LDAP_F ( void ) ldap_int_initialize LDAP_P((struct ldapoptions *, int *, char **directives ));
 LDAP_F ( void ) ldap_int_initialize_global_options LDAP_P((
 	struct ldapoptions *, int *));
 
@@ -652,6 +652,9 @@
 LDAP_F (int) ldap_int_tls_config LDAP_P(( LDAP *ld,
 	int option, const char *arg ));
 
+LDAP_F (int) ldap_int_tls_config_in_context LDAP_P(( struct ldapoptions *lo,
+	int option, const char *arg ));
+
 LDAP_F (int) ldap_int_tls_start LDAP_P(( LDAP *ld,
 	LDAPConn *conn, LDAPURLDesc *srv ));
 
diff -Nru openldap-src/libraries/libldap/open.c openldap-src-context/libraries/libldap/open.c
--- openldap-src/libraries/libldap/open.c	2007-02-12 03:20:24.000000000 +0000
+++ openldap-src-context/libraries/libldap/open.c	2007-02-17 13:45:19.000000000 +0000
@@ -87,27 +87,88 @@
 	return ld;
 }
 
+int
+ldap_free_context_internals( LDAPContext *context )
+{
+	ldap_free_urllist( context->ldo_defludp );
+#ifdef HAVE_CYRUS_SASL
+	LDAP_FREE( context->ldo_def_sasl_authzid );
+	LDAP_FREE( context->ldo_def_sasl_authcid );
+	LDAP_FREE( context->ldo_def_sasl_realm );
+	LDAP_FREE( context->ldo_def_sasl_mech );
+#endif
+	return LDAP_SUCCESS;
+}
+
+/* public destructor of LDAPContext */
+int
+ldap_destroy_context( LDAPContext *context )
+{
+	if( context ) {
+		ldap_free_context_internals( context );
+		free( context );
+	}
+	return LDAP_SUCCESS;
+}
+
+/* public constructor of LDAPContext */
+int
+ldap_create_context(
+	LDAPContext **context,
+	/* directives: NULL-terminated list of initialization directives:
+	 *  - NULL: default initialization procedure (see ldap.conf(5))
+	 *  - { NULL }: equivalent to LDAPNOINIT
+	 *  - { ..., "file=path", ... }: parse path like user-config file
+	 */
+	char **directives )
+{
+	LDAPContext *lo;
+	
+	*context = NULL;
+	lo = ( LDAPContext * ) LDAP_CALLOC( 1, sizeof( LDAPContext ) );
+	if( ! lo )
+		return LDAP_NO_MEMORY;
+
+	Debug( LDAP_DEBUG_TRACE, "ldap_create_context %p\n", lo, 0, 0 );
+
+	lo->ldo_valid = LDAP_UNINITIALIZED;
+	ldap_int_initialize( lo, NULL, directives );
+	if( lo->ldo_valid != LDAP_INITIALIZED )
+		return LDAP_LOCAL_ERROR;
 
+	*context = lo;
+
+	return LDAP_SUCCESS;
+}
 
 int
 ldap_create( LDAP **ldp )
 {
+	return ldap_create_in_context( ldp, NULL );
+}
+
+int
+ldap_create_in_context( LDAP **ldp, LDAPContext *gopts )
+{
 	LDAP			*ld;
-	struct ldapoptions	*gopts;
 
 	*ldp = NULL;
-	/* Get pointer to global option structure */
-	if ( (gopts = LDAP_INT_GLOBAL_OPT()) == NULL) {
-		return LDAP_NO_MEMORY;
-	}
 
-	/* Initialize the global options, if not already done. */
-	if( gopts->ldo_valid != LDAP_INITIALIZED ) {
-		ldap_int_initialize(gopts, NULL);
-		if ( gopts->ldo_valid != LDAP_INITIALIZED )
-			return LDAP_LOCAL_ERROR;
+	if( ! gopts ) {
+		/* default is the global context */
+		if ( (gopts = LDAP_INT_GLOBAL_OPT()) == NULL) {
+			return LDAP_NO_MEMORY;
+		}
+
+		/* Initialize the global options, if not already done. */
+		if( gopts->ldo_valid != LDAP_INITIALIZED ) {
+			ldap_int_initialize(gopts, NULL, NULL);
+		}
 	}
 
+	if( gopts->ldo_valid != LDAP_INITIALIZED )
+		return LDAP_LOCAL_ERROR;
+
 	Debug( LDAP_DEBUG_TRACE, "ldap_create\n", 0, 0, 0 );
 
 	if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) {
@@ -167,13 +228,7 @@
 
 nomem:
 	ldap_free_select_info( ld->ld_selectinfo );
-	ldap_free_urllist( ld->ld_options.ldo_defludp );
-#ifdef HAVE_CYRUS_SASL
-	LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid );
-	LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid );
-	LDAP_FREE( ld->ld_options.ldo_def_sasl_realm );
-	LDAP_FREE( ld->ld_options.ldo_def_sasl_mech );
-#endif
+	ldap_free_context_internals( &ld->ld_options );
 	LDAP_FREE( (char *)ld );
 	return LDAP_NO_MEMORY;
 }
@@ -215,11 +270,17 @@
 int
 ldap_initialize( LDAP **ldp, LDAP_CONST char *url )
 {
+	return ldap_initialize_in_context( ldp, url, NULL );
+}
+
+int
+ldap_initialize_in_context( LDAP **ldp, LDAP_CONST char *url, LDAPContext *context ) 
+{
 	int rc;
 	LDAP *ld;
 
 	*ldp = NULL;
-	rc = ldap_create(&ld);
+	rc = ldap_create_in_context(&ld, context);
 	if ( rc != LDAP_SUCCESS )
 		return rc;
 
diff -Nru openldap-src/libraries/libldap/options.c openldap-src-context/libraries/libldap/options.c
--- openldap-src/libraries/libldap/options.c	2007-02-06 22:02:47.000000000 +0000
+++ openldap-src-context/libraries/libldap/options.c	2007-02-17 13:22:45.000000000 +0000
@@ -97,16 +97,6 @@
 {
 	struct ldapoptions *lo;
 
-	/* Get pointer to global option structure */
-	lo = LDAP_INT_GLOBAL_OPT();   
-	if (NULL == lo)	{
-		return LDAP_NO_MEMORY;
-	}
-
-	if( lo->ldo_valid != LDAP_INITIALIZED ) {
-		ldap_int_initialize(lo, NULL);
-	}
-
 	if(ld != NULL) {
 		assert( LDAP_VALID( ld ) );
 
@@ -117,6 +107,18 @@
 		lo = &ld->ld_options;
 	}
 
+	if( lo == NULL ) {
+		/* Get pointer to global option structure */
+		lo = LDAP_INT_GLOBAL_OPT();   
+		if (NULL == lo)	{
+			return LDAP_NO_MEMORY;
+		}
+
+		if( lo->ldo_valid != LDAP_INITIALIZED ) {
+			ldap_int_initialize(lo, NULL, NULL);
+		}
+	}
+
 	if(outvalue == NULL) {
 		/* no place to get to */
 		return LDAP_OPT_ERROR;
@@ -347,19 +349,35 @@
 }
 
 int
+ldap_set_option_in_context(
+	LDAPContext *context,
+	int		option,
+	LDAP_CONST void	*invalue)
+{
+	return ldap_set_option_2( context, NULL, option, invalue );
+}
+
+int
 ldap_set_option(
 	LDAP	*ld,
 	int		option,
 	LDAP_CONST void	*invalue)
 {
-	struct ldapoptions *lo;
-	int *dbglvl = NULL;
+	return ldap_set_option_2( NULL, ld, option, invalue );
+}
 
-	/* Get pointer to global option structure */
-	lo = LDAP_INT_GLOBAL_OPT();
-	if (lo == NULL)	{
-		return LDAP_NO_MEMORY;
-	}
+/*
+ *  ldap_set_option_2: can set options per LDAP handle or per context.
+ *  if handle is given, the context is ignored.
+ */
+int
+ldap_set_option_2(
+	struct ldapoptions *lo,
+	LDAP	*ld,
+	int		option,
+	LDAP_CONST void	*invalue)
+{
+	int *dbglvl = NULL;
 
 	/*
 	 * The architecture to turn on debugging has a chicken and egg
@@ -370,10 +388,6 @@
 		dbglvl = (int *) invalue;
 	}
 
-	if( lo->ldo_valid != LDAP_INITIALIZED ) {
-		ldap_int_initialize(lo, dbglvl);
-	}
-
 	if(ld != NULL) {
 		assert( LDAP_VALID( ld ) );
 
@@ -384,6 +398,17 @@
 		lo = &ld->ld_options;
 	}
 
+	if( lo == NULL ) {
+		/* Get pointer to global option structure */
+		lo = LDAP_INT_GLOBAL_OPT();
+		if (lo == NULL)	{
+			return LDAP_NO_MEMORY;
+		}
+		if( lo->ldo_valid != LDAP_INITIALIZED ) {
+			ldap_int_initialize(lo, dbglvl, NULL);
+		}
+	}
+
 	switch(option) {
 	case LDAP_OPT_REFERRALS:
 		if(invalue == LDAP_OPT_OFF) {
@@ -668,7 +693,7 @@
 
 	default:
 #ifdef HAVE_TLS
-		if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 )
+		if ( ldap_pvt_tls_set_option_2( lo, ld, option, (void *)invalue ) == 0 )
 			return LDAP_OPT_SUCCESS;
 #endif
 #ifdef HAVE_CYRUS_SASL
diff -Nru openldap-src/libraries/libldap/tls.c openldap-src-context/libraries/libldap/tls.c
--- openldap-src/libraries/libldap/tls.c	2007-01-24 22:38:26.000000000 +0000
+++ openldap-src-context/libraries/libldap/tls.c	2007-02-17 13:22:45.000000000 +0000
@@ -1178,8 +1178,20 @@
 }
 
 int
+ldap_int_tls_config_in_context( struct ldapoptions *lo, int option, const char *arg )
+{
+	return ldap_int_tls_config_2( lo, NULL, option, arg );
+}
+
+int
 ldap_int_tls_config( LDAP *ld, int option, const char *arg )
 {
+	return ldap_int_tls_config_2( NULL, ld, option, arg );
+}
+
+int
+ldap_int_tls_config_2( struct ldapconfig *lo, LDAP *ld, int option, const char *arg )
+{
 	int i;
 
 	switch( option ) {
@@ -1190,7 +1202,7 @@
 	case LDAP_OPT_X_TLS_RANDOM_FILE:
 	case LDAP_OPT_X_TLS_CIPHER_SUITE:
 	case LDAP_OPT_X_TLS_DHFILE:
-		return ldap_pvt_tls_set_option( ld, option, (void *) arg );
+		return ldap_pvt_tls_set_option_2( lo, ld, option, (void *) arg );
 
 	case LDAP_OPT_X_TLS_REQUIRE_CERT:
 	case LDAP_OPT_X_TLS:
@@ -1216,7 +1228,7 @@
 		}
 
 		if (i >= 0) {
-			return ldap_pvt_tls_set_option( ld, option, &i );
+			return ldap_pvt_tls_set_option_2( lo, ld, option, &i );
 		}
 		return -1;
 #ifdef HAVE_OPENSSL_CRL
@@ -1230,7 +1242,7 @@
 			i = LDAP_OPT_X_TLS_CRL_ALL ;
 		}
 		if (i >= 0) {
-			return ldap_pvt_tls_set_option( ld, option, &i );
+			return ldap_pvt_tls_set_option_2( lo, ld, option, &i );
 		}
 		return -1;
 #endif
@@ -1334,7 +1346,12 @@
 int
 ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
 {
-	struct ldapoptions *lo;
+	return ldap_pvt_tls_set_option_2( NULL, ld, option, arg );
+}
+
+int
+ldap_pvt_tls_set_option_2( struct ldapoptions *lo, LDAP *ld, int option, void *arg )
+{
 
 	if( ld != NULL ) {
 		assert( LDAP_VALID( ld ) );
@@ -1345,7 +1362,8 @@
 
 		lo = &ld->ld_options;
 
-	} else {
+	}
+  if( lo == NULL ) {
 		/* Get pointer to global option structure */
 		lo = LDAP_INT_GLOBAL_OPT();   
 		if ( lo == NULL ) {

--pf9I7BMVVzbSWLtt
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="nss_ldap.patch"

This patch file is derived from PADL Software (nss_ldap).
All of the modifications to PADL Software represented in the following
patch(es) were developed by Timo Felbinger <timo@physik.uni-potsdam.de>.
These modifications are not subject to any license of University of Potsdam.

I, Timo Felbinger, hereby place the following modifications to PADL Software
(and only these modifications) into the public domain.
Hence, these modifications may be freely used and/or redistributed for any purpose
with or without attribution and/or other notice. 

diff -Nru nss_ldap-254/config.h.in nss_ldap-254-context/config.h.in
--- nss_ldap-254/config.h.in	2006-12-18 08:12:56.000000000 +0000
+++ nss_ldap-254-context/config.h.in	2007-02-17 14:46:02.000000000 +0000
@@ -132,6 +132,9 @@
 /* Define to 1 if you have the `ldap_initialize' function. */
 #undef HAVE_LDAP_INITIALIZE
 
+/* Define to 1 if you have the `ldap_create_context' function. */
+#undef HAVE_LDAP_CREATE_CONTEXT
+
 /* Define to 1 if you have the `ldap_ld_free' function. */
 #undef HAVE_LDAP_LD_FREE
 
diff -Nru nss_ldap-254/configure nss_ldap-254-context/configure
--- nss_ldap-254/configure	2006-12-18 08:12:56.000000000 +0000
+++ nss_ldap-254-context/configure	2007-02-17 14:46:37.000000000 +0000
@@ -1,4 +1,6 @@
 #! /bin/sh
+echo please run autoconf first!
+exit 1
 
 # Guess values for system-dependent variables and create Makefiles.
 # Generated automatically using autoconf version 2.13 
diff -Nru nss_ldap-254/configure.in nss_ldap-254-context/configure.in
--- nss_ldap-254/configure.in	2006-12-18 08:12:56.000000000 +0000
+++ nss_ldap-254-context/configure.in	2007-02-17 14:46:02.000000000 +0000
@@ -297,7 +297,7 @@
 AC_CHECK_FUNCS(sasl_auxprop_request)
 AC_CHECK_FUNCS(ldap_init ldap_get_lderrno ldap_parse_result ldap_memfree ldap_controls_free)
 AC_CHECK_FUNCS(ldap_ld_free ldap_explode_rdn ldap_set_option ldap_get_option)
-AC_CHECK_FUNCS(ldap_sasl_interactive_bind_s ldap_initialize ldap_search_ext)
+AC_CHECK_FUNCS(ldap_sasl_interactive_bind_s ldap_initialize ldap_search_ext ldap_create_context)
 AC_CHECK_FUNCS(ldap_create_control ldap_create_page_control ldap_parse_page_control)
 if test "$enable_ssl" \!= "no"; then
   AC_CHECK_FUNCS(ldapssl_client_init ldap_start_tls_s ldap_pvt_tls_set_option ldap_start_tls)
diff -Nru nss_ldap-254/ldap-nss.c nss_ldap-254-context/ldap-nss.c
--- nss_ldap-254/ldap-nss.c	2006-12-18 08:12:56.000000000 +0000
+++ nss_ldap-254-context/ldap-nss.c	2007-02-17 14:46:02.000000000 +0000
@@ -137,7 +137,7 @@
 /*
  * Global LDAP session.
  */
-static ldap_session_t __session = { NULL, NULL, 0, LS_UNINITIALIZED };
+static ldap_session_t __session = { NULL, NULL, NULL, 0, LS_UNINITIALIZED };
 
 #if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
 static pthread_once_t __once = PTHREAD_ONCE_INIT;
@@ -1003,7 +1003,7 @@
 }
 
 static NSS_STATUS
-do_init_session (LDAP ** ld, const char *uri, int defport)
+do_init_session ( LDAPContext **ldap_context, LDAP ** ld, const char *uri, int defport)
 {
   int rc;
   int ldaps;
@@ -1011,6 +1011,17 @@
   char *p;
   NSS_STATUS stat;
 
+#ifdef HAVE_LDAP_CREATE_CONTEXT
+  if( ! *ldap_context )
+    {
+      /* make sure ldap config is read in a safe way */
+      static const char *directives[2] = { "file=" NSS_LDAP_PATH_CONF, NULL };
+      int rc = ldap_create_context( ldap_context, directives );
+      if (rc != LDAP_SUCCESS)
+        return NSS_UNAVAIL;
+    }
+#endif
+
   ldaps = (strncasecmp (uri, "ldaps://", sizeof ("ldaps://") - 1) == 0);
   p = strchr (uri, ':');
   /* we should be looking for the second instance to find the port number */
@@ -1028,7 +1039,11 @@
       uri = uribuf;
     }
 
+# ifdef HAVE_LDAP_CREATE_CONTEXT
+  rc = ldap_initialize_in_context (ld, uri, *ldap_context);
+#	else
   rc = ldap_initialize (ld, uri);
+#	endif
 #else
   if (strncasecmp (uri, "ldap://";, sizeof ("ldap://";) - 1) != 0)
     {
@@ -1311,7 +1326,7 @@
   assert (__session.ls_current_uri <= NSS_LDAP_CONFIG_URI_MAX);
   assert (cfg->ldc_uris[__session.ls_current_uri] != NULL);
 
-  stat = do_init_session (&__session.ls_conn,
+  stat = do_init_session ( &__session.ldap_context, &__session.ls_conn,
 			  cfg->ldc_uris[__session.ls_current_uri],
 			  cfg->ldc_port);
   if (stat != NSS_SUCCESS)
diff -Nru nss_ldap-254/ldap-nss.h nss_ldap-254-context/ldap-nss.h
--- nss_ldap-254/ldap-nss.h	2006-12-18 08:12:56.000000000 +0000
+++ nss_ldap-254-context/ldap-nss.h	2007-02-17 14:46:02.000000000 +0000
@@ -416,12 +416,19 @@
 
 typedef enum ldap_session_state ldap_session_state_t;
 
+/* for readability, make sure LDAPContext is at least a dummy type: */
+#ifndef HAVE_LDAP_CREATE_CONTEXT
+#	define LDAPContext void
+#endif
+
 /*
  * convenient wrapper around pointer into global config list, and a
  * connection to an LDAP server.
  */
 struct ldap_session
 {
+  /* the context, if supported */
+  LDAPContext *ldap_context;
   /* the connection */
   LDAP *ls_conn;
   /* pointer into config table */

--pf9I7BMVVzbSWLtt
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="pam_ldap.patch"

This patch file is derived from PADL Software (pam_ldap).
All of the modifications to PADL Software represented in the following
patch(es) were developed by Timo Felbinger <timo@physik.uni-potsdam.de>.
These modifications are not subject to any license of University of Potsdam.

I, Timo Felbinger, hereby place the following modifications to PADL Software
(and only these modifications) into the public domain.
Hence, these modifications may be freely used and/or redistributed for any purpose
with or without attribution and/or other notice. 

diff -Nru pam_ldap-183/config.h.in pam_ldap-183-context/config.h.in
--- pam_ldap-183/config.h.in	2006-10-19 13:22:27.000000000 +0000
+++ pam_ldap-183-context/config.h.in	2007-02-17 14:55:38.000000000 +0000
@@ -33,6 +33,9 @@
 /* Define if you have the ldap_initialize function.  */
 #undef HAVE_LDAP_INITIALIZE
 
+/* Define if you have the ldap_create_context function.  */
+#undef HAVE_LDAP_CREATE_CONTEXT
+
 /* Define if you have the ldap_memfree function.  */
 #undef HAVE_LDAP_MEMFREE
 
diff -Nru pam_ldap-183/configure pam_ldap-183-context/configure
--- pam_ldap-183/configure	2006-10-19 13:22:27.000000000 +0000
+++ pam_ldap-183-context/configure	2007-02-17 14:55:38.000000000 +0000
@@ -1,4 +1,6 @@
 #! /bin/sh
+echo Please run autoconf first!
+exit 1
 
 # Guess values for system-dependent variables and create Makefiles.
 # Generated automatically using autoconf version 2.13 
diff -Nru pam_ldap-183/configure.in pam_ldap-183-context/configure.in
--- pam_ldap-183/configure.in	2006-10-19 13:22:27.000000000 +0000
+++ pam_ldap-183-context/configure.in	2007-02-17 14:55:38.000000000 +0000
@@ -131,6 +131,7 @@
   AC_CHECK_FUNCS(ldapssl_init ldap_start_tls_s ldap_pvt_tls_set_option)
 fi
 AC_CHECK_FUNCS(ldap_initialize)
+AC_CHECK_FUNCS(ldap_create_context)
 AC_CHECK_FUNCS(ldap_sasl_bind ldap_sasl_interactive_bind_s)
 AC_CHECK_FUNCS(gethostbyname_r)
 
diff -Nru pam_ldap-183/pam_ldap.c pam_ldap-183-context/pam_ldap.c
--- pam_ldap-183/pam_ldap.c	2006-10-19 13:22:27.000000000 +0000
+++ pam_ldap-183-context/pam_ldap.c	2007-02-17 15:08:39.000000000 +0000
@@ -155,6 +155,11 @@
 #endif
 static int pam_debug_level __UNUSED__ = 0;
 
+#ifndef HAVE_LDAP_CREATE_CONTEXT
+#	typedef LDAPContext void;
+#endif
+static LDAPContext *ldap_context = 0;
+
 #ifdef HAVE_LDAPSSL_INIT
 static int ssl_initialized = 0;
 #endif
@@ -1190,6 +1195,36 @@
   struct timeval tv;
 #endif
 
+#ifdef HAVE_LDAP_CREATE_CONTEXT
+  /* make sure ldap config is read in a safe and transparent way */
+  if( ! ldap_context )
+    {
+      char *directives[2];
+      int rc;
+
+      if( session->conf->configFile == NULL )
+        {
+          directives[0] = NULL;
+        }
+      else
+        {
+          directives[0] = malloc (strlen (session->conf->configFile) + 6);
+          if( directives[0] == NULL )
+            return PAM_BUF_ERR;
+          strcpy( directives[0], "file=" );
+          strcpy( directives[0]+5, session->conf->configFile );
+        }
+      directives[1] = NULL;
+      rc = ldap_create_context( &ldap_context, directives );
+      _pam_drop( directives[0] );
+      if (rc != LDAP_SUCCESS || ! ldap_context )
+        {
+          syslog (LOG_ERR, "pam_ldap: ldap_create_context: %s", ldap_err2string (rc));
+          return PAM_SERVICE_ERR;
+        }
+    }
+#endif
+
 #ifdef HAVE_LDAP_SET_OPTION
   if (session->conf->debug)
     {
@@ -1253,7 +1288,11 @@
 #ifdef HAVE_LDAP_INITIALIZE
       if (session->conf->uri != NULL)
 	{
+#	ifdef HAVE_LDAP_CREATE_CONTEXT
+	  int rc = ldap_initialize_in_context (&session->ld, session->conf->uri, ldap_context);
+#	else
 	  int rc = ldap_initialize (&session->ld, session->conf->uri);
+#	endif
 	  if (rc != LDAP_SUCCESS)
 	    {
 	      syslog (LOG_ERR, "pam_ldap: ldap_initialize %s",
@@ -1400,8 +1439,12 @@
   /* rand file */
   if (session->conf->tls_randfile != NULL)
     {
-      rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
-			    session->conf->tls_randfile);
+#	ifdef HAVE_LDAP_CREATE_CONTEXT
+      rc = ldap_set_option_in_context ( ldap_context, 
+#	else
+      rc = ldap_set_option (NULL,
+#	endif
+			    LDAP_OPT_X_TLS_RANDOM_FILE, session->conf->tls_randfile);
       if (rc != LDAP_SUCCESS)
 	{
 	  syslog (LOG_ERR,
@@ -1415,7 +1458,12 @@
   /* ca cert file */
   if (session->conf->tls_cacertfile != NULL)
     {
-      rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
+#	ifdef HAVE_LDAP_CREATE_CONTEXT
+      rc = ldap_set_option_in_context ( ldap_context,
+#	else
+      rc = ldap_set_option (NULL,
+#	endif
+			    LDAP_OPT_X_TLS_CACERTFILE,
 			    session->conf->tls_cacertfile);
       if (rc != LDAP_SUCCESS)
 	{
@@ -1429,7 +1477,12 @@
   if (session->conf->tls_cacertdir != NULL)
     {
       /* ca cert directory */
-      rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
+#	ifdef HAVE_LDAP_CREATE_CONTEXT
+      rc = ldap_set_option_in_context ( ldap_context,
+#	else
+      rc = ldap_set_option (NULL,
+#	endif
+			    LDAP_OPT_X_TLS_CACERTDIR,
 			    session->conf->tls_cacertdir);
       if (rc != LDAP_SUCCESS)
 	{
@@ -1443,7 +1496,12 @@
   if (session->conf->tls_checkpeer > -1)
     {
       /* require cert? */
-      rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
+#	ifdef HAVE_LDAP_CREATE_CONTEXT
+      rc = ldap_set_option_in_context ( ldap_context,
+#	else
+      rc = ldap_set_option (NULL,
+#	endif
+		    LDAP_OPT_X_TLS_REQUIRE_CERT,
 			    &session->conf->tls_checkpeer);
       if (rc != LDAP_SUCCESS)
 	{
@@ -1457,7 +1515,12 @@
   if (session->conf->tls_ciphers != NULL)
     {
       /* set cipher suite, certificate and private key: */
-      rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
+#	ifdef HAVE_LDAP_CREATE_CONTEXT
+      rc = ldap_set_option_in_context ( ldap_context,
+#	else
+      rc = ldap_set_option (NULL,
+#	endif
+			    LDAP_OPT_X_TLS_CIPHER_SUITE,
 			    session->conf->tls_ciphers);
       if (rc != LDAP_SUCCESS)
 	{
@@ -1470,7 +1533,12 @@
 
   if (session->conf->tls_cert != NULL)
     {
-      rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE,
+#	ifdef HAVE_LDAP_CREATE_CONTEXT
+      rc = ldap_set_option_in_context ( ldap_context,
+#	else
+      rc = ldap_set_option (NULL,
+#	endif
+			    LDAP_OPT_X_TLS_CERTFILE,
 			    session->conf->tls_cert);
       if (rc != LDAP_SUCCESS)
 	{
@@ -1483,7 +1551,12 @@
 
   if (session->conf->tls_key != NULL)
     {
-      rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE,
+#	ifdef HAVE_LDAP_CREATE_CONTEXT
+      rc = ldap_set_option_in_context ( ldap_context,
+#	else
+      rc = ldap_set_option (NULL,
+#	endif
+			    LDAP_OPT_X_TLS_KEYFILE,
 			    session->conf->tls_key);
       if (rc != LDAP_SUCCESS)
 	{

--pf9I7BMVVzbSWLtt--