Home | History | Annotate | Line # | Download | only in overlays
unique.c revision 1.1.1.3
      1 /*	$NetBSD: unique.c,v 1.1.1.3 2010/03/08 02:14:20 lukem Exp $	*/
      2 
      3 /* unique.c - attribute uniqueness module */
      4 /* OpenLDAP: pkg/ldap/servers/slapd/overlays/unique.c,v 1.20.2.17 2009/12/02 16:52:10 quanah Exp */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 2004-2009 The OpenLDAP Foundation.
      8  * Portions Copyright 2004,2006-2007 Symas Corporation.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted only as authorized by the OpenLDAP
     13  * Public License.
     14  *
     15  * A copy of this license is available in the file LICENSE in the
     16  * top-level directory of the distribution or, alternatively, at
     17  * <http://www.OpenLDAP.org/license.html>.
     18  */
     19 /* ACKNOWLEDGEMENTS:
     20  * This work was initially developed by Symas Corporation for
     21  * inclusion in OpenLDAP Software, with subsequent enhancements by
     22  * Matthew Backes at Symas Corporation.  This work was sponsored by
     23  * Hewlett-Packard.
     24  */
     25 
     26 #include "portable.h"
     27 
     28 #ifdef SLAPD_OVER_UNIQUE
     29 
     30 #include <stdio.h>
     31 
     32 #include <ac/string.h>
     33 #include <ac/socket.h>
     34 
     35 #include "slap.h"
     36 #include "config.h"
     37 
     38 #define UNIQUE_DEFAULT_URI ("ldap:///??sub")
     39 
     40 static slap_overinst unique;
     41 
     42 typedef struct unique_attrs_s {
     43 	struct unique_attrs_s *next;	      /* list of attrs */
     44 	AttributeDescription *attr;
     45 } unique_attrs;
     46 
     47 typedef struct unique_domain_uri_s {
     48 	struct unique_domain_uri_s *next;
     49 	struct berval dn;
     50 	struct berval ndn;
     51 	struct berval filter;
     52 	Filter *f;
     53 	struct unique_attrs_s *attrs;
     54 	int scope;
     55 } unique_domain_uri;
     56 
     57 typedef struct unique_domain_s {
     58 	struct unique_domain_s *next;
     59 	struct berval domain_spec;
     60 	struct unique_domain_uri_s *uri;
     61 	char ignore;                          /* polarity of attributes */
     62 	char strict;                          /* null considered unique too */
     63 } unique_domain;
     64 
     65 typedef struct unique_data_s {
     66 	struct unique_domain_s *domains;
     67 	struct unique_domain_s *legacy;
     68 	char legacy_strict_set;
     69 } unique_data;
     70 
     71 typedef struct unique_counter_s {
     72 	struct berval *ndn;
     73 	int count;
     74 } unique_counter;
     75 
     76 enum {
     77 	UNIQUE_BASE = 1,
     78 	UNIQUE_IGNORE,
     79 	UNIQUE_ATTR,
     80 	UNIQUE_STRICT,
     81 	UNIQUE_URI
     82 };
     83 
     84 static ConfigDriver unique_cf_base;
     85 static ConfigDriver unique_cf_attrs;
     86 static ConfigDriver unique_cf_strict;
     87 static ConfigDriver unique_cf_uri;
     88 
     89 static ConfigTable uniquecfg[] = {
     90 	{ "unique_base", "basedn", 2, 2, 0, ARG_DN|ARG_MAGIC|UNIQUE_BASE,
     91 	  unique_cf_base, "( OLcfgOvAt:10.1 NAME 'olcUniqueBase' "
     92 	  "DESC 'Subtree for uniqueness searches' "
     93 	  "EQUALITY distinguishedNameMatch "
     94 	  "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
     95 	{ "unique_ignore", "attribute...", 2, 0, 0, ARG_MAGIC|UNIQUE_IGNORE,
     96 	  unique_cf_attrs, "( OLcfgOvAt:10.2 NAME 'olcUniqueIgnore' "
     97 	  "DESC 'Attributes for which uniqueness shall not be enforced' "
     98 	  "EQUALITY caseIgnoreMatch "
     99 	  "ORDERING caseIgnoreOrderingMatch "
    100 	  "SUBSTR caseIgnoreSubstringsMatch "
    101 	  "SYNTAX OMsDirectoryString )", NULL, NULL },
    102 	{ "unique_attributes", "attribute...", 2, 0, 0, ARG_MAGIC|UNIQUE_ATTR,
    103 	  unique_cf_attrs, "( OLcfgOvAt:10.3 NAME 'olcUniqueAttribute' "
    104 	  "DESC 'Attributes for which uniqueness shall be enforced' "
    105 	  "EQUALITY caseIgnoreMatch "
    106 	  "ORDERING caseIgnoreOrderingMatch "
    107 	  "SUBSTR caseIgnoreSubstringsMatch "
    108 	  "SYNTAX OMsDirectoryString )", NULL, NULL },
    109 	{ "unique_strict", "on|off", 1, 2, 0, ARG_MAGIC|UNIQUE_STRICT,
    110 	  unique_cf_strict, "( OLcfgOvAt:10.4 NAME 'olcUniqueStrict' "
    111 	  "DESC 'Enforce uniqueness of null values' "
    112 	  "EQUALITY booleanMatch "
    113 	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
    114 	{ "unique_uri", "ldapuri", 2, 3, 0, ARG_MAGIC|UNIQUE_URI,
    115 	  unique_cf_uri, "( OLcfgOvAt:10.5 NAME 'olcUniqueURI' "
    116 	  "DESC 'List of keywords and LDAP URIs for a uniqueness domain' "
    117 	  "EQUALITY caseExactMatch "
    118 	  "ORDERING caseExactOrderingMatch "
    119 	  "SUBSTR caseExactSubstringsMatch "
    120 	  "SYNTAX OMsDirectoryString )", NULL, NULL },
    121 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
    122 };
    123 
    124 static ConfigOCs uniqueocs[] = {
    125 	{ "( OLcfgOvOc:10.1 "
    126 	  "NAME 'olcUniqueConfig' "
    127 	  "DESC 'Attribute value uniqueness configuration' "
    128 	  "SUP olcOverlayConfig "
    129 	  "MAY ( olcUniqueBase $ olcUniqueIgnore $ "
    130 	  "olcUniqueAttribute $ olcUniqueStrict $ "
    131 	  "olcUniqueURI ) )",
    132 	  Cft_Overlay, uniquecfg },
    133 	{ NULL, 0, NULL }
    134 };
    135 
    136 static void
    137 unique_free_domain_uri ( unique_domain_uri *uri )
    138 {
    139 	unique_domain_uri *next_uri = NULL;
    140 	unique_attrs *attr, *next_attr = NULL;
    141 
    142 	while ( uri ) {
    143 		next_uri = uri->next;
    144 		ch_free ( uri->dn.bv_val );
    145 		ch_free ( uri->ndn.bv_val );
    146 		ch_free ( uri->filter.bv_val );
    147 		filter_free( uri->f );
    148 		attr = uri->attrs;
    149 		while ( attr ) {
    150 			next_attr = attr->next;
    151 			ch_free (attr);
    152 			attr = next_attr;
    153 		}
    154 		ch_free ( uri );
    155 		uri = next_uri;
    156 	}
    157 }
    158 
    159 /* free an entire stack of domains */
    160 static void
    161 unique_free_domain ( unique_domain *domain )
    162 {
    163 	unique_domain *next_domain = NULL;
    164 
    165 	while ( domain ) {
    166 		next_domain = domain->next;
    167 		ch_free ( domain->domain_spec.bv_val );
    168 		unique_free_domain_uri ( domain->uri );
    169 		ch_free ( domain );
    170 		domain = next_domain;
    171 	}
    172 }
    173 
    174 static int
    175 unique_new_domain_uri ( unique_domain_uri **urip,
    176 			const LDAPURLDesc *url_desc,
    177 			ConfigArgs *c )
    178 {
    179 	int i, rc = LDAP_SUCCESS;
    180 	unique_domain_uri *uri;
    181 	struct berval bv = {0, NULL};
    182 	BackendDB *be = (BackendDB *)c->be;
    183 	char ** attr_str;
    184 	AttributeDescription * ad;
    185 	const char * text;
    186 
    187 	uri = ch_calloc ( 1, sizeof ( unique_domain_uri ) );
    188 
    189 	if ( url_desc->lud_dn && url_desc->lud_dn[0] ) {
    190 		ber_str2bv( url_desc->lud_dn, 0, 0, &bv );
    191 		rc = dnPrettyNormal( NULL,
    192 				     &bv,
    193 				     &uri->dn,
    194 				     &uri->ndn,
    195 				     NULL );
    196 		if ( rc != LDAP_SUCCESS ) {
    197 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    198 				  "<%s> invalid DN %d (%s)",
    199 				  url_desc->lud_dn, rc, ldap_err2string( rc ));
    200 			rc = ARG_BAD_CONF;
    201 			goto exit;
    202 		}
    203 
    204 		if ( be->be_nsuffix == NULL ) {
    205 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    206 				  "suffix must be set" );
    207 			Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
    208 				c->cr_msg, NULL, NULL );
    209 			rc = ARG_BAD_CONF;
    210 			goto exit;
    211 		}
    212 
    213 		if ( !dnIsSuffix ( &uri->ndn, &be->be_nsuffix[0] ) ) {
    214 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    215 				  "dn <%s> is not a suffix of backend base dn <%s>",
    216 				  uri->dn.bv_val,
    217 				  be->be_nsuffix[0].bv_val );
    218 			rc = ARG_BAD_CONF;
    219 			goto exit;
    220 		}
    221 
    222 		if ( BER_BVISNULL( &be->be_rootndn ) || BER_BVISEMPTY( &be->be_rootndn ) ) {
    223 			Debug( LDAP_DEBUG_ANY,
    224 				"slapo-unique needs a rootdn; "
    225 				"backend <%s> has none, YMMV.\n",
    226 				be->be_nsuffix[0].bv_val, 0, 0 );
    227 		}
    228 	}
    229 
    230 	attr_str = url_desc->lud_attrs;
    231 	if ( attr_str ) {
    232 		for ( i=0; attr_str[i]; ++i ) {
    233 			unique_attrs * attr;
    234 			ad = NULL;
    235 			if ( slap_str2ad ( attr_str[i], &ad, &text )
    236 			     == LDAP_SUCCESS) {
    237 				attr = ch_calloc ( 1,
    238 						   sizeof ( unique_attrs ) );
    239 				attr->attr = ad;
    240 				attr->next = uri->attrs;
    241 				uri->attrs = attr;
    242 			} else {
    243 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
    244 					  "unique: attribute: %s: %s",
    245 					  attr_str[i], text );
    246 				rc = ARG_BAD_CONF;
    247 				goto exit;
    248 			}
    249 		}
    250 	}
    251 
    252 	uri->scope = url_desc->lud_scope;
    253 	if ( !uri->scope ) {
    254 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
    255 			  "unique: uri with base scope will always be unique");
    256 		rc = ARG_BAD_CONF;
    257 		goto exit;
    258 	}
    259 
    260 	if (url_desc->lud_filter) {
    261 		char *ptr;
    262 		uri->f = str2filter( url_desc->lud_filter );
    263 		if ( !uri->f ) {
    264 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    265 				  "unique: bad filter");
    266 			rc = ARG_BAD_CONF;
    267 			goto exit;
    268 		}
    269 		/* make sure the strfilter is in normal form (ITS#5581) */
    270 		filter2bv( uri->f, &uri->filter );
    271 		ptr = strstr( uri->filter.bv_val, "(?=" /*)*/ );
    272 		if ( ptr != NULL && ptr <= ( uri->filter.bv_val - STRLENOF( "(?=" /*)*/ ) + uri->filter.bv_len ) )
    273 		{
    274 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    275 				  "unique: bad filter");
    276 			rc = ARG_BAD_CONF;
    277 			goto exit;
    278 		}
    279 	}
    280 exit:
    281 	uri->next = *urip;
    282 	*urip = uri;
    283 	if ( rc ) {
    284 		Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
    285 			"%s: %s\n", c->log, c->cr_msg, 0 );
    286 		unique_free_domain_uri ( uri );
    287 		*urip = NULL;
    288 	}
    289 	return rc;
    290 }
    291 
    292 static int
    293 unique_new_domain_uri_basic ( unique_domain_uri **urip,
    294 			      ConfigArgs *c )
    295 {
    296 	LDAPURLDesc *url_desc = NULL;
    297 	int rc;
    298 
    299 	rc = ldap_url_parse ( UNIQUE_DEFAULT_URI, &url_desc );
    300 	if ( rc ) return rc;
    301 	rc = unique_new_domain_uri ( urip, url_desc, c );
    302 	ldap_free_urldesc ( url_desc );
    303 	return rc;
    304 }
    305 
    306 /* if *domain is non-null, it's pushed down the stack.
    307  * note that the entire stack is freed if there is an error,
    308  * so build added domains in a separate stack before adding them
    309  *
    310  * domain_specs look like
    311  *
    312  * [strict ][ignore ]uri[[ uri]...]
    313  * e.g. "ldap:///ou=foo,o=bar?uid?sub ldap:///ou=baz,o=bar?uid?sub"
    314  *      "strict ldap:///ou=accounts,o=bar?uid,uidNumber?one"
    315  *      etc
    316  *
    317  * so finally strictness is per-domain
    318  * but so is ignore-state, and that would be better as a per-url thing
    319  */
    320 static int
    321 unique_new_domain ( unique_domain **domainp,
    322 		    char *domain_spec,
    323 		    ConfigArgs *c )
    324 {
    325 	char *uri_start;
    326 	int rc = LDAP_SUCCESS;
    327 	int uri_err = 0;
    328 	unique_domain * domain;
    329 	LDAPURLDesc *url_desc, *url_descs = NULL;
    330 
    331 	Debug(LDAP_DEBUG_TRACE, "==> unique_new_domain <%s>\n",
    332 	      domain_spec, 0, 0);
    333 
    334 	domain = ch_calloc ( 1, sizeof (unique_domain) );
    335 	ber_str2bv( domain_spec, 0, 1, &domain->domain_spec );
    336 
    337 	uri_start = domain_spec;
    338 	if ( strncasecmp ( uri_start, "ignore ",
    339 			   STRLENOF( "ignore " ) ) == 0 ) {
    340 		domain->ignore = 1;
    341 		uri_start += STRLENOF( "ignore " );
    342 	}
    343 	if ( strncasecmp ( uri_start, "strict ",
    344 			   STRLENOF( "strict " ) ) == 0 ) {
    345 		domain->strict = 1;
    346 		uri_start += STRLENOF( "strict " );
    347 		if ( !domain->ignore
    348 		     && strncasecmp ( uri_start, "ignore ",
    349 				      STRLENOF( "ignore " ) ) == 0 ) {
    350 			domain->ignore = 1;
    351 			uri_start += STRLENOF( "ignore " );
    352 		}
    353 	}
    354 	rc = ldap_url_parselist_ext ( &url_descs, uri_start, " ", 0 );
    355 	if ( rc ) {
    356 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
    357 			  "<%s> invalid ldap urilist",
    358 			  uri_start );
    359 		rc = ARG_BAD_CONF;
    360 		goto exit;
    361 	}
    362 
    363 	for ( url_desc = url_descs;
    364 	      url_desc;
    365 	      url_desc = url_descs->lud_next ) {
    366 		rc = unique_new_domain_uri ( &domain->uri,
    367 					     url_desc,
    368 					     c );
    369 		if ( rc ) {
    370 			rc = ARG_BAD_CONF;
    371 			uri_err = 1;
    372 			goto exit;
    373 		}
    374 	}
    375 
    376 exit:
    377 	if ( url_descs ) ldap_free_urldesc ( url_descs );
    378 	domain->next = *domainp;
    379 	*domainp = domain;
    380 	if ( rc ) {
    381 		Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
    382 			"%s: %s\n", c->log, c->cr_msg, 0 );
    383 		unique_free_domain ( domain );
    384 		*domainp = NULL;
    385 	}
    386 	return rc;
    387 }
    388 
    389 static int
    390 unique_cf_base( ConfigArgs *c )
    391 {
    392 	BackendDB *be = (BackendDB *)c->be;
    393 	slap_overinst *on = (slap_overinst *)c->bi;
    394 	unique_data *private = (unique_data *) on->on_bi.bi_private;
    395 	unique_domain *domains = private->domains;
    396 	unique_domain *legacy = private->legacy;
    397 	int rc = ARG_BAD_CONF;
    398 
    399 	switch ( c->op ) {
    400 	case SLAP_CONFIG_EMIT:
    401 		rc = 0;
    402 		if ( legacy && legacy->uri && legacy->uri->dn.bv_val ) {
    403 			rc = value_add_one ( &c->rvalue_vals,
    404 					     &legacy->uri->dn );
    405 			if ( rc ) return rc;
    406 			rc = value_add_one ( &c->rvalue_nvals,
    407 					     &legacy->uri->ndn );
    408 			if ( rc ) return rc;
    409 		}
    410 		break;
    411 	case LDAP_MOD_DELETE:
    412 		assert ( legacy && legacy->uri && legacy->uri->dn.bv_val );
    413 		rc = 0;
    414 		ch_free ( legacy->uri->dn.bv_val );
    415 		ch_free ( legacy->uri->ndn.bv_val );
    416 		BER_BVZERO( &legacy->uri->dn );
    417 		BER_BVZERO( &legacy->uri->ndn );
    418 		if ( !legacy->uri->attrs ) {
    419 			unique_free_domain_uri ( legacy->uri );
    420 			legacy->uri = NULL;
    421 		}
    422 		if ( !legacy->uri && !private->legacy_strict_set ) {
    423 			unique_free_domain ( legacy );
    424 			private->legacy = legacy = NULL;
    425 		}
    426 		break;
    427 	case LDAP_MOD_ADD:
    428 	case SLAP_CONFIG_ADD:
    429 		if ( domains ) {
    430 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    431 				  "cannot set legacy attrs when URIs are present" );
    432 			Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
    433 				c->cr_msg, NULL, NULL );
    434 			rc = ARG_BAD_CONF;
    435 			break;
    436 		}
    437 		if ( be->be_nsuffix == NULL ) {
    438 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    439 				  "suffix must be set" );
    440 			Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
    441 				c->cr_msg, NULL, NULL );
    442 			rc = ARG_BAD_CONF;
    443 			break;
    444 		}
    445 		if ( !dnIsSuffix ( &c->value_ndn,
    446 				   &be->be_nsuffix[0] ) ) {
    447 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    448 				  "dn is not a suffix of backend base" );
    449 			Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
    450 				c->cr_msg, NULL, NULL );
    451 			rc = ARG_BAD_CONF;
    452 			break;
    453 		}
    454 		if ( !legacy ) {
    455 			unique_new_domain ( &private->legacy,
    456 					    UNIQUE_DEFAULT_URI,
    457 					    c );
    458 			legacy = private->legacy;
    459 		}
    460 		if ( !legacy->uri )
    461 			unique_new_domain_uri_basic ( &legacy->uri, c );
    462 		ch_free ( legacy->uri->dn.bv_val );
    463 		ch_free ( legacy->uri->ndn.bv_val );
    464 		legacy->uri->dn = c->value_dn;
    465 		legacy->uri->ndn = c->value_ndn;
    466 		rc = 0;
    467 		break;
    468 	default:
    469 		abort();
    470 	}
    471 
    472 	if ( rc ) {
    473 		ch_free( c->value_dn.bv_val );
    474 		BER_BVZERO( &c->value_dn );
    475 		ch_free( c->value_ndn.bv_val );
    476 		BER_BVZERO( &c->value_ndn );
    477 	}
    478 
    479 	return rc;
    480 }
    481 
    482 static int
    483 unique_cf_attrs( ConfigArgs *c )
    484 {
    485 	slap_overinst *on = (slap_overinst *)c->bi;
    486 	unique_data *private = (unique_data *) on->on_bi.bi_private;
    487 	unique_domain *domains = private->domains;
    488 	unique_domain *legacy = private->legacy;
    489 	unique_attrs *new_attrs = NULL;
    490 	unique_attrs *attr, *next_attr, *reverse_attrs;
    491 	unique_attrs **attrp;
    492 	int rc = ARG_BAD_CONF;
    493 	int i;
    494 
    495 	switch ( c->op ) {
    496 	case SLAP_CONFIG_EMIT:
    497 		if ( legacy
    498 		     && (c->type == UNIQUE_IGNORE) == legacy->ignore
    499 		     && legacy->uri )
    500 			for ( attr = legacy->uri->attrs;
    501 			      attr;
    502 			      attr = attr->next )
    503 				value_add_one( &c->rvalue_vals,
    504 					       &attr->attr->ad_cname );
    505 		rc = 0;
    506 		break;
    507 	case LDAP_MOD_DELETE:
    508 		if ( legacy
    509 		     && (c->type == UNIQUE_IGNORE) == legacy->ignore
    510 		     && legacy->uri
    511 		     && legacy->uri->attrs) {
    512 			if ( c->valx < 0 ) { /* delete all */
    513 				for ( attr = legacy->uri->attrs;
    514 				      attr;
    515 				      attr = next_attr ) {
    516 					next_attr = attr->next;
    517 					ch_free ( attr );
    518 				}
    519 				legacy->uri->attrs = NULL;
    520 			} else { /* delete by index */
    521 				attrp = &legacy->uri->attrs;
    522 				for ( i=0; i < c->valx; ++i )
    523 					attrp = &(*attrp)->next;
    524 				attr = *attrp;
    525 				*attrp = attr->next;
    526 				ch_free (attr);
    527 			}
    528 			if ( !legacy->uri->attrs
    529 			     && !legacy->uri->dn.bv_val ) {
    530 				unique_free_domain_uri ( legacy->uri );
    531 				legacy->uri = NULL;
    532 			}
    533 			if ( !legacy->uri && !private->legacy_strict_set ) {
    534 				unique_free_domain ( legacy );
    535 				private->legacy = legacy = NULL;
    536 			}
    537 		}
    538 		rc = 0;
    539 		break;
    540 	case LDAP_MOD_ADD:
    541 	case SLAP_CONFIG_ADD:
    542 		if ( domains ) {
    543 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    544 				  "cannot set legacy attrs when URIs are present" );
    545 			Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
    546 				c->cr_msg, NULL, NULL );
    547 			rc = ARG_BAD_CONF;
    548 			break;
    549 		}
    550 		if ( legacy
    551 		     && legacy->uri
    552 		     && legacy->uri->attrs
    553 		     && (c->type == UNIQUE_IGNORE) != legacy->ignore ) {
    554 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    555 				  "cannot set both attrs and ignore-attrs" );
    556 			Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
    557 				c->cr_msg, NULL, NULL );
    558 			rc = ARG_BAD_CONF;
    559 			break;
    560 		}
    561 		if ( !legacy ) {
    562 			unique_new_domain ( &private->legacy,
    563 					    UNIQUE_DEFAULT_URI,
    564 					    c );
    565 			legacy = private->legacy;
    566 		}
    567 		if ( !legacy->uri )
    568 			unique_new_domain_uri_basic ( &legacy->uri, c );
    569 		rc = 0;
    570 		for ( i=1; c->argv[i]; ++i ) {
    571 			AttributeDescription * ad = NULL;
    572 			const char * text;
    573 			if ( slap_str2ad ( c->argv[i], &ad, &text )
    574 			     == LDAP_SUCCESS) {
    575 
    576 				attr = ch_calloc ( 1,
    577 					sizeof ( unique_attrs ) );
    578 				attr->attr = ad;
    579 				attr->next = new_attrs;
    580 				new_attrs = attr;
    581 			} else {
    582 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
    583 					  "unique: attribute: %s: %s",
    584 					  c->argv[i], text );
    585 				for ( attr = new_attrs;
    586 				      attr;
    587 				      attr=next_attr ) {
    588 					next_attr = attr->next;
    589 					ch_free ( attr );
    590 				}
    591 				rc = ARG_BAD_CONF;
    592 				break;
    593 			}
    594 		}
    595 		if ( rc ) break;
    596 
    597 		/* (nconc legacy->uri->attrs (nreverse new_attrs)) */
    598 		reverse_attrs = NULL;
    599 		for ( attr = new_attrs;
    600 		      attr;
    601 		      attr = next_attr ) {
    602 			next_attr = attr->next;
    603 			attr->next = reverse_attrs;
    604 			reverse_attrs = attr;
    605 		}
    606 		for ( attrp = &legacy->uri->attrs;
    607 		      *attrp;
    608 		      attrp = &(*attrp)->next ) ;
    609 		*attrp = reverse_attrs;
    610 
    611 		legacy->ignore = ( c->type == UNIQUE_IGNORE );
    612 		break;
    613 	default:
    614 		abort();
    615 	}
    616 
    617 	if ( rc ) {
    618 		Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
    619 			"%s: %s\n", c->log, c->cr_msg, 0 );
    620 	}
    621 	return rc;
    622 }
    623 
    624 static int
    625 unique_cf_strict( ConfigArgs *c )
    626 {
    627 	slap_overinst *on = (slap_overinst *)c->bi;
    628 	unique_data *private = (unique_data *) on->on_bi.bi_private;
    629 	unique_domain *domains = private->domains;
    630 	unique_domain *legacy = private->legacy;
    631 	int rc = ARG_BAD_CONF;
    632 
    633 	switch ( c->op ) {
    634 	case SLAP_CONFIG_EMIT:
    635 		/* We process the boolean manually instead of using
    636 		 * ARG_ON_OFF so that we can three-state it;
    637 		 * olcUniqueStrict is either TRUE, FALSE, or missing,
    638 		 * and missing is necessary to add olcUniqueURIs...
    639 		 */
    640 		if ( private->legacy_strict_set ) {
    641 			struct berval bv;
    642 			bv.bv_val = legacy->strict ? "TRUE" : "FALSE";
    643 			bv.bv_len = legacy->strict ?
    644 				STRLENOF("TRUE") :
    645 				STRLENOF("FALSE");
    646 			value_add_one ( &c->rvalue_vals, &bv );
    647 		}
    648 		rc = 0;
    649 		break;
    650 	case LDAP_MOD_DELETE:
    651 		if ( legacy ) {
    652 			legacy->strict = 0;
    653 			if ( ! legacy->uri ) {
    654 				unique_free_domain ( legacy );
    655 				private->legacy = NULL;
    656 			}
    657 		}
    658 		private->legacy_strict_set = 0;
    659 		rc = 0;
    660 		break;
    661 	case LDAP_MOD_ADD:
    662 	case SLAP_CONFIG_ADD:
    663 		if ( domains ) {
    664 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    665 				  "cannot set legacy attrs when URIs are present" );
    666 			Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
    667 				c->cr_msg, NULL, NULL );
    668 			rc = ARG_BAD_CONF;
    669 			break;
    670 		}
    671 		if ( ! legacy ) {
    672 			unique_new_domain ( &private->legacy,
    673 					    UNIQUE_DEFAULT_URI,
    674 					    c );
    675 			legacy = private->legacy;
    676 		}
    677 		/* ... not using ARG_ON_OFF makes this necessary too */
    678 		assert ( c->argc == 2 );
    679 		legacy->strict = (strcasecmp ( c->argv[1], "TRUE" ) == 0);
    680 		private->legacy_strict_set = 1;
    681 		rc = 0;
    682 		break;
    683 	default:
    684 		abort();
    685 	}
    686 
    687 	return rc;
    688 }
    689 
    690 static int
    691 unique_cf_uri( ConfigArgs *c )
    692 {
    693 	slap_overinst *on = (slap_overinst *)c->bi;
    694 	unique_data *private = (unique_data *) on->on_bi.bi_private;
    695 	unique_domain *domains = private->domains;
    696 	unique_domain *legacy = private->legacy;
    697 	unique_domain *domain = NULL, **domainp = NULL;
    698 	int rc = ARG_BAD_CONF;
    699 	int i;
    700 
    701 	switch ( c->op ) {
    702 	case SLAP_CONFIG_EMIT:
    703 		for ( domain = domains;
    704 		      domain;
    705 		      domain = domain->next ) {
    706 			rc = value_add_one ( &c->rvalue_vals,
    707 					     &domain->domain_spec );
    708 			if ( rc ) break;
    709 		}
    710 		break;
    711 	case LDAP_MOD_DELETE:
    712 		if ( c->valx < 0 ) { /* delete them all! */
    713 			unique_free_domain ( domains );
    714 			private->domains = NULL;
    715 		} else { /* delete just one */
    716 			domainp = &private->domains;
    717 			for ( i=0; i < c->valx && *domainp; ++i )
    718 				domainp = &(*domainp)->next;
    719 
    720 			/* If *domainp is null, we walked off the end
    721 			 * of the list.  This happens when back-config
    722 			 * and the overlay are out-of-sync, like when
    723 			 * rejecting changes before ITS#4752 gets
    724 			 * fixed.
    725 			 *
    726 			 * This should never happen, but will appear
    727 			 * if you backport this version of
    728 			 * slapo-unique without the config-undo fixes
    729 			 *
    730 			 * test024 Will hit this case in such a
    731 			 * situation.
    732 			 */
    733 			assert (*domainp != NULL);
    734 
    735 			domain = *domainp;
    736 			*domainp = domain->next;
    737 			domain->next = NULL;
    738 			unique_free_domain ( domain );
    739 		}
    740 		rc = 0;
    741 		break;
    742 
    743 	case SLAP_CONFIG_ADD: /* fallthrough */
    744 	case LDAP_MOD_ADD:
    745 		if ( legacy ) {
    746 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
    747 				  "cannot set Uri when legacy attrs are present" );
    748 			Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
    749 				c->cr_msg, NULL, NULL );
    750 			rc = ARG_BAD_CONF;
    751 			break;
    752 		}
    753 		rc = 0;
    754 		if ( c->line ) rc = unique_new_domain ( &domain, c->line, c );
    755 		else rc = unique_new_domain ( &domain, c->argv[1], c );
    756 		if ( rc ) break;
    757 		assert ( domain->next == NULL );
    758 		for ( domainp = &private->domains;
    759 		      *domainp;
    760 		      domainp = &(*domainp)->next ) ;
    761 		*domainp = domain;
    762 
    763 		break;
    764 
    765 	default:
    766 		abort ();
    767 	}
    768 
    769 	return rc;
    770 }
    771 
    772 /*
    773 ** allocate new unique_data;
    774 ** initialize, copy basedn;
    775 ** store in on_bi.bi_private;
    776 **
    777 */
    778 
    779 static int
    780 unique_db_init(
    781 	BackendDB	*be,
    782 	ConfigReply	*cr
    783 )
    784 {
    785 	slap_overinst *on = (slap_overinst *)be->bd_info;
    786 	unique_data **privatep = (unique_data **) &on->on_bi.bi_private;
    787 
    788 	Debug(LDAP_DEBUG_TRACE, "==> unique_db_init\n", 0, 0, 0);
    789 
    790 	*privatep = ch_calloc ( 1, sizeof ( unique_data ) );
    791 
    792 	return 0;
    793 }
    794 
    795 static int
    796 unique_db_destroy(
    797 	BackendDB	*be,
    798 	ConfigReply	*cr
    799 )
    800 {
    801 	slap_overinst *on = (slap_overinst *)be->bd_info;
    802 	unique_data **privatep = (unique_data **) &on->on_bi.bi_private;
    803 	unique_data *private = *privatep;
    804 
    805 	Debug(LDAP_DEBUG_TRACE, "==> unique_db_destroy\n", 0, 0, 0);
    806 
    807 	if ( private ) {
    808 		unique_domain *domains = private->domains;
    809 		unique_domain *legacy = private->legacy;
    810 
    811 		unique_free_domain ( domains );
    812 		unique_free_domain ( legacy );
    813 		ch_free ( private );
    814 		*privatep = NULL;
    815 	}
    816 
    817 	return 0;
    818 }
    819 
    820 static int
    821 unique_open(
    822 	BackendDB *be,
    823 	ConfigReply *cr
    824 )
    825 {
    826 	Debug(LDAP_DEBUG_TRACE, "unique_open: overlay initialized\n", 0, 0, 0);
    827 
    828 	return 0;
    829 }
    830 
    831 
    832 /*
    833 ** Leave unique_data but wipe out config
    834 **
    835 */
    836 
    837 static int
    838 unique_close(
    839 	BackendDB *be,
    840 	ConfigReply *cr
    841 )
    842 {
    843 	slap_overinst *on	= (slap_overinst *) be->bd_info;
    844 	unique_data **privatep = (unique_data **) &on->on_bi.bi_private;
    845 	unique_data *private = *privatep;
    846 
    847 	Debug(LDAP_DEBUG_TRACE, "==> unique_close\n", 0, 0, 0);
    848 
    849 	if ( private ) {
    850 		unique_domain *domains = private->domains;
    851 		unique_domain *legacy = private->legacy;
    852 
    853 		unique_free_domain ( domains );
    854 		unique_free_domain ( legacy );
    855 		memset ( private, 0, sizeof ( unique_data ) );
    856 	}
    857 
    858 	return ( 0 );
    859 }
    860 
    861 
    862 /*
    863 ** search callback
    864 **	if this is a REP_SEARCH, count++;
    865 **
    866 */
    867 
    868 static int count_attr_cb(
    869 	Operation *op,
    870 	SlapReply *rs
    871 )
    872 {
    873 	unique_counter *uc;
    874 
    875 	/* because you never know */
    876 	if(!op || !rs) return(0);
    877 
    878 	/* Only search entries are interesting */
    879 	if(rs->sr_type != REP_SEARCH) return(0);
    880 
    881 	uc = op->o_callback->sc_private;
    882 
    883 	/* Ignore the current entry */
    884 	if ( dn_match( uc->ndn, &rs->sr_entry->e_nname )) return(0);
    885 
    886 	Debug(LDAP_DEBUG_TRACE, "==> count_attr_cb <%s>\n",
    887 		rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
    888 
    889 	uc->count++;
    890 
    891 	return(0);
    892 }
    893 
    894 /* count the length of one attribute ad
    895  * (and all of its values b)
    896  * in the proposed filter
    897  */
    898 static int
    899 count_filter_len(
    900 	unique_domain *domain,
    901 	unique_domain_uri *uri,
    902 	AttributeDescription *ad,
    903 	BerVarray b
    904 )
    905 {
    906 	unique_attrs *attr;
    907 	int i;
    908 	int ks = 0;
    909 
    910 	while ( !is_at_operational( ad->ad_type ) ) {
    911 		if ( uri->attrs ) {
    912 			for ( attr = uri->attrs; attr; attr = attr->next ) {
    913 				if ( ad == attr->attr ) {
    914 					break;
    915 				}
    916 			}
    917 			if ( ( domain->ignore && attr )
    918 			     || (!domain->ignore && !attr )) {
    919 				break;
    920 			}
    921 		}
    922 		if ( b && b[0].bv_val ) {
    923 			for (i = 0; b[i].bv_val; i++ ) {
    924 				/* note: make room for filter escaping... */
    925 				ks += ( 3 * b[i].bv_len ) + ad->ad_cname.bv_len + STRLENOF( "(=)" );
    926 			}
    927 		} else if ( domain->strict ) {
    928 			ks += ad->ad_cname.bv_len + STRLENOF( "(=*)" );	/* (attr=*) */
    929 		}
    930 		break;
    931 	}
    932 
    933 	return ks;
    934 }
    935 
    936 static char *
    937 build_filter(
    938 	unique_domain *domain,
    939 	unique_domain_uri *uri,
    940 	AttributeDescription *ad,
    941 	BerVarray b,
    942 	char *kp,
    943 	int ks,
    944 	void *ctx
    945 )
    946 {
    947 	unique_attrs *attr;
    948 	int i;
    949 
    950 	while ( !is_at_operational( ad->ad_type ) ) {
    951 		if ( uri->attrs ) {
    952 			for ( attr = uri->attrs; attr; attr = attr->next ) {
    953 				if ( ad == attr->attr ) {
    954 					break;
    955 				}
    956 			}
    957 			if ( ( domain->ignore && attr )
    958 			     || (!domain->ignore && !attr )) {
    959 				break;
    960 			}
    961 		}
    962 		if ( b && b[0].bv_val ) {
    963 			for ( i = 0; b[i].bv_val; i++ ) {
    964 				struct berval	bv;
    965 				int len;
    966 
    967 				ldap_bv2escaped_filter_value_x( &b[i], &bv, 1, ctx );
    968 				len = snprintf( kp, ks, "(%s=%s)", ad->ad_cname.bv_val, bv.bv_val );
    969 				assert( len >= 0 && len < ks );
    970 				kp += len;
    971 				if ( bv.bv_val != b[i].bv_val ) {
    972 					ber_memfree_x( bv.bv_val, ctx );
    973 				}
    974 			}
    975 		} else if ( domain->strict ) {
    976 			int len;
    977 			len = snprintf( kp, ks, "(%s=*)", ad->ad_cname.bv_val );
    978 			assert( len >= 0 && len < ks );
    979 			kp += len;
    980 		}
    981 		break;
    982 	}
    983 	return kp;
    984 }
    985 
    986 static int
    987 unique_search(
    988 	Operation *op,
    989 	Operation *nop,
    990 	struct berval * dn,
    991 	int scope,
    992 	SlapReply *rs,
    993 	struct berval *key
    994 )
    995 {
    996 	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
    997 	SlapReply nrs = { REP_RESULT };
    998 	slap_callback cb = { NULL, NULL, NULL, NULL }; /* XXX */
    999 	unique_counter uq = { NULL, 0 };
   1000 	int rc;
   1001 
   1002 	Debug(LDAP_DEBUG_TRACE, "==> unique_search %s\n", key->bv_val, 0, 0);
   1003 
   1004 	nop->ors_filter = str2filter_x(nop, key->bv_val);
   1005 	if(nop->ors_filter == NULL) {
   1006 		op->o_bd->bd_info = (BackendInfo *) on->on_info;
   1007 		send_ldap_error(op, rs, LDAP_OTHER,
   1008 			"unique_search invalid filter");
   1009 		return(rs->sr_err);
   1010 	}
   1011 
   1012 	nop->ors_filterstr = *key;
   1013 
   1014 	cb.sc_response	= (slap_response*)count_attr_cb;
   1015 	cb.sc_private	= &uq;
   1016 	nop->o_callback	= &cb;
   1017 	nop->o_tag	= LDAP_REQ_SEARCH;
   1018 	nop->ors_scope	= scope;
   1019 	nop->ors_deref	= LDAP_DEREF_NEVER;
   1020 	nop->ors_limit	= NULL;
   1021 	nop->ors_slimit	= SLAP_NO_LIMIT;
   1022 	nop->ors_tlimit	= SLAP_NO_LIMIT;
   1023 	nop->ors_attrs	= slap_anlist_no_attrs;
   1024 	nop->ors_attrsonly = 1;
   1025 
   1026 	uq.ndn = &op->o_req_ndn;
   1027 
   1028 	nop->o_req_ndn = *dn;
   1029 	nop->o_ndn = op->o_bd->be_rootndn;
   1030 
   1031 	nop->o_bd = on->on_info->oi_origdb;
   1032 	rc = nop->o_bd->be_search(nop, &nrs);
   1033 	filter_free_x(nop, nop->ors_filter, 1);
   1034 	op->o_tmpfree( key->bv_val, op->o_tmpmemctx );
   1035 
   1036 	if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
   1037 		op->o_bd->bd_info = (BackendInfo *) on->on_info;
   1038 		send_ldap_error(op, rs, rc, "unique_search failed");
   1039 		return(rs->sr_err);
   1040 	}
   1041 
   1042 	Debug(LDAP_DEBUG_TRACE, "=> unique_search found %d records\n", uq.count, 0, 0);
   1043 
   1044 	if(uq.count) {
   1045 		op->o_bd->bd_info = (BackendInfo *) on->on_info;
   1046 		send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION,
   1047 			"some attributes not unique");
   1048 		return(rs->sr_err);
   1049 	}
   1050 
   1051 	return(SLAP_CB_CONTINUE);
   1052 }
   1053 
   1054 static int
   1055 unique_add(
   1056 	Operation *op,
   1057 	SlapReply *rs
   1058 )
   1059 {
   1060 	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
   1061 	unique_data *private = (unique_data *) on->on_bi.bi_private;
   1062 	unique_domain *domains = private->domains;
   1063 	unique_domain *legacy = private->legacy;
   1064 	unique_domain *domain;
   1065 	Operation nop = *op;
   1066 	Attribute *a;
   1067 	char *key, *kp;
   1068 	struct berval bvkey;
   1069 	int rc = SLAP_CB_CONTINUE;
   1070 
   1071 	Debug(LDAP_DEBUG_TRACE, "==> unique_add <%s>\n",
   1072 	      op->o_req_dn.bv_val, 0, 0);
   1073 
   1074 	for ( domain = legacy ? legacy : domains;
   1075 	      domain;
   1076 	      domain = domain->next )
   1077 	{
   1078 		unique_domain_uri *uri;
   1079 
   1080 		for ( uri = domain->uri;
   1081 		      uri;
   1082 		      uri = uri->next )
   1083 		{
   1084 			int len;
   1085 			int ks = 0;
   1086 
   1087 			if ( uri->ndn.bv_val
   1088 			     && !dnIsSuffix( &op->o_req_ndn, &uri->ndn ))
   1089 				continue;
   1090 
   1091 			if ( uri->f ) {
   1092 				if ( test_filter( NULL, op->ora_e, uri->f )
   1093 					== LDAP_COMPARE_FALSE )
   1094 				{
   1095 					Debug( LDAP_DEBUG_TRACE,
   1096 						"==> unique_add_skip<%s>\n",
   1097 						op->o_req_dn.bv_val, 0, 0 );
   1098 					continue;
   1099 				}
   1100 			}
   1101 
   1102 			if(!(a = op->ora_e->e_attrs)) {
   1103 				op->o_bd->bd_info = (BackendInfo *) on->on_info;
   1104 				send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
   1105 						"unique_add() got null op.ora_e.e_attrs");
   1106 				rc = rs->sr_err;
   1107 				break;
   1108 
   1109 			} else {
   1110 				for(; a; a = a->a_next) {
   1111 					ks += count_filter_len ( domain,
   1112 								 uri,
   1113 								 a->a_desc,
   1114 								 a->a_vals);
   1115 				}
   1116 			}
   1117 
   1118 			/* skip this domain-uri if it isn't involved */
   1119 			if ( !ks ) continue;
   1120 
   1121 			/* terminating NUL */
   1122 			ks += sizeof("(|)");
   1123 
   1124 			if ( uri->filter.bv_val && uri->filter.bv_len )
   1125 				ks += uri->filter.bv_len + STRLENOF ("(&)");
   1126 			kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
   1127 
   1128 			if ( uri->filter.bv_val && uri->filter.bv_len ) {
   1129 				len = snprintf (kp, ks, "(&%s", uri->filter.bv_val);
   1130 				assert( len >= 0 && len < ks );
   1131 				kp += len;
   1132 			}
   1133 			len = snprintf(kp, ks - (kp - key), "(|");
   1134 			assert( len >= 0 && len < ks - (kp - key) );
   1135 			kp += len;
   1136 
   1137 			for(a = op->ora_e->e_attrs; a; a = a->a_next)
   1138 				kp = build_filter(domain,
   1139 						  uri,
   1140 						  a->a_desc,
   1141 						  a->a_vals,
   1142 						  kp,
   1143 						  ks - ( kp - key ),
   1144 						  op->o_tmpmemctx);
   1145 
   1146 			len = snprintf(kp, ks - (kp - key), ")");
   1147 			assert( len >= 0 && len < ks - (kp - key) );
   1148 			kp += len;
   1149 			if ( uri->filter.bv_val && uri->filter.bv_len ) {
   1150 				len = snprintf(kp, ks - (kp - key), ")");
   1151 				assert( len >= 0 && len < ks - (kp - key) );
   1152 				kp += len;
   1153 			}
   1154 			bvkey.bv_val = key;
   1155 			bvkey.bv_len = kp - key;
   1156 
   1157 			rc = unique_search ( op,
   1158 					     &nop,
   1159 					     uri->ndn.bv_val ?
   1160 					     &uri->ndn :
   1161 					     &op->o_bd->be_nsuffix[0],
   1162 					     uri->scope,
   1163 					     rs,
   1164 					     &bvkey);
   1165 
   1166 			if ( rc != SLAP_CB_CONTINUE ) break;
   1167 		}
   1168 		if ( rc != SLAP_CB_CONTINUE ) break;
   1169 	}
   1170 
   1171 	return rc;
   1172 }
   1173 
   1174 
   1175 static int
   1176 unique_modify(
   1177 	Operation *op,
   1178 	SlapReply *rs
   1179 )
   1180 {
   1181 	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
   1182 	unique_data *private = (unique_data *) on->on_bi.bi_private;
   1183 	unique_domain *domains = private->domains;
   1184 	unique_domain *legacy = private->legacy;
   1185 	unique_domain *domain;
   1186 	Operation nop = *op;
   1187 	Modifications *m;
   1188 	char *key, *kp;
   1189 	struct berval bvkey;
   1190 	int rc = SLAP_CB_CONTINUE;
   1191 
   1192 	Debug(LDAP_DEBUG_TRACE, "==> unique_modify <%s>\n",
   1193 	      op->o_req_dn.bv_val, 0, 0);
   1194 
   1195 	for ( domain = legacy ? legacy : domains;
   1196 	      domain;
   1197 	      domain = domain->next )
   1198 	{
   1199 		unique_domain_uri *uri;
   1200 
   1201 		for ( uri = domain->uri;
   1202 		      uri;
   1203 		      uri = uri->next )
   1204 		{
   1205 			int len;
   1206 			int ks = 0;
   1207 
   1208 			if ( uri->ndn.bv_val
   1209 			     && !dnIsSuffix( &op->o_req_ndn, &uri->ndn ))
   1210 				continue;
   1211 
   1212 			if ( !(m = op->orm_modlist) ) {
   1213 				op->o_bd->bd_info = (BackendInfo *) on->on_info;
   1214 				send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
   1215 						"unique_modify() got null op.orm_modlist");
   1216 				rc = rs->sr_err;
   1217 				break;
   1218 
   1219 			} else
   1220 				for ( ; m; m = m->sml_next)
   1221 					if ( (m->sml_op & LDAP_MOD_OP)
   1222 					     != LDAP_MOD_DELETE )
   1223 						ks += count_filter_len
   1224 							( domain,
   1225 							  uri,
   1226 							  m->sml_desc,
   1227 							  m->sml_values);
   1228 
   1229 			/* skip this domain-uri if it isn't involved */
   1230 			if ( !ks ) continue;
   1231 
   1232 			/* terminating NUL */
   1233 			ks += sizeof("(|)");
   1234 
   1235 			if ( uri->filter.bv_val && uri->filter.bv_len )
   1236 				ks += uri->filter.bv_len + STRLENOF ("(&)");
   1237 			kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
   1238 
   1239 			if ( uri->filter.bv_val && uri->filter.bv_len ) {
   1240 				len = snprintf(kp, ks, "(&%s", uri->filter.bv_val);
   1241 				assert( len >= 0 && len < ks );
   1242 				kp += len;
   1243 			}
   1244 			len = snprintf(kp, ks - (kp - key), "(|");
   1245 			assert( len >= 0 && len < ks - (kp - key) );
   1246 			kp += len;
   1247 
   1248 			for(m = op->orm_modlist; m; m = m->sml_next)
   1249 				if ( (m->sml_op & LDAP_MOD_OP)
   1250 				     != LDAP_MOD_DELETE )
   1251 					kp = build_filter ( domain,
   1252 							    uri,
   1253 							    m->sml_desc,
   1254 							    m->sml_values,
   1255 							    kp,
   1256 							    ks - (kp - key),
   1257 							    op->o_tmpmemctx );
   1258 
   1259 			len = snprintf(kp, ks - (kp - key), ")");
   1260 			assert( len >= 0 && len < ks - (kp - key) );
   1261 			kp += len;
   1262 			if ( uri->filter.bv_val && uri->filter.bv_len ) {
   1263 				len = snprintf (kp, ks - (kp - key), ")");
   1264 				assert( len >= 0 && len < ks - (kp - key) );
   1265 				kp += len;
   1266 			}
   1267 			bvkey.bv_val = key;
   1268 			bvkey.bv_len = kp - key;
   1269 
   1270 			rc = unique_search ( op,
   1271 					     &nop,
   1272 					     uri->ndn.bv_val ?
   1273 					     &uri->ndn :
   1274 					     &op->o_bd->be_nsuffix[0],
   1275 					     uri->scope,
   1276 					     rs,
   1277 					     &bvkey);
   1278 
   1279 			if ( rc != SLAP_CB_CONTINUE ) break;
   1280 		}
   1281 		if ( rc != SLAP_CB_CONTINUE ) break;
   1282 	}
   1283 
   1284 	return rc;
   1285 }
   1286 
   1287 
   1288 static int
   1289 unique_modrdn(
   1290 	Operation *op,
   1291 	SlapReply *rs
   1292 )
   1293 {
   1294 	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
   1295 	unique_data *private = (unique_data *) on->on_bi.bi_private;
   1296 	unique_domain *domains = private->domains;
   1297 	unique_domain *legacy = private->legacy;
   1298 	unique_domain *domain;
   1299 	Operation nop = *op;
   1300 	char *key, *kp;
   1301 	struct berval bvkey;
   1302 	LDAPRDN	newrdn;
   1303 	struct berval bv[2];
   1304 	int rc = SLAP_CB_CONTINUE;
   1305 
   1306 	Debug(LDAP_DEBUG_TRACE, "==> unique_modrdn <%s> <%s>\n",
   1307 		op->o_req_dn.bv_val, op->orr_newrdn.bv_val, 0);
   1308 
   1309 	for ( domain = legacy ? legacy : domains;
   1310 	      domain;
   1311 	      domain = domain->next )
   1312 	{
   1313 		unique_domain_uri *uri;
   1314 
   1315 		for ( uri = domain->uri;
   1316 		      uri;
   1317 		      uri = uri->next )
   1318 		{
   1319 			int i, len;
   1320 			int ks = 0;
   1321 
   1322 			if ( uri->ndn.bv_val
   1323 			     && !dnIsSuffix( &op->o_req_ndn, &uri->ndn )
   1324 			     && (!op->orr_nnewSup
   1325 				 || !dnIsSuffix( op->orr_nnewSup, &uri->ndn )))
   1326 				continue;
   1327 
   1328 			if ( ldap_bv2rdn_x ( &op->oq_modrdn.rs_newrdn,
   1329 					     &newrdn,
   1330 					     (char **)&rs->sr_text,
   1331 					     LDAP_DN_FORMAT_LDAP,
   1332 					     op->o_tmpmemctx ) ) {
   1333 				op->o_bd->bd_info = (BackendInfo *) on->on_info;
   1334 				send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
   1335 						"unknown type(s) used in RDN");
   1336 				rc = rs->sr_err;
   1337 				break;
   1338 			}
   1339 
   1340 			rc = SLAP_CB_CONTINUE;
   1341 			for ( i=0; newrdn[i]; i++) {
   1342 				AttributeDescription *ad = NULL;
   1343 				if ( slap_bv2ad( &newrdn[i]->la_attr, &ad, &rs->sr_text )) {
   1344 					ldap_rdnfree_x( newrdn, op->o_tmpmemctx );
   1345 					rs->sr_err = LDAP_INVALID_SYNTAX;
   1346 					send_ldap_result( op, rs );
   1347 					rc = rs->sr_err;
   1348 					break;
   1349 				}
   1350 				newrdn[i]->la_private = ad;
   1351 			}
   1352 			if ( rc != SLAP_CB_CONTINUE ) break;
   1353 
   1354 			bv[1].bv_val = NULL;
   1355 			bv[1].bv_len = 0;
   1356 
   1357 			for ( i=0; newrdn[i]; i++ ) {
   1358 				bv[0] = newrdn[i]->la_value;
   1359 				ks += count_filter_len ( domain,
   1360 							 uri,
   1361 							 newrdn[i]->la_private,
   1362 							 bv);
   1363 			}
   1364 
   1365 			/* skip this domain if it isn't involved */
   1366 			if ( !ks ) continue;
   1367 
   1368 			/* terminating NUL */
   1369 			ks += sizeof("(|)");
   1370 
   1371 			if ( uri->filter.bv_val && uri->filter.bv_len )
   1372 				ks += uri->filter.bv_len + STRLENOF ("(&)");
   1373 			kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
   1374 
   1375 			if ( uri->filter.bv_val && uri->filter.bv_len ) {
   1376 				len = snprintf(kp, ks, "(&%s", uri->filter.bv_val);
   1377 				assert( len >= 0 && len < ks );
   1378 				kp += len;
   1379 			}
   1380 			len = snprintf(kp, ks - (kp - key), "(|");
   1381 			assert( len >= 0 && len < ks - (kp - key) );
   1382 			kp += len;
   1383 
   1384 			for ( i=0; newrdn[i]; i++) {
   1385 				bv[0] = newrdn[i]->la_value;
   1386 				kp = build_filter ( domain,
   1387 						    uri,
   1388 						    newrdn[i]->la_private,
   1389 						    bv,
   1390 						    kp,
   1391 						    ks - (kp - key ),
   1392 						    op->o_tmpmemctx);
   1393 			}
   1394 
   1395 			len = snprintf(kp, ks - (kp - key), ")");
   1396 			assert( len >= 0 && len < ks - (kp - key) );
   1397 			kp += len;
   1398 			if ( uri->filter.bv_val && uri->filter.bv_len ) {
   1399 				len = snprintf (kp, ks - (kp - key), ")");
   1400 				assert( len >= 0 && len < ks - (kp - key) );
   1401 				kp += len;
   1402 			}
   1403 			bvkey.bv_val = key;
   1404 			bvkey.bv_len = kp - key;
   1405 
   1406 			rc = unique_search ( op,
   1407 					     &nop,
   1408 					     uri->ndn.bv_val ?
   1409 					     &uri->ndn :
   1410 					     &op->o_bd->be_nsuffix[0],
   1411 					     uri->scope,
   1412 					     rs,
   1413 					     &bvkey);
   1414 
   1415 			if ( rc != SLAP_CB_CONTINUE ) break;
   1416 		}
   1417 		if ( rc != SLAP_CB_CONTINUE ) break;
   1418 	}
   1419 
   1420 	return rc;
   1421 }
   1422 
   1423 /*
   1424 ** init_module is last so the symbols resolve "for free" --
   1425 ** it expects to be called automagically during dynamic module initialization
   1426 */
   1427 
   1428 int
   1429 unique_initialize()
   1430 {
   1431 	int rc;
   1432 
   1433 	/* statically declared just after the #includes at top */
   1434 	memset (&unique, 0, sizeof(unique));
   1435 
   1436 	unique.on_bi.bi_type = "unique";
   1437 	unique.on_bi.bi_db_init = unique_db_init;
   1438 	unique.on_bi.bi_db_destroy = unique_db_destroy;
   1439 	unique.on_bi.bi_db_open = unique_open;
   1440 	unique.on_bi.bi_db_close = unique_close;
   1441 	unique.on_bi.bi_op_add = unique_add;
   1442 	unique.on_bi.bi_op_modify = unique_modify;
   1443 	unique.on_bi.bi_op_modrdn = unique_modrdn;
   1444 
   1445 	unique.on_bi.bi_cf_ocs = uniqueocs;
   1446 	rc = config_register_schema( uniquecfg, uniqueocs );
   1447 	if ( rc ) return rc;
   1448 
   1449 	return(overlay_register(&unique));
   1450 }
   1451 
   1452 #if SLAPD_OVER_UNIQUE == SLAPD_MOD_DYNAMIC && defined(PIC)
   1453 int init_module(int argc, char *argv[]) {
   1454 	return unique_initialize();
   1455 }
   1456 #endif
   1457 
   1458 #endif /* SLAPD_OVER_UNIQUE */
   1459