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