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