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