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