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