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