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