+ char ** attr_str;
+ AttributeDescription * ad;
+ const char * text;
+
+ uri = ch_calloc ( 1, sizeof ( unique_domain_uri ) );
+
+ if ( url_desc->lud_dn && url_desc->lud_dn[0] ) {
+ ber_str2bv( url_desc->lud_dn, 0, 1, &bv );
+ rc = dnPrettyNormal( NULL,
+ &bv,
+ uri->dn,
+ uri->ndn,
+ NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "<%s> invalid DN %d (%s)",
+ url_desc->lud_dn, rc, ldap_err2string( rc ));
+ rc = ARG_BAD_CONF;
+ goto exit;
+ }
+
+ if ( !dnIsSuffix ( uri->ndn, &be->be_nsuffix[0] ) ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "dn <%s> is not a suffix of backend base dn <%s>",
+ uri->dn->bv_val,
+ be->be_nsuffix[0].bv_val );
+ rc = ARG_BAD_CONF;
+ goto exit;
+ }
+ }
+
+ attr_str = url_desc->lud_attrs;
+ if ( attr_str ) {
+ for ( i=0; attr_str[i]; ++i ) {
+ unique_attrs * attr;
+ ad = NULL;
+ if ( slap_str2ad ( attr_str[i], &ad, &text )
+ == LDAP_SUCCESS) {
+ attr = ch_calloc ( 1,
+ sizeof ( unique_attrs ) );
+ attr->attr = ad;
+ attr->next = uri->attrs;
+ uri->attrs = attr;
+ } else {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unique: attribute: %s: %s",
+ attr_str[i], text );
+ rc = ARG_BAD_CONF;
+ goto exit;
+ }
+ }
+ }
+
+ uri->scope = url_desc->lud_scope;
+ if ( !uri->scope ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unique: uri with base scope will always be unique");
+ rc = ARG_BAD_CONF;
+ goto exit;
+ }
+
+ if (url_desc->lud_filter) {
+ Filter * f;
+ uri->filter = ber_str2bv( url_desc->lud_filter, 0, 1, NULL);
+ f = str2filter( uri->filter->bv_val );
+ if ( !f ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "unique: bad filter");
+ rc = ARG_BAD_CONF;
+ goto exit;
+ }
+ filter_free( f );
+ }
+exit:
+ if ( bv.bv_val ) ber_memfree ( bv.bv_val );
+ uri->next = *urip;
+ *urip = uri;
+ if ( rc ) {
+ Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
+ "%s: %s\n", c->log, c->cr_msg, 0 );
+ unique_free_domain_uri ( uri );
+ *urip = NULL;
+ }
+ return rc;
+}
+
+static int
+unique_new_domain_uri_basic ( unique_domain_uri **urip,
+ ConfigArgs *c )
+{
+ LDAPURLDesc *url_desc = NULL;
+ int rc;
+
+ rc = ldap_url_parse ( UNIQUE_DEFAULT_URI, &url_desc );
+ if ( rc ) return rc;
+ rc = unique_new_domain_uri ( urip, url_desc, c );
+ ldap_free_urldesc ( url_desc );
+ return rc;
+}
+
+/* if *domain is non-null, it's pushed down the stack.
+ * note that the entire stack is freed if there is an error,
+ * so build added domains in a separate stack before adding them
+ *
+ * domain_specs look like
+ *
+ * [strict ][ignore ]uri[[ uri]...]
+ * e.g. "ldap:///ou=foo,o=bar?uid?sub ldap:///ou=baz,o=bar?uid?sub"
+ * "strict ldap:///ou=accounts,o=bar?uid,uidNumber?one"
+ * etc
+ *
+ * so finally strictness is per-domain
+ * but so is ignore-state, and that would be better as a per-url thing
+ */
+static int
+unique_new_domain ( unique_domain **domainp,
+ char *domain_spec,
+ ConfigArgs *c )
+{
+ char *uri_start;
+ int rc = LDAP_SUCCESS;
+ int uri_err = 0;
+ unique_domain * domain;
+ LDAPURLDesc *url_desc, *url_descs = NULL;
+
+ Debug(LDAP_DEBUG_TRACE, "==> unique_new_domain <%s>\n",
+ domain_spec, 0, 0);
+
+ domain = ch_calloc ( 1, sizeof (unique_domain) );
+ domain->domain_spec = ber_str2bv( domain_spec, 0, 1, NULL );
+
+ uri_start = domain_spec;
+ if ( strncasecmp ( uri_start, "ignore ",
+ STRLENOF( "ignore " ) ) == 0 ) {
+ domain->ignore = 1;
+ uri_start += STRLENOF( "ignore " );
+ }
+ if ( strncasecmp ( uri_start, "strict ",
+ STRLENOF( "strict " ) ) == 0 ) {
+ domain->strict = 1;
+ uri_start += STRLENOF( "strict " );
+ if ( !domain->ignore
+ && strncasecmp ( uri_start, "ignore ",
+ STRLENOF( "ignore " ) ) == 0 ) {
+ domain->ignore = 1;
+ uri_start += STRLENOF( "ignore " );
+ }
+ }
+ rc = ldap_url_parselist_ext ( &url_descs, uri_start, " ", 0 );
+ if ( rc ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "<%s> invalid ldap urilist",
+ uri_start );
+ rc = ARG_BAD_CONF;
+ goto exit;
+ }
+
+ for ( url_desc = url_descs;
+ url_desc;
+ url_desc = url_descs->lud_next ) {
+ rc = unique_new_domain_uri ( &domain->uri,
+ url_desc,
+ c );
+ if ( rc ) {
+ rc = ARG_BAD_CONF;
+ uri_err = 1;
+ goto exit;
+ }
+ }
+
+exit:
+ if ( url_descs ) ldap_free_urldesc ( url_descs );
+ domain->next = *domainp;
+ *domainp = domain;
+ if ( rc ) {
+ Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
+ "%s: %s\n", c->log, c->cr_msg, 0 );
+ unique_free_domain ( domain );
+ *domainp = NULL;
+ }
+ return rc;
+}
+
+static int
+unique_cf_base( ConfigArgs *c )
+{
+ BackendDB *be = (BackendDB *)c->be;
+ slap_overinst *on = (slap_overinst *)c->bi;
+ unique_data *private = (unique_data *) on->on_bi.bi_private;
+ unique_domain *domains = private->domains;
+ unique_domain *legacy = private->legacy;