From f3a860750b33eff6b240482d52f002d524b0be0e Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Thu, 15 Apr 2010 22:25:47 +0000
Subject: [PATCH] ITS#6456

---
 CHANGES                              |   1 +
 doc/man/man5/slapd-ldap.5            |  18 +++
 servers/slapd/back-ldap/back-ldap.h  |   4 +
 servers/slapd/back-ldap/bind.c       |  59 ++++++---
 servers/slapd/back-ldap/config.c     | 176 +++++++++++++++++++++++++--
 servers/slapd/back-ldap/init.c       |   1 +
 servers/slapd/back-ldap/proto-ldap.h |   1 +
 7 files changed, 229 insertions(+), 31 deletions(-)

diff --git a/CHANGES b/CHANGES
index a297d56cf0..f8a3f4eb72 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,7 @@ OpenLDAP 2.4 Change Log
 OpenLDAP 2.4.22 Engineering
 	Added slapd SLAP_SCHEMA_EXPOSE flag for hidden schema elements (ITS#6435)
 	Added slapd tools selective iterations (ITS#6442)
+	Added slapo-ldap idassert-passthru (ITS#6456)
 	Added slapo-pbind
 	Fixed libldap GnuTLS serial length (ITS#6460)
 	Fixed slapd acl non-entry internal searches (ITS#6481)
diff --git a/doc/man/man5/slapd-ldap.5 b/doc/man/man5/slapd-ldap.5
index d46c72ee25..1168e542da 100644
--- a/doc/man/man5/slapd-ldap.5
+++ b/doc/man/man5/slapd-ldap.5
@@ -382,6 +382,24 @@ and
 .BR idassert\-method .
 .RE
 
+.TP
+.B idassert-passthru <authz-regexp>
+if defined, selects what
+.I local
+identities bypass the identity assertion feature.
+Those identities need to be known by the remote host.
+The string
+.B <authz-regexp>
+follows the rules defined for the
+.I authzFrom
+attribute.
+See 
+.BR slapd.conf (5),
+section related to
+.BR authz\-policy ,
+for details on the syntax of this field.
+
+
 .TP
 .B idle\-timeout <time>
 This directive causes a cached connection to be dropped an recreated
diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h
index 1cd19530f6..21760bfbfe 100644
--- a/servers/slapd/back-ldap/back-ldap.h
+++ b/servers/slapd/back-ldap/back-ldap.h
@@ -238,6 +238,9 @@ typedef struct slap_idassert_t {
 
 	BerVarray	si_authz;
 #define	li_idassert_authz	li_idassert.si_authz
+
+	BerVarray	si_passthru;
+#define	li_idassert_passthru	li_idassert.si_passthru
 } slap_idassert_t;
 
 /*
@@ -448,6 +451,7 @@ typedef struct ldap_extra_t {
 		int version, slap_idassert_t *si, LDAPControl	*ctrl );
 	int (*controls_free)( Operation *op, SlapReply *rs, LDAPControl ***pctrls );
 	int (*idassert_authzfrom_parse_cf)( const char *fname, int lineno, const char *arg, slap_idassert_t *si );
+	int (*idassert_passthru_parse_cf)( const char *fname, int lineno, const char *arg, slap_idassert_t *si );
 	int (*idassert_parse_cf)( const char *fname, int lineno, int argc, char *argv[], slap_idassert_t *si );
 	void (*retry_info_destroy)( slap_retry_info_t *ri );
 	int (*retry_info_parse)( char *in, slap_retry_info_t *ri, char *buf, ber_len_t buflen );
diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c
index 8aabf38ecf..916c0c6820 100644
--- a/servers/slapd/back-ldap/bind.c
+++ b/servers/slapd/back-ldap/bind.c
@@ -2057,32 +2057,51 @@ ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
 
 			goto done;
 
-		} else if ( li->li_idassert_authz && !be_isroot( op ) ) {
-			struct berval authcDN;
+		} else if ( !be_isroot( op ) ) {
+			if ( li->li_idassert_passthru ) {
+				struct berval authcDN;
 
-			if ( BER_BVISNULL( &ndn ) ) {
-				authcDN = slap_empty_bv;
-
-			} else {
-				authcDN = ndn;
-			}	
-			rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz,
-					&authcDN, &authcDN );
-			if ( rs->sr_err != LDAP_SUCCESS ) {
-				if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
-					if ( sendok & LDAP_BACK_SENDERR ) {
-						send_ldap_result( op, rs );
-						dobind = -1;
-					}
+				if ( BER_BVISNULL( &ndn ) ) {
+					authcDN = slap_empty_bv;
 
 				} else {
-					rs->sr_err = LDAP_SUCCESS;
-					*binddn = slap_empty_bv;
-					*bindcred = slap_empty_bv;
+					authcDN = ndn;
+				}	
+				rs->sr_err = slap_sasl_matches( op, li->li_idassert_passthru,
+						&authcDN, &authcDN );
+				if ( rs->sr_err == LDAP_SUCCESS ) {
+					dobind = 0;
 					break;
 				}
+			}
 
-				goto done;
+			if ( li->li_idassert_authz ) {
+				struct berval authcDN;
+
+				if ( BER_BVISNULL( &ndn ) ) {
+					authcDN = slap_empty_bv;
+
+				} else {
+					authcDN = ndn;
+				}	
+				rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz,
+						&authcDN, &authcDN );
+				if ( rs->sr_err != LDAP_SUCCESS ) {
+					if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
+						if ( sendok & LDAP_BACK_SENDERR ) {
+							send_ldap_result( op, rs );
+							dobind = -1;
+						}
+
+					} else {
+						rs->sr_err = LDAP_SUCCESS;
+						*binddn = slap_empty_bv;
+						*bindcred = slap_empty_bv;
+						break;
+					}
+
+					goto done;
+				}
 			}
 		}
 
diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c
index f0b47b81f5..816890bfc3 100644
--- a/servers/slapd/back-ldap/config.c
+++ b/servers/slapd/back-ldap/config.c
@@ -54,6 +54,7 @@ enum {
 	LDAP_BACK_CFG_IDASSERT_AUTHCDN,
 	LDAP_BACK_CFG_IDASSERT_PASSWD,
 	LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
+	LDAP_BACK_CFG_IDASSERT_PASSTHRU,
 	LDAP_BACK_CFG_IDASSERT_METHOD,
 	LDAP_BACK_CFG_IDASSERT_BIND,
 	LDAP_BACK_CFG_REBIND,
@@ -185,6 +186,7 @@ static ConfigTable ldapcfg[] = {
 		ldap_back_cf_gen, "( OLcfgDbAt:3.9 "
 			"NAME 'olcDbIDAssertAuthzFrom' "
 			"DESC 'Remote Identity Assertion authz rules' "
+			"EQUALITY caseIgnoreMatch "
 			"SYNTAX OMsDirectoryString "
 			"X-ORDERED 'VALUES' )",
 		NULL, NULL },
@@ -326,6 +328,16 @@ static ConfigTable ldapcfg[] = {
 			"SYNTAX OMsBoolean "
 			"SINGLE-VALUE )",
 		NULL, NULL },
+	{ "idassert-passThru", "authzRule", 2, 2, 0,
+		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_PASSTHRU,
+		ldap_back_cf_gen, "( OLcfgDbAt:3.27 "
+			"NAME 'olcDbIDAssertPassThru' "
+			"DESC 'Remote Identity Assertion passthru rules' "
+			"EQUALITY caseIgnoreMatch "
+			"SYNTAX OMsDirectoryString "
+			"X-ORDERED 'VALUES' )",
+		NULL, NULL },
+
 	{ "suffixmassage", "[virtual]> <real", 2, 3, 0,
 		ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
 		ldap_back_cf_gen, NULL, NULL, NULL },
@@ -354,6 +366,7 @@ static ConfigOCs ldapocs[] = {
 			"$ olcDbIDAssertBind "
 			"$ olcDbIDAssertMode "
 			"$ olcDbIDAssertAuthzFrom "
+			"$ olcDbIDAssertPassThru "
 			"$ olcDbRebindAsUser "
 			"$ olcDbChaseReferrals "
 			"$ olcDbTFSupport "
@@ -668,8 +681,76 @@ slap_idassert_authzfrom_parse( ConfigArgs *c, slap_idassert_t *si )
  		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
  		return 1;
  	}
+
+	if ( c->valx == -1 ) {
+		ber_bvarray_add( &si->si_authz, &bv );
+
+	} else {
+		int i;
+		for ( i = 0; !BER_BVISNULL( &si->si_authz[ i ] ); i++ )
+			;
+
+		if ( i <= c->valx ) {
+			ber_bvarray_add( &si->si_authz, &bv );
+
+		} else {
+			BerVarray tmp = ber_memrealloc( si->si_authz,
+				sizeof( struct berval )*( i + 2 ) );
+			if ( tmp == NULL ) {
+				return -1;
+			}
+			si->si_authz = tmp;
+			for ( ; i > c->valx; i-- ) {
+				si->si_authz[ i ] = si->si_authz[ i - 1 ];
+			}
+			si->si_authz[ c->valx ] = bv;
+		}
+	}
+
+	return 0;
+}
+
+static int
+slap_idassert_passthru_parse( ConfigArgs *c, slap_idassert_t *si )
+{
+	struct berval	bv;
+	struct berval	in;
+	int		rc;
+
+ 	ber_str2bv( c->argv[ 1 ], 0, 0, &in );
+ 	rc = authzNormalize( 0, NULL, NULL, &in, &bv, NULL );
+ 	if ( rc != LDAP_SUCCESS ) {
+ 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ 			"\"idassert-passThru <authz>\": "
+ 			"invalid syntax" );
+ 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ 		return 1;
+ 	}
   
-	ber_bvarray_add( &si->si_authz, &bv );
+	if ( c->valx == -1 ) {
+		ber_bvarray_add( &si->si_passthru, &bv );
+
+	} else {
+		int i;
+		for ( i = 0; !BER_BVISNULL( &si->si_passthru[ i ] ); i++ )
+			;
+
+		if ( i <= c->valx ) {
+			ber_bvarray_add( &si->si_passthru, &bv );
+
+		} else {
+			BerVarray tmp = ber_memrealloc( si->si_passthru,
+				sizeof( struct berval )*( i + 2 ) );
+			if ( tmp == NULL ) {
+				return -1;
+			}
+			si->si_passthru = tmp;
+			for ( ; i > c->valx; i-- ) {
+				si->si_passthru[ i ] = si->si_passthru[ i - 1 ];
+			}
+			si->si_passthru[ c->valx ] = bv;
+		}
+	}
 
 	return 0;
 }
@@ -835,6 +916,22 @@ slap_idassert_authzfrom_parse_cf( const char *fname, int lineno, const char *arg
 	return slap_idassert_authzfrom_parse( &c, si );
 }
 
+int
+slap_idassert_passthru_parse_cf( const char *fname, int lineno, const char *arg, slap_idassert_t *si )
+{
+	ConfigArgs	c = { 0 };
+	char		*argv[ 3 ];
+
+	snprintf( c.log, sizeof( c.log ), "%s: line %d", fname, lineno );
+	c.argc = 2;
+	c.argv = argv;
+	argv[ 0 ] = "idassert-passThru";
+	argv[ 1 ] = (char *)arg;
+	argv[ 2 ] = NULL;
+
+	return slap_idassert_passthru_parse( &c, si );
+}
+
 int
 slap_idassert_parse_cf( const char *fname, int lineno, int argc, char *argv[], slap_idassert_t *si )
 {
@@ -936,11 +1033,23 @@ ldap_back_cf_gen( ConfigArgs *c )
 			rc = 1;
 			break;
 
-		case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: {
+		case LDAP_BACK_CFG_IDASSERT_AUTHZFROM:
+		case LDAP_BACK_CFG_IDASSERT_PASSTHRU: {
+			BerVarray	*bvp;
 			int		i;
+			struct berval	bv = BER_BVNULL;
+			char		buf[SLAP_TEXT_BUFLEN];
 
-			if ( li->li_idassert_authz == NULL ) {
-				if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) {
+			switch ( c->type ) {
+			case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: bvp = &li->li_idassert_authz; break;
+			case LDAP_BACK_CFG_IDASSERT_PASSTHRU: bvp = &li->li_idassert_passthru; break;
+			default: assert( 0 ); break;
+			}
+
+			if ( *bvp == NULL ) {
+				if ( *bvp == li->li_idassert_authz
+					&& ( li->li_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
+				{
 					BER_BVSTR( &bv, "*" );
 					value_add_one( &c->rvalue_vals, &bv );
 
@@ -950,9 +1059,18 @@ ldap_back_cf_gen( ConfigArgs *c )
 				break;
 			}
 
-			for ( i = 0; !BER_BVISNULL( &li->li_idassert_authz[ i ] ); i++ )
-			{
-				value_add_one( &c->rvalue_vals, &li->li_idassert_authz[ i ] );
+			for ( i = 0; !BER_BVISNULL( &((*bvp)[ i ]) ); i++ ) {
+				char *ptr;
+				int len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i );
+				bv.bv_len = ((*bvp)[ i ]).bv_len + len;
+				bv.bv_val = ber_memrealloc( bv.bv_val, bv.bv_len + 1 );
+				ptr = bv.bv_val;
+				ptr = lutil_strcopy( ptr, buf );
+				ptr = lutil_strncopy( ptr, ((*bvp)[ i ]).bv_val, ((*bvp)[ i ]).bv_len );
+				value_add_one( &c->rvalue_vals, &bv );
+			}
+			if ( bv.bv_val ) {
+				ber_memfree( bv.bv_val );
 			}
 			break;
 		}
@@ -1287,11 +1405,43 @@ ldap_back_cf_gen( ConfigArgs *c )
 			break;
 
 		case LDAP_BACK_CFG_IDASSERT_AUTHZFROM:
-			if ( li->li_idassert_authz != NULL ) {
-				ber_bvarray_free( li->li_idassert_authz );
-				li->li_idassert_authz = NULL;
+		case LDAP_BACK_CFG_IDASSERT_PASSTHRU: {
+			BerVarray *bvp;
+
+			switch ( c->type ) {
+			case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: bvp = &li->li_idassert_authz; break;
+			case LDAP_BACK_CFG_IDASSERT_PASSTHRU: bvp = &li->li_idassert_passthru; break;
+			default: assert( 0 ); break;
 			}
-			break;
+
+			if ( c->valx < 0 ) {
+				if ( *bvp != NULL ) {
+					ber_bvarray_free( *bvp );
+					*bvp = NULL;
+				}
+
+			} else {
+				int i;
+
+				if ( *bvp == NULL ) {
+					rc = 1;
+					break;
+				}
+
+				for ( i = 0; !BER_BVISNULL( &((*bvp)[ i ]) ); i++ )
+					;
+
+				if ( i >= c->valx ) {
+					rc = 1;
+					break;
+				}
+				ber_memfree( ((*bvp)[ c->valx ]).bv_val );
+				for ( i = c->valx; !BER_BVISNULL( &((*bvp)[ i + 1 ]) ); i++ ) {
+					(*bvp)[ i ] = (*bvp)[ i + 1 ];
+				}
+				BER_BVZERO( &((*bvp)[ i ]) );
+			}
+			} break;
 
 		case LDAP_BACK_CFG_IDASSERT_BIND:
 			bindconf_free( &li->li_idassert.si_bc );
@@ -1732,6 +1882,10 @@ done_url:;
 		rc = slap_idassert_authzfrom_parse( c, &li->li_idassert );
 		break;
 
+	case LDAP_BACK_CFG_IDASSERT_PASSTHRU:
+		rc = slap_idassert_passthru_parse( c, &li->li_idassert );
+		break;
+
 	case LDAP_BACK_CFG_IDASSERT_METHOD:
 		/* no longer supported */
 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
diff --git a/servers/slapd/back-ldap/init.c b/servers/slapd/back-ldap/init.c
index 729f611c11..db7033ffb4 100644
--- a/servers/slapd/back-ldap/init.c
+++ b/servers/slapd/back-ldap/init.c
@@ -36,6 +36,7 @@ static const ldap_extra_t ldap_extra = {
 	ldap_back_proxy_authz_ctrl,
 	ldap_back_controls_free,
 	slap_idassert_authzfrom_parse_cf,
+	slap_idassert_passthru_parse_cf,
 	slap_idassert_parse_cf,
 	slap_retry_info_destroy,
 	slap_retry_info_parse,
diff --git a/servers/slapd/back-ldap/proto-ldap.h b/servers/slapd/back-ldap/proto-ldap.h
index 4960cc9288..e4d8520514 100644
--- a/servers/slapd/back-ldap/proto-ldap.h
+++ b/servers/slapd/back-ldap/proto-ldap.h
@@ -102,6 +102,7 @@ extern int slap_retry_info_parse( char *in, slap_retry_info_t *ri,
 extern int slap_retry_info_unparse( slap_retry_info_t *ri, struct berval *bvout );
 
 extern int slap_idassert_authzfrom_parse_cf( const char *fname, int lineno, const char *arg, slap_idassert_t *si );
+extern int slap_idassert_passthru_parse_cf( const char *fname, int lineno, const char *arg, slap_idassert_t *si );
 extern int slap_idassert_parse_cf( const char *fname, int lineno, int argc, char *argv[], slap_idassert_t *si );
 
 extern int chain_initialize( void );
-- 
GitLab