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