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