database or to other stacked overlays.
.LP
-There are no chain overlay specific directives; however, directives
-related to the \fIslapd-ldap\fP database that is implicitly instantiated
-by the overlay may assume a special meaning when used in conjunction
-with this overlay. They are described in
+There are very few chain overlay specific directives; however, directives
+related to the instances of the \fIldap\fP backend that may be implicitly
+instantiated by the overlay may assume a special meaning when used
+in conjunction with this overlay. They are described in
.BR slapd-ldap (5).
.TP
.B overlay chain
It is useless in conjunction with the \fIslapd-ldap\fP and \fIslapd-meta\fP
backends because they already exploit the libldap specific referral chase
feature.
-[Note: this may change in the future, as \fBslapd-ldap\fP(5) and
-\fBslapd-meta\fP(5) might no longer chase referrals on their own.]
+[Note: this may change in the future, as the \fBldap\fP(5) and
+\fBmeta\fP(5) backends might no longer chase referrals on their own.]
+.\".TP
+.\".B chain-chaining [resolve=<r>] [continuation=<c>] [critical]
+.\"This directive enables the \fIchaining\fP control
+.\"(see \fIdraft-sermersheim-ldap-chaining\fP for details)
+.\"with the desired resolve and continuation behaviors and criticality.
+.\"The values \fBr\fP and \fBc\fP can be any of
+.\".BR chainingPreferred ,
+.\".BR chainingRequired ,
+.\".BR referralsPreferred ,
+.\".BR referralsRequired .
+.\"[This control is experimental and its support may change in the future.]
+.TP
+.B chain-cache-uris {FALSE|true}
+This directive instructs the \fIchain\fP overlay to cache
+connections to URIs parsed out of referrals that are not predefined,
+to be reused for later chaining.
.TP
.B chain-uri <ldapuri>
-This directive instructs the underlying ldap database about which
-URI to contact to chase referrals.
-If not present, the referral itself is parsed, and the protocol/host/port
-portions are used to establish a connection.
+This directive instantiates a new underlying \fIldap\fP database
+and instructs it about which URI to contact to chase referrals.
+As opposed to what stated in \fBslapd-ldap\fP(5), only one URI
+can appear after this directive.
.LP
Directives for configuring the underlying ldap database may also
.BR slapd\-ldap (5),
.BR slapd (8).
.SH AUTHOR
-Originally implemented by Howard Chu.
+Originally implemented by Howard Chu; extended by Pierangelo Masarati.
#define LDAP_BACK_F_SUPPORT_T_F_DISCOVER 0x40U
#define LDAP_BACK_F_SUPPORT_T_F_MASK (LDAP_BACK_F_SUPPORT_T_F|LDAP_BACK_F_SUPPORT_T_F_DISCOVER)
-#define LDAP_BACK_SAVECRED(li) ( (li)->li_flags & LDAP_BACK_F_SAVECRED )
-#define LDAP_BACK_USE_TLS(li) ( (li)->li_flags & LDAP_BACK_F_USE_TLS )
-#define LDAP_BACK_PROPAGATE_TLS(li) ( (li)->li_flags & LDAP_BACK_F_PROPAGATE_TLS )
-#define LDAP_BACK_TLS_CRITICAL(li) ( (li)->li_flags & LDAP_BACK_F_TLS_CRITICAL )
-#define LDAP_BACK_CHASE_REFERRALS(li) ( (li)->li_flags & LDAP_BACK_F_CHASE_REFERRALS )
+#define LDAP_BACK_ISSET(li,f) ( ( (li)->li_flags & (f) ) == (f) )
+#define LDAP_BACK_SAVECRED(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_SAVECRED )
+#define LDAP_BACK_USE_TLS(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_USE_TLS )
+#define LDAP_BACK_PROPAGATE_TLS(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_PROPAGATE_TLS )
+#define LDAP_BACK_TLS_CRITICAL(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_TLS_CRITICAL )
+#define LDAP_BACK_CHASE_REFERRALS(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_CHASE_REFERRALS )
+#define LDAP_BACK_PROXY_WHOAMI(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_PROXY_WHOAMI )
int li_version;
typedef struct ldap_chain_t {
/*
- * TODO: create a template ldapinfo_t that gets all common
- * configuration items; then for each configured URI create
- * an entry in this tree; all the specific configuration
- * items get in the current URI structure.
+ * A "template" ldapinfo_t gets all common configuration items;
+ * then, for each configured URI, an entry is created in the tree;
+ * all the specific configuration items get in the current URI
+ * structure.
*
* Then, for each referral, extract the URI and lookup the
* related structure. If configured to do so, allow URIs
* that chains anonymously; maybe it can also be added to
* the tree? Should be all configurable.
*/
- /* tree of configured[/generated] "uri" info */
- int lc_lai_count;
- ldap_avl_info_t lc_lai;
- /* current configuration info */
- ldapinfo_t *lc_cfg_li;
/* "common" configuration info (all occurring before an "uri") */
ldapinfo_t *lc_common_li;
+ /* current configuration info */
+ ldapinfo_t *lc_cfg_li;
+
+ /* tree of configured[/generated?] "uri" info */
+ ldap_avl_info_t lc_lai;
+
unsigned lc_flags;
#define LDAP_CHAIN_F_NONE (0x00U)
#define LDAP_CHAIN_F_CHAINING (0x01U)
-#define LDAP_CHAIN_F_CACHE_INFO (0x10U)
+#define LDAP_CHAIN_F_CACHE_URI (0x10U)
+
+#define LDAP_CHAIN_CHAINING( lc ) ( ( (lc)->lc_flags & LDAP_CHAIN_F_CHAINING ) == LDAP_CHAIN_F_CHAINING )
+#define LDAP_CHAIN_CACHE_URI( lc ) ( ( (lc)->lc_flags & LDAP_CHAIN_F_CACHE_URI ) == LDAP_CHAIN_F_CACHE_URI )
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
LDAPControl lc_chaining_ctrl;
} ldap_chain_t;
static int ldap_chain_db_init_one( BackendDB *be );
+#define ldap_chain_db_open_one(be) (lback)->bi_db_open( (be) )
+#define ldap_chain_db_close_one(be) (0)
+#define ldap_chain_db_destroy_one(be) (lback)->bi_db_destroy( (be) )
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
static int
*oldctrlsp = op->o_ctrls;
/* default chaining control not defined */
- if ( !( lc->lc_flags & LDAP_CHAIN_F_CHAINING ) ) {
+ if ( !LDAP_CHAIN_CHAINING( lc ) ) {
return 0;
}
lip = (ldapinfo_t *)op->o_bd->be_private;
lip->li_uri = li.li_uri;
lip->li_bvuri = bvuri;
- rc = lback->bi_db_open( op->o_bd );
+ rc = ldap_chain_db_open_one( op->o_bd );
if ( rc != 0 ) {
- (void)lback->bi_db_destroy( op->o_bd );
+ (void)ldap_chain_db_destroy_one( op->o_bd );
goto cleanup;
}
- temporary = 1;
+
+ if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
+ ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
+ if ( avl_insert( &lc->lc_lai.lai_tree,
+ (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
+ {
+ /* someone just inserted another;
+ * don't bother, use this and then
+ * just free it */
+ temporary = 1;
+ }
+ ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
+
+ } else {
+ temporary = 1;
+ }
}
rc = ( *op_f )( op, rs );
if ( temporary ) {
lip->li_uri = NULL;
lip->li_bvuri = NULL;
-#if 0 /* does not exist yet */
- (void)lback->bi_db_close( op->o_bd );
-#endif
- (void)lback->bi_db_destroy( op->o_bd );
+ (void)ldap_chain_db_close_one( op->o_bd );
+ (void)ldap_chain_db_destroy_one( op->o_bd );
}
if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
lip = (ldapinfo_t *)op->o_bd->be_private;
lip->li_uri = li.li_uri;
lip->li_bvuri = bvuri;
- rc = lback->bi_db_open( op->o_bd );
+ rc = ldap_chain_db_open_one( op->o_bd );
if ( rc != 0 ) {
- (void)lback->bi_db_destroy( op->o_bd );
+ (void)ldap_chain_db_destroy_one( op->o_bd );
goto cleanup;
}
- temporary = 1;
+
+ if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
+ ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
+ if ( avl_insert( &lc->lc_lai.lai_tree,
+ (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
+ {
+ /* someone just inserted another;
+ * don't bother, use this and then
+ * just free it */
+ temporary = 1;
+ }
+ ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
+
+ } else {
+ temporary = 1;
+ }
}
/* FIXME: should we also copy filter and scope?
if ( temporary ) {
lip->li_uri = NULL;
lip->li_bvuri = NULL;
-#if 0 /* does not exist yet */
- (void)lback->bi_db_close( op->o_bd );
-#endif
- (void)lback->bi_db_destroy( op->o_bd );
+ (void)ldap_chain_db_close_one( op->o_bd );
+ (void)ldap_chain_db_destroy_one( op->o_bd );
}
if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
*/
enum {
- PC_CHAINING = 1
+ PC_CHAINING = 1,
+ PC_CACHE_URI = 2,
+
+ PC_LAST
};
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
"DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+ { "chain-cache-uris", "TRUE/FALSE",
+ 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|PC_CACHE_URI, chain_cf_gen,
+ "( OLcfgOvAt:3.2 NAME 'olcCacheURIs' "
+ "DESC 'Enables caching of URIs not present in configuration' "
+ "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
};
"NAME 'olcChainConfig' "
"DESC 'Chain configuration' "
"SUP olcOverlayConfig "
- "MAY olcChainingBehavior )", Cft_Overlay, chaincfg, NULL, chain_cfadd },
+ "MAY ( olcChainingBehavior "
+ "$ olcCacheURIs "
+ ") )",
+ Cft_Overlay, chaincfg, NULL, chain_cfadd },
#endif
{ "( OLcfgOvOc:3.2 "
"NAME 'olcChainDatabase' "
"DESC 'Chain remote server configuration' "
- "AUXILIARY )", Cft_Misc, chaincfg, chain_ldadd },
+ "AUXILIARY )",
+ Cft_Misc, chaincfg, chain_ldadd },
{ NULL, 0, NULL }
};
struct berval resolve = BER_BVNULL,
continuation = BER_BVNULL;
- if ( !( lc->lc_flags & LDAP_CHAIN_F_CHAINING ) ) {
+ if ( !LDAP_CHAIN_CHAINING( lc ) ) {
return 1;
}
}
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+ case PC_CACHE_URI:
+ c->value_int = LDAP_CHAIN_CACHE_URI( lc );
+ break;
+
default:
assert( 0 );
rc = 1;
return rc;
} else if ( c->op == LDAP_MOD_DELETE ) {
- return 1; /* FIXME */
-#if 0
switch( c->type ) {
- case PC_ATTR:
- case PC_TEMP:
+ case PC_CHAINING:
+ return 1;
+
+ case PC_CACHE_URI:
+ lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
+ break;
+
+ default:
+ return 1;
}
return rc;
-#endif
}
switch( c->type ) {
}
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+ case PC_CACHE_URI:
+ if ( c->value_int ) {
+ lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
+ } else {
+ lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
+ }
+ break;
+
default:
assert( 0 );
return 1;
db.bd_info = lback;
db.be_private = (void *)lc->lc_cfg_li;
- lback->bi_db_destroy( &db );
+ ldap_chain_db_destroy_one( &db );
lc->lc_cfg_li = NULL;
} else {
{
int rc;
+ assert( PC_LAST <= ARGS_USERLAND );
+
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
/* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
ldap_chain_parse_ctrl, &sc_chainingBehavior );
if ( rc != LDAP_SUCCESS ) {
- fprintf( stderr, "Failed to register chaining behavior control: %d\n", rc );
+ Debug( LDAP_DEBUG_ANY, "slapd-chain: "
+ "unable to register chaining behavior control: %d\n",
+ rc, 0, 0 );
return rc;
}
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
"X-ORDERED 'VALUES' )",
NULL, NULL },
{ "rebind-as-user", "NO|yes", 1, 2, 0,
- ARG_MAGIC|LDAP_BACK_CFG_REBIND,
+ ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_REBIND,
ldap_back_cf_gen, "( OLcfgDbAt:3.10 "
"NAME 'olcDbRebindAsUser' "
"DESC 'Rebind as user' "
- "SYNTAX OMsDirectoryString "
+ "SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
{ "chase-referrals", "YES|no", 2, 2, 0,
- ARG_MAGIC|LDAP_BACK_CFG_CHASE,
+ ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_CHASE,
ldap_back_cf_gen, "( OLcfgDbAt:3.11 "
"NAME 'olcDbChaseReferrals' "
"DESC 'Chase referrals' "
- "SYNTAX OMsDirectoryString "
+ "SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
{ "t-f-support", "NO|yes|discover", 2, 2, 0,
"SINGLE-VALUE )",
NULL, NULL },
{ "proxy-whoami", "NO|yes", 1, 2, 0,
- ARG_MAGIC|LDAP_BACK_CFG_WHOAMI,
+ ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_WHOAMI,
ldap_back_cf_gen, "( OLcfgDbAt:3.13 "
"NAME 'olcDbProxyWhoAmI' "
"DESC 'Proxy whoAmI exop' "
- "SYNTAX OMsDirectoryString "
+ "SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
{ "timeout", "timeout", 0, 2, 0,
{ NULL, 0, NULL }
};
-#define LDAP_BACK_C_NO (0x0U)
-#define LDAP_BACK_C_YES (0x1U)
-static slap_verbmasks yn_mode[] = {
- { BER_BVC( "yes" ), LDAP_BACK_C_YES},
- { BER_BVC( "no" ), LDAP_BACK_C_NO },
- { BER_BVNULL, 0 }
-};
-
static slap_verbmasks idassert_mode[] = {
{ BER_BVC("self"), LDAP_BACK_IDASSERT_SELF },
{ BER_BVC("anonymous"), LDAP_BACK_IDASSERT_ANONYMOUS },
{ BER_BVC( "try-propagate" ), LDAP_BACK_F_PROPAGATE_TLS },
{ BER_BVC( "start" ), LDAP_BACK_F_TLS_USE_MASK },
{ BER_BVC( "try-start" ), LDAP_BACK_F_USE_TLS },
- { BER_BVC( "none" ), LDAP_BACK_C_NO },
+ { BER_BVC( "none" ), LDAP_BACK_F_NONE },
{ BER_BVNULL, 0 }
};
static slap_verbmasks t_f_mode[] = {
{ BER_BVC( "yes" ), LDAP_BACK_F_SUPPORT_T_F },
{ BER_BVC( "discover" ), LDAP_BACK_F_SUPPORT_T_F_DISCOVER },
- { BER_BVC( "no" ), LDAP_BACK_C_NO },
+ { BER_BVC( "no" ), LDAP_BACK_F_NONE },
{ BER_BVNULL, 0 }
};
}
case LDAP_BACK_CFG_REBIND:
- enum_to_verb( yn_mode, ( ( li->li_flags & LDAP_BACK_F_SAVECRED ) == LDAP_BACK_F_SAVECRED ), &bv );
- if ( BER_BVISNULL( &bv ) ) {
- /* there's something wrong... */
- assert( 0 );
- rc = 1;
-
- } else {
- value_add_one( &c->rvalue_vals, &bv );
- }
+ c->value_int = LDAP_BACK_SAVECRED( li );
break;
case LDAP_BACK_CFG_CHASE:
- enum_to_verb( yn_mode, ( ( li->li_flags & LDAP_BACK_F_CHASE_REFERRALS ) == LDAP_BACK_F_CHASE_REFERRALS ), &bv );
- if ( BER_BVISNULL( &bv ) ) {
- /* there's something wrong... */
- assert( 0 );
- rc = 1;
-
- } else {
- value_add_one( &c->rvalue_vals, &bv );
- }
+ c->value_int = LDAP_BACK_CHASE_REFERRALS( li );
break;
case LDAP_BACK_CFG_T_F:
- enum_to_verb( t_f_mode, ( ( li->li_flags & LDAP_BACK_F_SUPPORT_T_F_MASK ) == LDAP_BACK_F_SUPPORT_T_F_MASK ), &bv );
+ enum_to_verb( t_f_mode, (li->li_flags & LDAP_BACK_F_SUPPORT_T_F_MASK), &bv );
if ( BER_BVISNULL( &bv ) ) {
/* there's something wrong... */
assert( 0 );
break;
case LDAP_BACK_CFG_WHOAMI:
- enum_to_verb( yn_mode, ( ( li->li_flags & LDAP_BACK_F_PROXY_WHOAMI ) == LDAP_BACK_F_PROXY_WHOAMI ), &bv );
- if ( BER_BVISNULL( &bv ) ) {
- /* there's something wrong... */
- assert( 0 );
- rc = 1;
-
- } else {
- value_add_one( &c->rvalue_vals, &bv );
- }
+ c->value_int = LDAP_BACK_PROXY_WHOAMI( li );
break;
case LDAP_BACK_CFG_TIMEOUT:
i++, tmpludp = tmpludp->lud_next )
{
LDAPURLDesc tmplud;
- ber_len_t oldlen = 0, len;
tmplud = *tmpludp;
tmplud.lud_dn = "";
}
break;
- case LDAP_BACK_CFG_REBIND: {
- int dorebind = 0;
-
- if ( c->argc == 1 ) {
- /* legacy */
- dorebind = 1;
-
- } else {
- i = verb_to_mask( c->argv[1], yn_mode );
- if ( BER_BVISNULL( &yn_mode[i].word ) ) {
- return 1;
- }
- if ( yn_mode[i].mask & LDAP_BACK_C_YES ) {
- dorebind = 1;
- }
- }
-
- if ( dorebind ) {
+ case LDAP_BACK_CFG_REBIND:
+ if ( c->argc == 1 || c->value_int ) {
li->li_flags |= LDAP_BACK_F_SAVECRED;
} else {
li->li_flags &= ~LDAP_BACK_F_SAVECRED;
}
- } break;
-
- case LDAP_BACK_CFG_CHASE: {
- int dochase = 0;
-
- if ( c->argc == 1 ) {
- /* legacy */
- dochase = 1;
-
- } else {
- i = verb_to_mask( c->argv[1], yn_mode );
- if ( BER_BVISNULL( &yn_mode[i].word ) ) {
- return 1;
- }
- if ( yn_mode[i].mask & LDAP_BACK_C_YES ) {
- dochase = 1;
- }
- }
+ break;
- if ( dochase ) {
+ case LDAP_BACK_CFG_CHASE:
+ if ( c->argc == 1 || c->value_int ) {
li->li_flags |= LDAP_BACK_F_CHASE_REFERRALS;
} else {
li->li_flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
}
- } break;
+ break;
case LDAP_BACK_CFG_T_F:
i = verb_to_mask( c->argv[1], t_f_mode );
li->li_flags |= t_f_mode[i].mask;
break;
- case LDAP_BACK_CFG_WHOAMI: {
- int dowhoami = 0;
-
- if ( c->argc == 1 ) {
- /* legacy */
- dowhoami = 1;
-
- } else {
- i = verb_to_mask( c->argv[1], yn_mode );
- if ( BER_BVISNULL( &yn_mode[i].word ) ) {
- return 1;
- }
- if ( yn_mode[i].mask & LDAP_BACK_C_YES ) {
- dowhoami = 1;
- }
- }
-
- if ( dowhoami ) {
+ case LDAP_BACK_CFG_WHOAMI:
+ if ( c->argc == 1 || c->value_int ) {
li->li_flags |= LDAP_BACK_F_PROXY_WHOAMI;
-
load_extop( (struct berval *)&slap_EXOP_WHOAMI,
0, ldap_back_exop_whoami );
} else {
li->li_flags &= ~LDAP_BACK_F_PROXY_WHOAMI;
}
- } break;
+ break;
case LDAP_BACK_CFG_TIMEOUT:
if ( c->argc < 2 ) {
if(c->argc == 1) {
iarg = 1;
} else if(!strcasecmp(c->argv[1], "on") ||
- !strcasecmp(c->argv[1], "true")) {
+ !strcasecmp(c->argv[1], "true") ||
+ !strcasecmp(c->argv[1], "yes"))
+ {
iarg = 1;
} else if(!strcasecmp(c->argv[1], "off") ||
- !strcasecmp(c->argv[1], "false")) {
+ !strcasecmp(c->argv[1], "false") ||
+ !strcasecmp(c->argv[1], "no"))
+ {
iarg = 0;
} else {
snprintf( c->msg, sizeof( c->msg ), "<%s> invalid value, ignored",