1 /* $NetBSD: unique.c,v 1.3 2021/08/14 16:15:02 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-2021 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.3 2021/08/14 16:15:02 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
unique_free_domain_uri(unique_domain_uri * uri)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
unique_free_domain(unique_domain * domain)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
unique_new_domain_uri(unique_domain_uri ** urip,const LDAPURLDesc * url_desc,ConfigArgs * c)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
unique_new_domain_uri_basic(unique_domain_uri ** urip,ConfigArgs * c)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
unique_new_domain(unique_domain ** domainp,char * domain_spec,ConfigArgs * c)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
unique_cf_base(ConfigArgs * c)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
unique_cf_attrs(ConfigArgs * c)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 case SLAP_CONFIG_ADD:
560 if ( domains ) {
561 snprintf( c->cr_msg, sizeof( c->cr_msg ),
562 "cannot set legacy attrs when URIs are present" );
563 Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
564 c->cr_msg );
565 rc = ARG_BAD_CONF;
566 break;
567 }
568 if ( legacy
569 && legacy->uri
570 && legacy->uri->attrs
571 && (c->type == UNIQUE_IGNORE) != legacy->ignore ) {
572 snprintf( c->cr_msg, sizeof( c->cr_msg ),
573 "cannot set both attrs and ignore-attrs" );
574 Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
575 c->cr_msg );
576 rc = ARG_BAD_CONF;
577 break;
578 }
579 if ( !legacy ) {
580 unique_new_domain ( &private->legacy,
581 UNIQUE_DEFAULT_URI,
582 c );
583 legacy = private->legacy;
584 }
585 if ( !legacy->uri )
586 unique_new_domain_uri_basic ( &legacy->uri, c );
587 rc = 0;
588 for ( i=1; c->argv[i]; ++i ) {
589 AttributeDescription * ad = NULL;
590 const char * text;
591 if ( slap_str2ad ( c->argv[i], &ad, &text )
592 == LDAP_SUCCESS) {
593
594 attr = ch_calloc ( 1,
595 sizeof ( unique_attrs ) );
596 attr->attr = ad;
597 attr->next = new_attrs;
598 new_attrs = attr;
599 } else {
600 snprintf( c->cr_msg, sizeof( c->cr_msg ),
601 "unique: attribute: %s: %s",
602 c->argv[i], text );
603 for ( attr = new_attrs;
604 attr;
605 attr=next_attr ) {
606 next_attr = attr->next;
607 ch_free ( attr );
608 }
609 rc = ARG_BAD_CONF;
610 break;
611 }
612 }
613 if ( rc ) break;
614
615 /* (nconc legacy->uri->attrs (nreverse new_attrs)) */
616 reverse_attrs = NULL;
617 for ( attr = new_attrs;
618 attr;
619 attr = next_attr ) {
620 next_attr = attr->next;
621 attr->next = reverse_attrs;
622 reverse_attrs = attr;
623 }
624 for ( attrp = &legacy->uri->attrs;
625 *attrp;
626 attrp = &(*attrp)->next ) ;
627 *attrp = reverse_attrs;
628
629 legacy->ignore = ( c->type == UNIQUE_IGNORE );
630 break;
631 default:
632 abort();
633 }
634
635 if ( rc ) {
636 Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
637 "%s: %s\n", c->log, c->cr_msg );
638 }
639 return rc;
640 }
641
642 static int
unique_cf_strict(ConfigArgs * c)643 unique_cf_strict( ConfigArgs *c )
644 {
645 slap_overinst *on = (slap_overinst *)c->bi;
646 unique_data *private = (unique_data *) on->on_bi.bi_private;
647 unique_domain *domains = private->domains;
648 unique_domain *legacy = private->legacy;
649 int rc = ARG_BAD_CONF;
650
651 switch ( c->op ) {
652 case SLAP_CONFIG_EMIT:
653 /* We process the boolean manually instead of using
654 * ARG_ON_OFF so that we can three-state it;
655 * olcUniqueStrict is either TRUE, FALSE, or missing,
656 * and missing is necessary to add olcUniqueURIs...
657 */
658 if ( private->legacy_strict_set ) {
659 struct berval bv = legacy->strict ? slap_true_bv : slap_false_bv;
660 value_add_one ( &c->rvalue_vals, &bv );
661 }
662 rc = 0;
663 break;
664 case LDAP_MOD_DELETE:
665 if ( legacy ) {
666 legacy->strict = 0;
667 if ( ! legacy->uri ) {
668 unique_free_domain ( legacy );
669 private->legacy = NULL;
670 }
671 }
672 private->legacy_strict_set = 0;
673 rc = 0;
674 break;
675 case LDAP_MOD_ADD:
676 case SLAP_CONFIG_ADD:
677 if ( domains ) {
678 snprintf( c->cr_msg, sizeof( c->cr_msg ),
679 "cannot set legacy attrs when URIs are present" );
680 Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
681 c->cr_msg );
682 rc = ARG_BAD_CONF;
683 break;
684 }
685 if ( ! legacy ) {
686 unique_new_domain ( &private->legacy,
687 UNIQUE_DEFAULT_URI,
688 c );
689 legacy = private->legacy;
690 }
691 /* ... not using ARG_ON_OFF makes this necessary too */
692 assert ( c->argc == 2 );
693 legacy->strict = (strcasecmp ( c->argv[1], "TRUE" ) == 0);
694 private->legacy_strict_set = 1;
695 rc = 0;
696 break;
697 default:
698 abort();
699 }
700
701 return rc;
702 }
703
704 static int
unique_cf_uri(ConfigArgs * c)705 unique_cf_uri( ConfigArgs *c )
706 {
707 slap_overinst *on = (slap_overinst *)c->bi;
708 unique_data *private = (unique_data *) on->on_bi.bi_private;
709 unique_domain *domains = private->domains;
710 unique_domain *legacy = private->legacy;
711 unique_domain *domain = NULL, **domainp = NULL;
712 int rc = ARG_BAD_CONF;
713 int i;
714
715 switch ( c->op ) {
716 case SLAP_CONFIG_EMIT:
717 for ( domain = domains;
718 domain;
719 domain = domain->next ) {
720 rc = value_add_one ( &c->rvalue_vals,
721 &domain->domain_spec );
722 if ( rc ) break;
723 }
724 break;
725 case LDAP_MOD_DELETE:
726 if ( c->valx < 0 ) { /* delete them all! */
727 unique_free_domain ( domains );
728 private->domains = NULL;
729 } else { /* delete just one */
730 domainp = &private->domains;
731 for ( i=0; i < c->valx && *domainp; ++i )
732 domainp = &(*domainp)->next;
733
734 /* If *domainp is null, we walked off the end
735 * of the list. This happens when back-config
736 * and the overlay are out-of-sync, like when
737 * rejecting changes before ITS#4752 gets
738 * fixed.
739 *
740 * This should never happen, but will appear
741 * if you backport this version of
742 * slapo-unique without the config-undo fixes
743 *
744 * test024 Will hit this case in such a
745 * situation.
746 */
747 assert (*domainp != NULL);
748
749 domain = *domainp;
750 *domainp = domain->next;
751 domain->next = NULL;
752 unique_free_domain ( domain );
753 }
754 rc = 0;
755 break;
756
757 case SLAP_CONFIG_ADD: /* fallthru */
758 case LDAP_MOD_ADD:
759 if ( legacy ) {
760 snprintf( c->cr_msg, sizeof( c->cr_msg ),
761 "cannot set Uri when legacy attrs are present" );
762 Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
763 c->cr_msg );
764 rc = ARG_BAD_CONF;
765 break;
766 }
767 rc = 0;
768 if ( c->line ) rc = unique_new_domain ( &domain, c->line, c );
769 else rc = unique_new_domain ( &domain, c->argv[1], c );
770 if ( rc ) break;
771 assert ( domain->next == NULL );
772 for ( domainp = &private->domains;
773 *domainp;
774 domainp = &(*domainp)->next ) ;
775 *domainp = domain;
776
777 break;
778
779 default:
780 abort ();
781 }
782
783 return rc;
784 }
785
786 /*
787 ** allocate new unique_data;
788 ** initialize, copy basedn;
789 ** store in on_bi.bi_private;
790 **
791 */
792
793 static int
unique_db_init(BackendDB * be,ConfigReply * cr)794 unique_db_init(
795 BackendDB *be,
796 ConfigReply *cr
797 )
798 {
799 slap_overinst *on = (slap_overinst *)be->bd_info;
800 unique_data *private;
801
802 Debug(LDAP_DEBUG_TRACE, "==> unique_db_init\n" );
803
804 private = ch_calloc ( 1, sizeof ( unique_data ) );
805 ldap_pvt_thread_mutex_init( &private->serial_mutex );
806 on->on_bi.bi_private = private;
807
808 return 0;
809 }
810
811 static int
unique_db_destroy(BackendDB * be,ConfigReply * cr)812 unique_db_destroy(
813 BackendDB *be,
814 ConfigReply *cr
815 )
816 {
817 slap_overinst *on = (slap_overinst *)be->bd_info;
818 unique_data *private = on->on_bi.bi_private;
819
820 Debug(LDAP_DEBUG_TRACE, "==> unique_db_destroy\n" );
821
822 if ( private ) {
823 unique_domain *domains = private->domains;
824 unique_domain *legacy = private->legacy;
825
826 unique_free_domain ( domains );
827 unique_free_domain ( legacy );
828 ldap_pvt_thread_mutex_destroy( &private->serial_mutex );
829 ch_free ( private );
830 on->on_bi.bi_private = NULL;
831 }
832
833 return 0;
834 }
835
836
837 /*
838 ** search callback
839 ** if this is a REP_SEARCH, count++;
840 **
841 */
842
count_attr_cb(Operation * op,SlapReply * rs)843 static int count_attr_cb(
844 Operation *op,
845 SlapReply *rs
846 )
847 {
848 unique_counter *uc;
849
850 /* because you never know */
851 if(!op || !rs) return(0);
852
853 /* Only search entries are interesting */
854 if(rs->sr_type != REP_SEARCH) return(0);
855
856 uc = op->o_callback->sc_private;
857
858 /* Ignore the current entry */
859 if ( dn_match( uc->ndn, &rs->sr_entry->e_nname )) return(0);
860
861 Debug(LDAP_DEBUG_TRACE, "==> count_attr_cb <%s>\n",
862 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN" );
863
864 uc->count++;
865
866 return(0);
867 }
868
869 /* count the length of one attribute ad
870 * (and all of its values b)
871 * in the proposed filter
872 */
873 static int
count_filter_len(unique_domain * domain,unique_domain_uri * uri,AttributeDescription * ad,BerVarray b)874 count_filter_len(
875 unique_domain *domain,
876 unique_domain_uri *uri,
877 AttributeDescription *ad,
878 BerVarray b
879 )
880 {
881 unique_attrs *attr;
882 int i;
883 int ks = 0;
884
885 while ( !is_at_operational( ad->ad_type ) ) {
886 if ( uri->attrs ) {
887 for ( attr = uri->attrs; attr; attr = attr->next ) {
888 if ( ad == attr->attr ) {
889 break;
890 }
891 }
892 if ( ( domain->ignore && attr )
893 || (!domain->ignore && !attr )) {
894 break;
895 }
896 }
897 if ( b && b[0].bv_val ) {
898 for (i = 0; b[i].bv_val; i++ ) {
899 /* note: make room for filter escaping... */
900 ks += ( 3 * b[i].bv_len ) + ad->ad_cname.bv_len + STRLENOF( "(=)" );
901 }
902 } else if ( domain->strict ) {
903 ks += ad->ad_cname.bv_len + STRLENOF( "(=*)" ); /* (attr=*) */
904 }
905 break;
906 }
907
908 return ks;
909 }
910
911 static char *
build_filter(unique_domain * domain,unique_domain_uri * uri,AttributeDescription * ad,BerVarray b,char * kp,int ks,void * ctx)912 build_filter(
913 unique_domain *domain,
914 unique_domain_uri *uri,
915 AttributeDescription *ad,
916 BerVarray b,
917 char *kp,
918 int ks,
919 void *ctx
920 )
921 {
922 unique_attrs *attr;
923 int i;
924
925 while ( !is_at_operational( ad->ad_type ) ) {
926 if ( uri->attrs ) {
927 for ( attr = uri->attrs; attr; attr = attr->next ) {
928 if ( ad == attr->attr ) {
929 break;
930 }
931 }
932 if ( ( domain->ignore && attr )
933 || (!domain->ignore && !attr )) {
934 break;
935 }
936 }
937 if ( b && b[0].bv_val ) {
938 for ( i = 0; b[i].bv_val; i++ ) {
939 struct berval bv;
940 int len;
941
942 ldap_bv2escaped_filter_value_x( &b[i], &bv, 1, ctx );
943 if (!b[i].bv_len)
944 bv.bv_val = b[i].bv_val;
945 len = snprintf( kp, ks, "(%s=%s)", ad->ad_cname.bv_val, bv.bv_val );
946 assert( len >= 0 && len < ks );
947 kp += len;
948 if ( bv.bv_val != b[i].bv_val ) {
949 ber_memfree_x( bv.bv_val, ctx );
950 }
951 }
952 } else if ( domain->strict ) {
953 int len;
954 len = snprintf( kp, ks, "(%s=*)", ad->ad_cname.bv_val );
955 assert( len >= 0 && len < ks );
956 kp += len;
957 }
958 break;
959 }
960 return kp;
961 }
962
963 static int
unique_search(Operation * op,Operation * nop,struct berval * dn,int scope,SlapReply * rs,struct berval * key)964 unique_search(
965 Operation *op,
966 Operation *nop,
967 struct berval * dn,
968 int scope,
969 SlapReply *rs,
970 struct berval *key
971 )
972 {
973 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
974 SlapReply nrs = { REP_RESULT };
975 slap_callback cb = { NULL, NULL, NULL, NULL }; /* XXX */
976 unique_counter uq = { NULL, 0 };
977 int rc;
978 char *errmsg;
979 int errmsgsize;
980
981 Debug(LDAP_DEBUG_TRACE, "==> unique_search %s\n", key->bv_val );
982
983 nop->ors_filter = str2filter_x(nop, key->bv_val);
984 if(nop->ors_filter == NULL) {
985 op->o_bd->bd_info = (BackendInfo *) on->on_info;
986 send_ldap_error(op, rs, LDAP_OTHER,
987 "unique_search invalid filter");
988 return(rs->sr_err);
989 }
990
991 nop->ors_filterstr = *key;
992
993 cb.sc_response = (slap_response*)count_attr_cb;
994 cb.sc_private = &uq;
995 nop->o_callback = &cb;
996 nop->o_tag = LDAP_REQ_SEARCH;
997 nop->ors_scope = scope;
998 nop->ors_deref = LDAP_DEREF_NEVER;
999 nop->ors_limit = NULL;
1000 nop->ors_slimit = SLAP_NO_LIMIT;
1001 nop->ors_tlimit = SLAP_NO_LIMIT;
1002 nop->ors_attrs = slap_anlist_no_attrs;
1003 nop->ors_attrsonly = 1;
1004
1005 uq.ndn = &op->o_req_ndn;
1006
1007 nop->o_req_ndn = *dn;
1008 nop->o_ndn = op->o_bd->be_rootndn;
1009
1010 nop->o_bd = on->on_info->oi_origdb;
1011 rc = nop->o_bd->be_search(nop, &nrs);
1012 filter_free_x(nop, nop->ors_filter, 1);
1013
1014 if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
1015 op->o_bd->bd_info = (BackendInfo *) on->on_info;
1016 send_ldap_error(op, rs, rc, "unique_search failed");
1017 rc = rs->sr_err;
1018 } else if(uq.count) {
1019 Debug(LDAP_DEBUG_TRACE, "=> unique_search found %d records\n", uq.count );
1020
1021 errmsgsize = sizeof("non-unique attributes found with ") + key->bv_len;
1022 errmsg = op->o_tmpalloc(errmsgsize, op->o_tmpmemctx);
1023 snprintf( errmsg, errmsgsize, "non-unique attributes found with %s", key->bv_val );
1024 op->o_bd->bd_info = (BackendInfo *) on->on_info;
1025 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, errmsg);
1026 op->o_tmpfree(errmsg, op->o_tmpmemctx);
1027 rc = rs->sr_err;
1028 } else {
1029 Debug(LDAP_DEBUG_TRACE, "=> unique_search found no records\n" );
1030 rc = SLAP_CB_CONTINUE;
1031 }
1032
1033 op->o_tmpfree( key->bv_val, op->o_tmpmemctx );
1034
1035 return(rc);
1036 }
1037
1038 static int
unique_unlock(Operation * op,SlapReply * rs)1039 unique_unlock(
1040 Operation *op,
1041 SlapReply *rs
1042 )
1043 {
1044 slap_callback *sc = op->o_callback;
1045 unique_data *private = sc->sc_private;
1046
1047 ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
1048 op->o_callback = sc->sc_next;
1049 op->o_tmpfree( sc, op->o_tmpmemctx );
1050 return 0;
1051 }
1052
1053 static int
unique_add(Operation * op,SlapReply * rs)1054 unique_add(
1055 Operation *op,
1056 SlapReply *rs
1057 )
1058 {
1059 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1060 unique_data *private = (unique_data *) on->on_bi.bi_private;
1061 unique_domain *domains = private->domains;
1062 unique_domain *legacy = private->legacy;
1063 unique_domain *domain;
1064 Operation nop = *op;
1065 Attribute *a;
1066 char *key, *kp;
1067 struct berval bvkey;
1068 int rc = SLAP_CB_CONTINUE;
1069 int locked = 0;
1070
1071 Debug(LDAP_DEBUG_TRACE, "==> unique_add <%s>\n",
1072 op->o_req_dn.bv_val );
1073
1074 if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) || (
1075 get_relax(op) > SLAP_CONTROL_IGNORED
1076 && access_allowed( op, op->ora_e,
1077 slap_schema.si_ad_entry, NULL,
1078 ACL_MANAGE, NULL ) ) ) {
1079 return rc;
1080 }
1081
1082 for ( domain = legacy ? legacy : domains;
1083 domain;
1084 domain = domain->next )
1085 {
1086 unique_domain_uri *uri;
1087
1088 for ( uri = domain->uri;
1089 uri;
1090 uri = uri->next )
1091 {
1092 int len;
1093 int ks = 0;
1094
1095 if ( uri->ndn.bv_val
1096 && !dnIsSuffix( &op->o_req_ndn, &uri->ndn ))
1097 continue;
1098
1099 if ( uri->f ) {
1100 if ( test_filter( NULL, op->ora_e, uri->f )
1101 == LDAP_COMPARE_FALSE )
1102 {
1103 Debug( LDAP_DEBUG_TRACE,
1104 "==> unique_add_skip<%s>\n",
1105 op->o_req_dn.bv_val );
1106 continue;
1107 }
1108 }
1109
1110 if(!(a = op->ora_e->e_attrs)) {
1111 op->o_bd->bd_info = (BackendInfo *) on->on_info;
1112 send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
1113 "unique_add() got null op.ora_e.e_attrs");
1114 rc = rs->sr_err;
1115 break;
1116
1117 } else {
1118 for(; a; a = a->a_next) {
1119 ks += count_filter_len ( domain,
1120 uri,
1121 a->a_desc,
1122 a->a_vals);
1123 }
1124 }
1125
1126 /* skip this domain-uri if it isn't involved */
1127 if ( !ks ) continue;
1128
1129 if ( domain->serial && !locked ) {
1130 ldap_pvt_thread_mutex_lock( &private->serial_mutex );
1131 locked = 1;
1132 }
1133
1134 /* terminating NUL */
1135 ks += sizeof("(|)");
1136
1137 if ( uri->filter.bv_val && uri->filter.bv_len )
1138 ks += uri->filter.bv_len + STRLENOF ("(&)");
1139 kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
1140
1141 if ( uri->filter.bv_val && uri->filter.bv_len ) {
1142 len = snprintf (kp, ks, "(&%s", uri->filter.bv_val);
1143 assert( len >= 0 && len < ks );
1144 kp += len;
1145 }
1146 len = snprintf(kp, ks - (kp - key), "(|");
1147 assert( len >= 0 && len < ks - (kp - key) );
1148 kp += len;
1149
1150 for(a = op->ora_e->e_attrs; a; a = a->a_next)
1151 kp = build_filter(domain,
1152 uri,
1153 a->a_desc,
1154 a->a_vals,
1155 kp,
1156 ks - ( kp - key ),
1157 op->o_tmpmemctx);
1158
1159 len = snprintf(kp, ks - (kp - key), ")");
1160 assert( len >= 0 && len < ks - (kp - key) );
1161 kp += len;
1162 if ( uri->filter.bv_val && uri->filter.bv_len ) {
1163 len = snprintf(kp, ks - (kp - key), ")");
1164 assert( len >= 0 && len < ks - (kp - key) );
1165 kp += len;
1166 }
1167 bvkey.bv_val = key;
1168 bvkey.bv_len = kp - key;
1169
1170 rc = unique_search ( op,
1171 &nop,
1172 uri->ndn.bv_val ?
1173 &uri->ndn :
1174 &op->o_bd->be_nsuffix[0],
1175 uri->scope,
1176 rs,
1177 &bvkey);
1178
1179 if ( rc != SLAP_CB_CONTINUE ) break;
1180 }
1181 if ( rc != SLAP_CB_CONTINUE ) break;
1182 }
1183
1184 if ( locked ) {
1185 if ( rc != SLAP_CB_CONTINUE ) {
1186 ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
1187 } else {
1188 slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
1189 cb->sc_cleanup = unique_unlock;
1190 cb->sc_private = private;
1191 cb->sc_next = op->o_callback;
1192 op->o_callback = cb;
1193 }
1194 }
1195 return rc;
1196 }
1197
1198
1199 static int
unique_modify(Operation * op,SlapReply * rs)1200 unique_modify(
1201 Operation *op,
1202 SlapReply *rs
1203 )
1204 {
1205 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1206 unique_data *private = (unique_data *) on->on_bi.bi_private;
1207 unique_domain *domains = private->domains;
1208 unique_domain *legacy = private->legacy;
1209 unique_domain *domain;
1210 Operation nop = *op;
1211 Modifications *m;
1212 Entry *e = NULL;
1213 char *key, *kp;
1214 struct berval bvkey;
1215 int rc = SLAP_CB_CONTINUE;
1216 int locked = 0;
1217
1218 Debug(LDAP_DEBUG_TRACE, "==> unique_modify <%s>\n",
1219 op->o_req_dn.bv_val );
1220
1221 if ( !op->orm_modlist ) {
1222 Debug(LDAP_DEBUG_TRACE, "unique_modify: got empty modify op\n" );
1223 return rc;
1224 }
1225
1226 if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) || (
1227 get_relax(op) > SLAP_CONTROL_IGNORED
1228 && overlay_entry_get_ov(op, &op->o_req_ndn, NULL, NULL, 0, &e, on) == LDAP_SUCCESS
1229 && e
1230 && access_allowed( op, e,
1231 slap_schema.si_ad_entry, NULL,
1232 ACL_MANAGE, NULL ) ) ) {
1233 overlay_entry_release_ov( op, e, 0, on );
1234 return rc;
1235 }
1236 if ( e ) {
1237 overlay_entry_release_ov( op, e, 0, on );
1238 }
1239
1240 for ( domain = legacy ? legacy : domains;
1241 domain;
1242 domain = domain->next )
1243 {
1244 unique_domain_uri *uri;
1245
1246 for ( uri = domain->uri;
1247 uri;
1248 uri = uri->next )
1249 {
1250 int len;
1251 int ks = 0;
1252
1253 if ( uri->ndn.bv_val
1254 && !dnIsSuffix( &op->o_req_ndn, &uri->ndn ))
1255 continue;
1256
1257 for ( m = op->orm_modlist; m; m = m->sml_next)
1258 if ( (m->sml_op & LDAP_MOD_OP)
1259 != LDAP_MOD_DELETE )
1260 ks += count_filter_len
1261 ( domain,
1262 uri,
1263 m->sml_desc,
1264 m->sml_values);
1265
1266 /* skip this domain-uri if it isn't involved */
1267 if ( !ks ) continue;
1268
1269 if ( domain->serial && !locked ) {
1270 ldap_pvt_thread_mutex_lock( &private->serial_mutex );
1271 locked = 1;
1272 }
1273
1274 /* terminating NUL */
1275 ks += sizeof("(|)");
1276
1277 if ( uri->filter.bv_val && uri->filter.bv_len )
1278 ks += uri->filter.bv_len + STRLENOF ("(&)");
1279 kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
1280
1281 if ( uri->filter.bv_val && uri->filter.bv_len ) {
1282 len = snprintf(kp, ks, "(&%s", uri->filter.bv_val);
1283 assert( len >= 0 && len < ks );
1284 kp += len;
1285 }
1286 len = snprintf(kp, ks - (kp - key), "(|");
1287 assert( len >= 0 && len < ks - (kp - key) );
1288 kp += len;
1289
1290 for(m = op->orm_modlist; m; m = m->sml_next)
1291 if ( (m->sml_op & LDAP_MOD_OP)
1292 != LDAP_MOD_DELETE )
1293 kp = build_filter ( domain,
1294 uri,
1295 m->sml_desc,
1296 m->sml_values,
1297 kp,
1298 ks - (kp - key),
1299 op->o_tmpmemctx );
1300
1301 len = snprintf(kp, ks - (kp - key), ")");
1302 assert( len >= 0 && len < ks - (kp - key) );
1303 kp += len;
1304 if ( uri->filter.bv_val && uri->filter.bv_len ) {
1305 len = snprintf (kp, ks - (kp - key), ")");
1306 assert( len >= 0 && len < ks - (kp - key) );
1307 kp += len;
1308 }
1309 bvkey.bv_val = key;
1310 bvkey.bv_len = kp - key;
1311
1312 rc = unique_search ( op,
1313 &nop,
1314 uri->ndn.bv_val ?
1315 &uri->ndn :
1316 &op->o_bd->be_nsuffix[0],
1317 uri->scope,
1318 rs,
1319 &bvkey);
1320
1321 if ( rc != SLAP_CB_CONTINUE ) break;
1322 }
1323 if ( rc != SLAP_CB_CONTINUE ) break;
1324 }
1325
1326 if ( locked ) {
1327 if ( rc != SLAP_CB_CONTINUE ) {
1328 ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
1329 } else {
1330 slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
1331 cb->sc_cleanup = unique_unlock;
1332 cb->sc_private = private;
1333 cb->sc_next = op->o_callback;
1334 op->o_callback = cb;
1335 }
1336 }
1337 return rc;
1338 }
1339
1340
1341 static int
unique_modrdn(Operation * op,SlapReply * rs)1342 unique_modrdn(
1343 Operation *op,
1344 SlapReply *rs
1345 )
1346 {
1347 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1348 unique_data *private = (unique_data *) on->on_bi.bi_private;
1349 unique_domain *domains = private->domains;
1350 unique_domain *legacy = private->legacy;
1351 unique_domain *domain;
1352 Operation nop = *op;
1353 Entry *e = NULL;
1354 char *key, *kp;
1355 struct berval bvkey;
1356 LDAPRDN newrdn;
1357 struct berval bv[2];
1358 int rc = SLAP_CB_CONTINUE;
1359 int locked = 0;
1360
1361 Debug(LDAP_DEBUG_TRACE, "==> unique_modrdn <%s> <%s>\n",
1362 op->o_req_dn.bv_val, op->orr_newrdn.bv_val );
1363
1364 if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) || (
1365 get_relax(op) > SLAP_CONTROL_IGNORED
1366 && overlay_entry_get_ov(op, &op->o_req_ndn, NULL, NULL, 0, &e, on) == LDAP_SUCCESS
1367 && e
1368 && access_allowed( op, e,
1369 slap_schema.si_ad_entry, NULL,
1370 ACL_MANAGE, NULL ) ) ) {
1371 overlay_entry_release_ov( op, e, 0, on );
1372 return rc;
1373 }
1374 if ( e ) {
1375 overlay_entry_release_ov( op, e, 0, on );
1376 }
1377
1378 for ( domain = legacy ? legacy : domains;
1379 domain;
1380 domain = domain->next )
1381 {
1382 unique_domain_uri *uri;
1383
1384 for ( uri = domain->uri;
1385 uri;
1386 uri = uri->next )
1387 {
1388 int i, len;
1389 int ks = 0;
1390
1391 if ( uri->ndn.bv_val
1392 && !dnIsSuffix( &op->o_req_ndn, &uri->ndn )
1393 && (!op->orr_nnewSup
1394 || !dnIsSuffix( op->orr_nnewSup, &uri->ndn )))
1395 continue;
1396
1397 if ( ldap_bv2rdn_x ( &op->oq_modrdn.rs_newrdn,
1398 &newrdn,
1399 (char **)&rs->sr_text,
1400 LDAP_DN_FORMAT_LDAP,
1401 op->o_tmpmemctx ) ) {
1402 op->o_bd->bd_info = (BackendInfo *) on->on_info;
1403 send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
1404 "unknown type(s) used in RDN");
1405 rc = rs->sr_err;
1406 break;
1407 }
1408
1409 rc = SLAP_CB_CONTINUE;
1410 for ( i=0; newrdn[i]; i++) {
1411 AttributeDescription *ad = NULL;
1412 if ( slap_bv2ad( &newrdn[i]->la_attr, &ad, &rs->sr_text )) {
1413 ldap_rdnfree_x( newrdn, op->o_tmpmemctx );
1414 rs->sr_err = LDAP_INVALID_SYNTAX;
1415 send_ldap_result( op, rs );
1416 rc = rs->sr_err;
1417 break;
1418 }
1419 newrdn[i]->la_private = ad;
1420 }
1421 if ( rc != SLAP_CB_CONTINUE ) break;
1422
1423 bv[1].bv_val = NULL;
1424 bv[1].bv_len = 0;
1425
1426 for ( i=0; newrdn[i]; i++ ) {
1427 bv[0] = newrdn[i]->la_value;
1428 ks += count_filter_len ( domain,
1429 uri,
1430 newrdn[i]->la_private,
1431 bv);
1432 }
1433
1434 /* skip this domain if it isn't involved */
1435 if ( !ks ) continue;
1436
1437 if ( domain->serial && !locked ) {
1438 ldap_pvt_thread_mutex_lock( &private->serial_mutex );
1439 locked = 1;
1440 }
1441
1442 /* terminating NUL */
1443 ks += sizeof("(|)");
1444
1445 if ( uri->filter.bv_val && uri->filter.bv_len )
1446 ks += uri->filter.bv_len + STRLENOF ("(&)");
1447 kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
1448
1449 if ( uri->filter.bv_val && uri->filter.bv_len ) {
1450 len = snprintf(kp, ks, "(&%s", uri->filter.bv_val);
1451 assert( len >= 0 && len < ks );
1452 kp += len;
1453 }
1454 len = snprintf(kp, ks - (kp - key), "(|");
1455 assert( len >= 0 && len < ks - (kp - key) );
1456 kp += len;
1457
1458 for ( i=0; newrdn[i]; i++) {
1459 bv[0] = newrdn[i]->la_value;
1460 kp = build_filter ( domain,
1461 uri,
1462 newrdn[i]->la_private,
1463 bv,
1464 kp,
1465 ks - (kp - key ),
1466 op->o_tmpmemctx);
1467 }
1468
1469 len = snprintf(kp, ks - (kp - key), ")");
1470 assert( len >= 0 && len < ks - (kp - key) );
1471 kp += len;
1472 if ( uri->filter.bv_val && uri->filter.bv_len ) {
1473 len = snprintf (kp, ks - (kp - key), ")");
1474 assert( len >= 0 && len < ks - (kp - key) );
1475 kp += len;
1476 }
1477 bvkey.bv_val = key;
1478 bvkey.bv_len = kp - key;
1479
1480 rc = unique_search ( op,
1481 &nop,
1482 uri->ndn.bv_val ?
1483 &uri->ndn :
1484 &op->o_bd->be_nsuffix[0],
1485 uri->scope,
1486 rs,
1487 &bvkey);
1488
1489 if ( rc != SLAP_CB_CONTINUE ) break;
1490 }
1491 if ( rc != SLAP_CB_CONTINUE ) break;
1492 }
1493
1494 if ( locked ) {
1495 if ( rc != SLAP_CB_CONTINUE ) {
1496 ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
1497 } else {
1498 slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
1499 cb->sc_cleanup = unique_unlock;
1500 cb->sc_private = private;
1501 cb->sc_next = op->o_callback;
1502 op->o_callback = cb;
1503 }
1504 }
1505 return rc;
1506 }
1507
1508 /*
1509 ** init_module is last so the symbols resolve "for free" --
1510 ** it expects to be called automagically during dynamic module initialization
1511 */
1512
1513 int
unique_initialize()1514 unique_initialize()
1515 {
1516 int rc;
1517
1518 /* statically declared just after the #includes at top */
1519 memset (&unique, 0, sizeof(unique));
1520
1521 unique.on_bi.bi_type = "unique";
1522 unique.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
1523 unique.on_bi.bi_db_init = unique_db_init;
1524 unique.on_bi.bi_db_destroy = unique_db_destroy;
1525 unique.on_bi.bi_op_add = unique_add;
1526 unique.on_bi.bi_op_modify = unique_modify;
1527 unique.on_bi.bi_op_modrdn = unique_modrdn;
1528
1529 unique.on_bi.bi_cf_ocs = uniqueocs;
1530 rc = config_register_schema( uniquecfg, uniqueocs );
1531 if ( rc ) return rc;
1532
1533 return(overlay_register(&unique));
1534 }
1535
1536 #if SLAPD_OVER_UNIQUE == SLAPD_MOD_DYNAMIC && defined(PIC)
init_module(int argc,char * argv[])1537 int init_module(int argc, char *argv[]) {
1538 return unique_initialize();
1539 }
1540 #endif
1541
1542 #endif /* SLAPD_OVER_UNIQUE */
1543