1 /* schema_check.c - routines to enforce schema definitions */ 2 /* $OpenLDAP: pkg/ldap/servers/slapd/schema_check.c,v 1.103.2.6 2008/04/18 22:33:55 ando Exp $ */ 3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2008 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 17 #include "portable.h" 18 19 #include <stdio.h> 20 21 #include <ac/ctype.h> 22 #include <ac/string.h> 23 #include <ac/socket.h> 24 25 #include "slap.h" 26 27 static char * oc_check_required( 28 Entry *e, 29 ObjectClass *oc, 30 struct berval *ocname ); 31 32 static int entry_naming_check( 33 Entry *e, 34 int manage, 35 int add_naming, 36 const char** text, 37 char *textbuf, size_t textlen ); 38 /* 39 * entry_schema_check - check that entry e conforms to the schema required 40 * by its object class(es). 41 * 42 * returns 0 if so, non-zero otherwise. 43 */ 44 45 int 46 entry_schema_check( 47 Operation *op, 48 Entry *e, 49 Attribute *oldattrs, 50 int manage, 51 int add, 52 const char** text, 53 char *textbuf, size_t textlen ) 54 { 55 Attribute *a, *asc = NULL, *aoc = NULL; 56 ObjectClass *sc, *oc, **socs = NULL; 57 AttributeType *at; 58 ContentRule *cr; 59 int rc, i; 60 AttributeDescription *ad_structuralObjectClass 61 = slap_schema.si_ad_structuralObjectClass; 62 AttributeDescription *ad_objectClass 63 = slap_schema.si_ad_objectClass; 64 int extensible = 0; 65 int subentry = is_entry_subentry( e ); 66 int collectiveSubentry = 0; 67 68 if ( SLAP_NO_SCHEMA_CHECK( op->o_bd )) { 69 return LDAP_SUCCESS; 70 } 71 72 if ( get_no_schema_check( op ) ) { 73 return LDAP_SUCCESS; 74 } 75 76 if( subentry ) { 77 collectiveSubentry = is_entry_collectiveAttributeSubentry( e ); 78 } 79 80 *text = textbuf; 81 82 /* misc attribute checks */ 83 for ( a = e->e_attrs; a != NULL; a = a->a_next ) { 84 const char *type = a->a_desc->ad_cname.bv_val; 85 86 /* there should be at least one value */ 87 assert( a->a_vals != NULL ); 88 assert( a->a_vals[0].bv_val != NULL ); 89 90 if( a->a_desc->ad_type->sat_check ) { 91 rc = (a->a_desc->ad_type->sat_check)( 92 op->o_bd, e, a, text, textbuf, textlen ); 93 if( rc != LDAP_SUCCESS ) { 94 return rc; 95 } 96 } 97 98 if( a->a_desc == ad_structuralObjectClass ) 99 asc = a; 100 else if ( a->a_desc == ad_objectClass ) 101 aoc = a; 102 103 if( !collectiveSubentry && is_at_collective( a->a_desc->ad_type ) ) { 104 snprintf( textbuf, textlen, 105 "'%s' can only appear in collectiveAttributeSubentry", 106 type ); 107 return LDAP_OBJECT_CLASS_VIOLATION; 108 } 109 110 /* if single value type, check for multiple values */ 111 if( is_at_single_value( a->a_desc->ad_type ) && 112 a->a_vals[1].bv_val != NULL ) 113 { 114 snprintf( textbuf, textlen, 115 "attribute '%s' cannot have multiple values", 116 type ); 117 118 Debug( LDAP_DEBUG_ANY, 119 "Entry (%s), %s\n", 120 e->e_dn, textbuf, 0 ); 121 122 return LDAP_CONSTRAINT_VIOLATION; 123 } 124 } 125 126 /* check the object class attribute */ 127 if ( aoc == NULL ) { 128 Debug( LDAP_DEBUG_ANY, "No objectClass for entry (%s)\n", 129 e->e_dn, 0, 0 ); 130 131 *text = "no objectClass attribute"; 132 return LDAP_OBJECT_CLASS_VIOLATION; 133 } 134 135 assert( aoc->a_vals != NULL ); 136 assert( aoc->a_vals[0].bv_val != NULL ); 137 138 /* check the structural object class attribute */ 139 if ( asc == NULL && !add ) { 140 Debug( LDAP_DEBUG_ANY, 141 "No structuralObjectClass for entry (%s)\n", 142 e->e_dn, 0, 0 ); 143 144 *text = "no structuralObjectClass operational attribute"; 145 return LDAP_OTHER; 146 } 147 148 rc = structural_class( aoc->a_vals, &oc, &socs, text, textbuf, textlen, 149 op->o_tmpmemctx ); 150 if( rc != LDAP_SUCCESS ) { 151 return rc; 152 } 153 154 if ( asc == NULL && add ) { 155 attr_merge_one( e, ad_structuralObjectClass, &oc->soc_cname, NULL ); 156 asc = attr_find( e->e_attrs, ad_structuralObjectClass ); 157 sc = oc; 158 goto got_soc; 159 } 160 161 assert( asc->a_vals != NULL ); 162 assert( asc->a_vals[0].bv_val != NULL ); 163 assert( asc->a_vals[1].bv_val == NULL ); 164 165 sc = oc_bvfind( &asc->a_vals[0] ); 166 if( sc == NULL ) { 167 snprintf( textbuf, textlen, 168 "unrecognized structuralObjectClass '%s'", 169 asc->a_vals[0].bv_val ); 170 171 Debug( LDAP_DEBUG_ANY, 172 "entry_check_schema(%s): %s\n", 173 e->e_dn, textbuf, 0 ); 174 175 rc = LDAP_OBJECT_CLASS_VIOLATION; 176 goto done; 177 } 178 179 if( sc->soc_kind != LDAP_SCHEMA_STRUCTURAL ) { 180 snprintf( textbuf, textlen, 181 "structuralObjectClass '%s' is not STRUCTURAL", 182 asc->a_vals[0].bv_val ); 183 184 Debug( LDAP_DEBUG_ANY, 185 "entry_check_schema(%s): %s\n", 186 e->e_dn, textbuf, 0 ); 187 188 rc = LDAP_OTHER; 189 goto done; 190 } 191 192 got_soc: 193 if( !manage && sc->soc_obsolete ) { 194 snprintf( textbuf, textlen, 195 "structuralObjectClass '%s' is OBSOLETE", 196 asc->a_vals[0].bv_val ); 197 198 Debug( LDAP_DEBUG_ANY, 199 "entry_check_schema(%s): %s\n", 200 e->e_dn, textbuf, 0 ); 201 202 rc = LDAP_OBJECT_CLASS_VIOLATION; 203 goto done; 204 } 205 206 *text = textbuf; 207 208 if ( oc == NULL ) { 209 snprintf( textbuf, textlen, 210 "unrecognized objectClass '%s'", 211 aoc->a_vals[0].bv_val ); 212 rc = LDAP_OBJECT_CLASS_VIOLATION; 213 goto done; 214 215 } else if ( sc != slap_schema.si_oc_glue && sc != oc ) { 216 snprintf( textbuf, textlen, 217 "structural object class modification " 218 "from '%s' to '%s' not allowed", 219 asc->a_vals[0].bv_val, oc->soc_cname.bv_val ); 220 rc = LDAP_NO_OBJECT_CLASS_MODS; 221 goto done; 222 } else if ( sc == slap_schema.si_oc_glue ) { 223 sc = oc; 224 } 225 226 /* naming check */ 227 if ( !is_entry_glue ( e ) ) { 228 rc = entry_naming_check( e, manage, add, text, textbuf, textlen ); 229 if( rc != LDAP_SUCCESS ) { 230 goto done; 231 } 232 } else { 233 /* Glue Entry */ 234 } 235 236 /* find the content rule for the structural class */ 237 cr = cr_find( sc->soc_oid ); 238 239 /* the cr must be same as the structural class */ 240 assert( !cr || !strcmp( cr->scr_oid, sc->soc_oid ) ); 241 242 /* check that the entry has required attrs of the content rule */ 243 if( cr ) { 244 if( !manage && cr->scr_obsolete ) { 245 snprintf( textbuf, textlen, 246 "content rule '%s' is obsolete", 247 ldap_contentrule2name( &cr->scr_crule )); 248 249 Debug( LDAP_DEBUG_ANY, 250 "Entry (%s): %s\n", 251 e->e_dn, textbuf, 0 ); 252 253 rc = LDAP_OBJECT_CLASS_VIOLATION; 254 goto done; 255 } 256 257 if( cr->scr_required ) for( i=0; cr->scr_required[i]; i++ ) { 258 at = cr->scr_required[i]; 259 260 for ( a = e->e_attrs; a != NULL; a = a->a_next ) { 261 if( a->a_desc->ad_type == at ) { 262 break; 263 } 264 } 265 266 /* not there => schema violation */ 267 if ( a == NULL ) { 268 snprintf( textbuf, textlen, 269 "content rule '%s' requires attribute '%s'", 270 ldap_contentrule2name( &cr->scr_crule ), 271 at->sat_cname.bv_val ); 272 273 Debug( LDAP_DEBUG_ANY, 274 "Entry (%s): %s\n", 275 e->e_dn, textbuf, 0 ); 276 277 rc = LDAP_OBJECT_CLASS_VIOLATION; 278 goto done; 279 } 280 } 281 282 if( cr->scr_precluded ) for( i=0; cr->scr_precluded[i]; i++ ) { 283 at = cr->scr_precluded[i]; 284 285 for ( a = e->e_attrs; a != NULL; a = a->a_next ) { 286 if( a->a_desc->ad_type == at ) { 287 break; 288 } 289 } 290 291 /* there => schema violation */ 292 if ( a != NULL ) { 293 snprintf( textbuf, textlen, 294 "content rule '%s' precluded attribute '%s'", 295 ldap_contentrule2name( &cr->scr_crule ), 296 at->sat_cname.bv_val ); 297 298 Debug( LDAP_DEBUG_ANY, 299 "Entry (%s): %s\n", 300 e->e_dn, textbuf, 0 ); 301 302 rc = LDAP_OBJECT_CLASS_VIOLATION; 303 goto done; 304 } 305 } 306 } 307 308 /* check that the entry has required attrs for each oc */ 309 for ( i = 0; socs[i]; i++ ) { 310 oc = socs[i]; 311 if ( !manage && oc->soc_obsolete ) { 312 /* disallow obsolete classes */ 313 snprintf( textbuf, textlen, 314 "objectClass '%s' is OBSOLETE", 315 aoc->a_vals[i].bv_val ); 316 317 Debug( LDAP_DEBUG_ANY, 318 "entry_check_schema(%s): %s\n", 319 e->e_dn, textbuf, 0 ); 320 321 rc = LDAP_OBJECT_CLASS_VIOLATION; 322 goto done; 323 } 324 325 if ( oc->soc_check ) { 326 rc = (oc->soc_check)( op->o_bd, e, oc, 327 text, textbuf, textlen ); 328 if( rc != LDAP_SUCCESS ) { 329 goto done; 330 } 331 } 332 333 if ( oc->soc_kind == LDAP_SCHEMA_ABSTRACT ) { 334 /* object class is abstract */ 335 if ( oc != slap_schema.si_oc_top && 336 !is_object_subclass( oc, sc )) 337 { 338 int j; 339 ObjectClass *xc = NULL; 340 for( j=0; socs[j]; j++ ) { 341 if( i != j ) { 342 xc = socs[j]; 343 344 /* since we previous check against the 345 * structural object of this entry, the 346 * abstract class must be a (direct or indirect) 347 * superclass of one of the auxiliary classes of 348 * the entry. 349 */ 350 if ( xc->soc_kind == LDAP_SCHEMA_AUXILIARY && 351 is_object_subclass( oc, xc ) ) 352 { 353 xc = NULL; 354 break; 355 } 356 } 357 } 358 359 if( xc != NULL ) { 360 snprintf( textbuf, textlen, "instantiation of " 361 "abstract objectClass '%s' not allowed", 362 aoc->a_vals[i].bv_val ); 363 364 Debug( LDAP_DEBUG_ANY, 365 "entry_check_schema(%s): %s\n", 366 e->e_dn, textbuf, 0 ); 367 368 rc = LDAP_OBJECT_CLASS_VIOLATION; 369 goto done; 370 } 371 } 372 373 } else if ( oc->soc_kind != LDAP_SCHEMA_STRUCTURAL || oc == sc ) { 374 char *s; 375 376 if( oc->soc_kind == LDAP_SCHEMA_AUXILIARY ) { 377 int k; 378 379 if( cr ) { 380 int j; 381 382 k = -1; 383 if( cr->scr_auxiliaries ) { 384 for( j = 0; cr->scr_auxiliaries[j]; j++ ) { 385 if( cr->scr_auxiliaries[j] == oc ) { 386 k = 0; 387 break; 388 } 389 } 390 } 391 if ( k ) { 392 snprintf( textbuf, textlen, 393 "class '%s' not allowed by content rule '%s'", 394 oc->soc_cname.bv_val, 395 ldap_contentrule2name( &cr->scr_crule ) ); 396 } 397 } else if ( global_disallows & SLAP_DISALLOW_AUX_WO_CR ) { 398 k = -1; 399 snprintf( textbuf, textlen, 400 "class '%s' not allowed by any content rule", 401 oc->soc_cname.bv_val ); 402 } else { 403 k = 0; 404 } 405 406 if( k == -1 ) { 407 Debug( LDAP_DEBUG_ANY, 408 "Entry (%s): %s\n", 409 e->e_dn, textbuf, 0 ); 410 411 rc = LDAP_OBJECT_CLASS_VIOLATION; 412 goto done; 413 } 414 } 415 416 s = oc_check_required( e, oc, &aoc->a_vals[i] ); 417 if (s != NULL) { 418 snprintf( textbuf, textlen, 419 "object class '%s' requires attribute '%s'", 420 aoc->a_vals[i].bv_val, s ); 421 422 Debug( LDAP_DEBUG_ANY, 423 "Entry (%s): %s\n", 424 e->e_dn, textbuf, 0 ); 425 426 rc = LDAP_OBJECT_CLASS_VIOLATION; 427 goto done; 428 } 429 430 if( oc == slap_schema.si_oc_extensibleObject ) { 431 extensible=1; 432 } 433 } 434 } 435 436 if( extensible ) { 437 *text = NULL; 438 rc = LDAP_SUCCESS; 439 goto done; 440 } 441 442 /* check that each attr in the entry is allowed by some oc */ 443 for ( a = e->e_attrs; a != NULL; a = a->a_next ) { 444 rc = LDAP_OBJECT_CLASS_VIOLATION; 445 446 if( cr && cr->scr_required ) { 447 for( i=0; cr->scr_required[i]; i++ ) { 448 if( cr->scr_required[i] == a->a_desc->ad_type ) { 449 rc = LDAP_SUCCESS; 450 break; 451 } 452 } 453 } 454 455 if( rc != LDAP_SUCCESS && cr && cr->scr_allowed ) { 456 for( i=0; cr->scr_allowed[i]; i++ ) { 457 if( cr->scr_allowed[i] == a->a_desc->ad_type ) { 458 rc = LDAP_SUCCESS; 459 break; 460 } 461 } 462 } 463 464 if( rc != LDAP_SUCCESS ) 465 { 466 rc = oc_check_allowed( a->a_desc->ad_type, socs, sc ); 467 } 468 469 if ( rc != LDAP_SUCCESS ) { 470 char *type = a->a_desc->ad_cname.bv_val; 471 472 snprintf( textbuf, textlen, 473 "attribute '%s' not allowed", 474 type ); 475 476 Debug( LDAP_DEBUG_ANY, 477 "Entry (%s), %s\n", 478 e->e_dn, textbuf, 0 ); 479 480 goto done; 481 } 482 } 483 484 *text = NULL; 485 done: 486 slap_sl_free( socs, op->o_tmpmemctx ); 487 return rc; 488 } 489 490 static char * 491 oc_check_required( 492 Entry *e, 493 ObjectClass *oc, 494 struct berval *ocname ) 495 { 496 AttributeType *at; 497 int i; 498 Attribute *a; 499 500 Debug( LDAP_DEBUG_TRACE, 501 "oc_check_required entry (%s), objectClass \"%s\"\n", 502 e->e_dn, ocname->bv_val, 0 ); 503 504 505 /* check for empty oc_required */ 506 if(oc->soc_required == NULL) { 507 return NULL; 508 } 509 510 /* for each required attribute */ 511 for ( i = 0; oc->soc_required[i] != NULL; i++ ) { 512 at = oc->soc_required[i]; 513 /* see if it's in the entry */ 514 for ( a = e->e_attrs; a != NULL; a = a->a_next ) { 515 if( a->a_desc->ad_type == at ) { 516 break; 517 } 518 } 519 /* not there => schema violation */ 520 if ( a == NULL ) { 521 return at->sat_cname.bv_val; 522 } 523 } 524 525 return( NULL ); 526 } 527 528 int oc_check_allowed( 529 AttributeType *at, 530 ObjectClass **socs, 531 ObjectClass *sc ) 532 { 533 int i, j; 534 535 Debug( LDAP_DEBUG_TRACE, 536 "oc_check_allowed type \"%s\"\n", 537 at->sat_cname.bv_val, 0, 0 ); 538 539 /* always allow objectClass attribute */ 540 if ( strcasecmp( at->sat_cname.bv_val, "objectClass" ) == 0 ) { 541 return LDAP_SUCCESS; 542 } 543 544 /* 545 * All operational attributions are allowed by schema rules. 546 */ 547 if( is_at_operational(at) ) { 548 return LDAP_SUCCESS; 549 } 550 551 /* check to see if its allowed by the structuralObjectClass */ 552 if( sc ) { 553 /* does it require the type? */ 554 for ( j = 0; sc->soc_required != NULL && 555 sc->soc_required[j] != NULL; j++ ) 556 { 557 if( at == sc->soc_required[j] ) { 558 return LDAP_SUCCESS; 559 } 560 } 561 562 /* does it allow the type? */ 563 for ( j = 0; sc->soc_allowed != NULL && 564 sc->soc_allowed[j] != NULL; j++ ) 565 { 566 if( at == sc->soc_allowed[j] ) { 567 return LDAP_SUCCESS; 568 } 569 } 570 } 571 572 /* check that the type appears as req or opt in at least one oc */ 573 for ( i = 0; socs[i]; i++ ) { 574 /* if we know about the oc */ 575 ObjectClass *oc = socs[i]; 576 /* extensibleObject allows all */ 577 if ( oc == slap_schema.si_oc_extensibleObject ) { 578 return LDAP_SUCCESS; 579 } 580 if ( oc != NULL && oc->soc_kind != LDAP_SCHEMA_ABSTRACT && 581 ( sc == NULL || oc->soc_kind == LDAP_SCHEMA_AUXILIARY )) 582 { 583 /* does it require the type? */ 584 for ( j = 0; oc->soc_required != NULL && 585 oc->soc_required[j] != NULL; j++ ) 586 { 587 if( at == oc->soc_required[j] ) { 588 return LDAP_SUCCESS; 589 } 590 } 591 /* does it allow the type? */ 592 for ( j = 0; oc->soc_allowed != NULL && 593 oc->soc_allowed[j] != NULL; j++ ) 594 { 595 if( at == oc->soc_allowed[j] ) { 596 return LDAP_SUCCESS; 597 } 598 } 599 } 600 } 601 602 /* not allowed by any oc */ 603 return LDAP_OBJECT_CLASS_VIOLATION; 604 } 605 606 /* 607 * Determine the structural object class from a set of OIDs 608 */ 609 int structural_class( 610 BerVarray ocs, 611 ObjectClass **scp, 612 ObjectClass ***socsp, 613 const char **text, 614 char *textbuf, size_t textlen, 615 void *ctx ) 616 { 617 int i, nocs; 618 ObjectClass *oc, **socs; 619 ObjectClass *sc = NULL; 620 int scn = -1; 621 622 *text = "structural_class: internal error"; 623 624 /* count them */ 625 for( i=0; ocs[i].bv_val; i++ ) ; 626 nocs = i; 627 628 socs = slap_sl_malloc( (nocs+1) * sizeof(ObjectClass *), ctx ); 629 630 for( i=0; ocs[i].bv_val; i++ ) { 631 socs[i] = oc_bvfind( &ocs[i] ); 632 633 if( socs[i] == NULL ) { 634 snprintf( textbuf, textlen, 635 "unrecognized objectClass '%s'", 636 ocs[i].bv_val ); 637 *text = textbuf; 638 goto fail; 639 } 640 } 641 socs[i] = NULL; 642 643 for( i=0; ocs[i].bv_val; i++ ) { 644 oc = socs[i]; 645 if( oc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) { 646 if( sc == NULL || is_object_subclass( sc, oc ) ) { 647 sc = oc; 648 scn = i; 649 650 } else if ( !is_object_subclass( oc, sc ) ) { 651 int j; 652 ObjectClass *xc = NULL; 653 654 /* find common superior */ 655 for( j=i+1; ocs[j].bv_val; j++ ) { 656 xc = socs[j]; 657 658 if( xc == NULL ) { 659 snprintf( textbuf, textlen, 660 "unrecognized objectClass '%s'", 661 ocs[j].bv_val ); 662 *text = textbuf; 663 goto fail; 664 } 665 666 if( xc->soc_kind != LDAP_SCHEMA_STRUCTURAL ) { 667 xc = NULL; 668 continue; 669 } 670 671 if( is_object_subclass( sc, xc ) && 672 is_object_subclass( oc, xc ) ) 673 { 674 /* found common subclass */ 675 break; 676 } 677 678 xc = NULL; 679 } 680 681 if( xc == NULL ) { 682 /* no common subclass */ 683 snprintf( textbuf, textlen, 684 "invalid structural object class chain (%s/%s)", 685 ocs[scn].bv_val, ocs[i].bv_val ); 686 *text = textbuf; 687 goto fail; 688 } 689 } 690 } 691 } 692 693 if( scp ) { 694 *scp = sc; 695 } 696 697 if( sc == NULL ) { 698 *text = "no structural object class provided"; 699 goto fail; 700 } 701 702 if( scn < 0 ) { 703 *text = "invalid structural object class"; 704 goto fail; 705 } 706 707 if ( socsp ) { 708 *socsp = socs; 709 } else { 710 slap_sl_free( socs, ctx ); 711 } 712 *text = NULL; 713 714 return LDAP_SUCCESS; 715 716 fail: 717 slap_sl_free( socs, ctx ); 718 return LDAP_OBJECT_CLASS_VIOLATION; 719 } 720 721 /* 722 * Return structural object class from list of modifications 723 */ 724 int mods_structural_class( 725 Modifications *mods, 726 struct berval *sc, 727 const char **text, 728 char *textbuf, size_t textlen, void *ctx ) 729 { 730 Modifications *ocmod = NULL; 731 ObjectClass *ssc; 732 int rc; 733 734 for( ; mods != NULL; mods = mods->sml_next ) { 735 if( mods->sml_desc == slap_schema.si_ad_objectClass ) { 736 if( ocmod != NULL ) { 737 *text = "entry has multiple objectClass attributes"; 738 return LDAP_OBJECT_CLASS_VIOLATION; 739 } 740 ocmod = mods; 741 } 742 } 743 744 if( ocmod == NULL ) { 745 *text = "entry has no objectClass attribute"; 746 return LDAP_OBJECT_CLASS_VIOLATION; 747 } 748 749 if( ocmod->sml_values == NULL || ocmod->sml_values[0].bv_val == NULL ) { 750 *text = "objectClass attribute has no values"; 751 return LDAP_OBJECT_CLASS_VIOLATION; 752 } 753 754 rc = structural_class( ocmod->sml_values, &ssc, NULL, 755 text, textbuf, textlen, ctx ); 756 if ( rc == LDAP_SUCCESS ) 757 *sc = ssc->soc_cname; 758 return rc; 759 } 760 761 762 static int 763 entry_naming_check( 764 Entry *e, 765 int manage, 766 int add_naming, 767 const char** text, 768 char *textbuf, size_t textlen ) 769 { 770 /* naming check */ 771 LDAPRDN rdn = NULL; 772 const char *p = NULL; 773 ber_len_t cnt; 774 int rc = LDAP_SUCCESS; 775 776 if ( BER_BVISEMPTY( &e->e_name )) { 777 return LDAP_SUCCESS; 778 } 779 780 /* 781 * Get attribute type(s) and attribute value(s) of our RDN 782 */ 783 if ( ldap_bv2rdn( &e->e_name, &rdn, (char **)&p, 784 LDAP_DN_FORMAT_LDAP ) ) 785 { 786 *text = "unrecongized attribute type(s) in RDN"; 787 return LDAP_INVALID_DN_SYNTAX; 788 } 789 790 /* Check that each AVA of the RDN is present in the entry */ 791 /* FIXME: Should also check that each AVA lists a distinct type */ 792 for ( cnt = 0; rdn[cnt]; cnt++ ) { 793 LDAPAVA *ava = rdn[cnt]; 794 AttributeDescription *desc = NULL; 795 Attribute *attr; 796 const char *errtext; 797 int add = 0; 798 799 if( ava->la_flags & LDAP_AVA_BINARY ) { 800 snprintf( textbuf, textlen, 801 "value of naming attribute '%s' in unsupported BER form", 802 ava->la_attr.bv_val ); 803 rc = LDAP_NAMING_VIOLATION; 804 } 805 806 rc = slap_bv2ad( &ava->la_attr, &desc, &errtext ); 807 if ( rc != LDAP_SUCCESS ) { 808 snprintf( textbuf, textlen, "%s (in RDN)", errtext ); 809 break; 810 } 811 812 if( desc->ad_type->sat_usage ) { 813 snprintf( textbuf, textlen, 814 "naming attribute '%s' is operational", 815 ava->la_attr.bv_val ); 816 rc = LDAP_NAMING_VIOLATION; 817 break; 818 } 819 820 if( desc->ad_type->sat_collective ) { 821 snprintf( textbuf, textlen, 822 "naming attribute '%s' is collective", 823 ava->la_attr.bv_val ); 824 rc = LDAP_NAMING_VIOLATION; 825 break; 826 } 827 828 if( !manage && desc->ad_type->sat_obsolete ) { 829 snprintf( textbuf, textlen, 830 "naming attribute '%s' is obsolete", 831 ava->la_attr.bv_val ); 832 rc = LDAP_NAMING_VIOLATION; 833 break; 834 } 835 836 if( !desc->ad_type->sat_equality ) { 837 snprintf( textbuf, textlen, 838 "naming attribute '%s' has no equality matching rule", 839 ava->la_attr.bv_val ); 840 rc = LDAP_NAMING_VIOLATION; 841 break; 842 } 843 844 if( !desc->ad_type->sat_equality->smr_match ) { 845 snprintf( textbuf, textlen, 846 "naming attribute '%s' has unsupported equality matching rule", 847 ava->la_attr.bv_val ); 848 rc = LDAP_NAMING_VIOLATION; 849 break; 850 } 851 852 /* find the naming attribute */ 853 attr = attr_find( e->e_attrs, desc ); 854 if ( attr == NULL ) { 855 snprintf( textbuf, textlen, 856 "naming attribute '%s' is not present in entry", 857 ava->la_attr.bv_val ); 858 if ( add_naming ) { 859 add = 1; 860 861 } else { 862 rc = LDAP_NAMING_VIOLATION; 863 } 864 865 } else { 866 rc = attr_valfind( attr, SLAP_MR_VALUE_OF_ASSERTION_SYNTAX| 867 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, 868 &ava->la_value, NULL, NULL ); 869 870 if( rc != 0 ) { 871 switch( rc ) { 872 case LDAP_INAPPROPRIATE_MATCHING: 873 snprintf( textbuf, textlen, 874 "inappropriate matching for naming attribute '%s'", 875 ava->la_attr.bv_val ); 876 break; 877 case LDAP_INVALID_SYNTAX: 878 snprintf( textbuf, textlen, 879 "value of naming attribute '%s' is invalid", 880 ava->la_attr.bv_val ); 881 break; 882 case LDAP_NO_SUCH_ATTRIBUTE: 883 snprintf( textbuf, textlen, 884 "value of naming attribute '%s' is not present in entry", 885 ava->la_attr.bv_val ); 886 if ( add_naming ) { 887 add = 1; 888 } 889 break; 890 default: 891 snprintf( textbuf, textlen, 892 "naming attribute '%s' is inappropriate", 893 ava->la_attr.bv_val ); 894 } 895 rc = LDAP_NAMING_VIOLATION; 896 } 897 } 898 899 if ( add ) { 900 attr_merge_normalize_one( e, desc, &ava->la_value, NULL ); 901 902 } else if ( rc != LDAP_SUCCESS ) { 903 break; 904 } 905 } 906 907 ldap_rdnfree( rdn ); 908 return rc; 909 } 910 911