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