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