1/* oc.c - object class routines */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 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 27int is_object_subclass( 28 ObjectClass *sup, 29 ObjectClass *sub ) 30{ 31 int i; 32 33 if( sub == NULL || sup == NULL ) return 0; 34 35#if 0 36 Debug( LDAP_DEBUG_TRACE, "is_object_subclass(%s,%s) %d\n", 37 sup->soc_oid, sub->soc_oid, sup == sub ); 38#endif 39 40 if ( sup == sub ) { 41 return 1; 42 } 43 44 if ( sub->soc_sups == NULL ) { 45 return 0; 46 } 47 48 for ( i = 0; sub->soc_sups[i] != NULL; i++ ) { 49 if ( is_object_subclass( sup, sub->soc_sups[i] ) ) { 50 return 1; 51 } 52 } 53 54 return 0; 55} 56 57int is_entry_objectclass( 58 Entry* e, 59 ObjectClass *oc, 60 unsigned flags ) 61{ 62 /* 63 * set_flags should only be true if oc is one of operational 64 * object classes which we support objectClass flags for 65 * (e.g., referral, alias, ...). See <slap.h>. 66 */ 67 68 Attribute *attr; 69 struct berval *bv; 70 71 assert( !( e == NULL || oc == NULL ) ); 72 assert( ( flags & SLAP_OCF_MASK ) != SLAP_OCF_MASK ); 73 74 if ( e == NULL || oc == NULL ) { 75 return 0; 76 } 77 78 if ( flags == SLAP_OCF_SET_FLAGS && ( e->e_ocflags & SLAP_OC__END ) ) 79 { 80 /* flags are set, use them */ 81 return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0; 82 } 83 84 /* 85 * find objectClass attribute 86 */ 87 attr = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); 88 if ( attr == NULL ) { 89 /* no objectClass attribute */ 90 Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") " 91 "no objectClass attribute\n", 92 e->e_dn == NULL ? "" : e->e_dn, 93 oc->soc_oclass.oc_oid, 0 ); 94 95 /* mark flags as set */ 96 e->e_ocflags |= SLAP_OC__END; 97 98 return 0; 99 } 100 101 for ( bv = attr->a_vals; bv->bv_val; bv++ ) { 102 ObjectClass *objectClass = oc_bvfind( bv ); 103 104 if ( objectClass == NULL ) { 105 /* FIXME: is this acceptable? */ 106 continue; 107 } 108 109 if ( !( flags & SLAP_OCF_SET_FLAGS ) ) { 110 if ( objectClass == oc ) { 111 return 1; 112 } 113 114 if ( ( flags & SLAP_OCF_CHECK_SUP ) 115 && is_object_subclass( oc, objectClass ) ) 116 { 117 return 1; 118 } 119 } 120 121 e->e_ocflags |= objectClass->soc_flags; 122 } 123 124 /* mark flags as set */ 125 e->e_ocflags |= SLAP_OC__END; 126 127 return ( e->e_ocflags & oc->soc_flags & SLAP_OC__MASK ) != 0; 128} 129 130 131struct oindexrec { 132 struct berval oir_name; 133 ObjectClass *oir_oc; 134}; 135 136static Avlnode *oc_index = NULL; 137static Avlnode *oc_cache = NULL; 138static LDAP_STAILQ_HEAD(OCList, ObjectClass) oc_list 139 = LDAP_STAILQ_HEAD_INITIALIZER(oc_list); 140 141ObjectClass *oc_sys_tail; 142 143static int 144oc_index_cmp( 145 const void *v_oir1, 146 const void *v_oir2 ) 147{ 148 const struct oindexrec *oir1 = v_oir1, *oir2 = v_oir2; 149 int i = oir1->oir_name.bv_len - oir2->oir_name.bv_len; 150 if (i) return i; 151 return strcasecmp( oir1->oir_name.bv_val, oir2->oir_name.bv_val ); 152} 153 154static int 155oc_index_name_cmp( 156 const void *v_name, 157 const void *v_oir ) 158{ 159 const struct berval *name = v_name; 160 const struct oindexrec *oir = v_oir; 161 int i = name->bv_len - oir->oir_name.bv_len; 162 if (i) return i; 163 return strncasecmp( name->bv_val, oir->oir_name.bv_val, name->bv_len ); 164} 165 166ObjectClass * 167oc_find( const char *ocname ) 168{ 169 struct berval bv; 170 171 bv.bv_val = (char *)ocname; 172 bv.bv_len = strlen( ocname ); 173 174 return( oc_bvfind( &bv ) ); 175} 176 177ObjectClass * 178oc_bvfind( struct berval *ocname ) 179{ 180 struct oindexrec *oir; 181 182 if ( oc_cache ) { 183 oir = avl_find( oc_cache, ocname, oc_index_name_cmp ); 184 if ( oir ) return oir->oir_oc; 185 } 186 oir = avl_find( oc_index, ocname, oc_index_name_cmp ); 187 188 if ( oir != NULL ) { 189 if ( at_oc_cache ) { 190 avl_insert( &oc_cache, (caddr_t) oir, 191 oc_index_cmp, avl_dup_error ); 192 } 193 return( oir->oir_oc ); 194 } 195 196 return( NULL ); 197} 198 199static LDAP_STAILQ_HEAD(OCUList, ObjectClass) oc_undef_list 200 = LDAP_STAILQ_HEAD_INITIALIZER(oc_undef_list); 201 202ObjectClass * 203oc_bvfind_undef( struct berval *ocname ) 204{ 205 ObjectClass *oc = oc_bvfind( ocname ); 206 207 if ( oc ) { 208 return oc; 209 } 210 211 LDAP_STAILQ_FOREACH( oc, &oc_undef_list, soc_next ) { 212 int d = oc->soc_cname.bv_len - ocname->bv_len; 213 214 if ( d ) { 215 continue; 216 } 217 218 if ( strcasecmp( oc->soc_cname.bv_val, ocname->bv_val ) == 0 ) { 219 break; 220 } 221 } 222 223 if ( oc ) { 224 return oc; 225 } 226 227 oc = ch_malloc( sizeof( ObjectClass ) + ocname->bv_len + 1 ); 228 memset( oc, 0, sizeof( ObjectClass ) ); 229 230 oc->soc_cname.bv_len = ocname->bv_len; 231 oc->soc_cname.bv_val = (char *)&oc[ 1 ]; 232 AC_MEMCPY( oc->soc_cname.bv_val, ocname->bv_val, ocname->bv_len ); 233 oc->soc_cname.bv_val[ oc->soc_cname.bv_len ] = '\0'; 234 235 /* canonical to upper case */ 236 ldap_pvt_str2upper( oc->soc_cname.bv_val ); 237 238 LDAP_STAILQ_NEXT( oc, soc_next ) = NULL; 239 ldap_pvt_thread_mutex_lock( &oc_undef_mutex ); 240 LDAP_STAILQ_INSERT_HEAD( &oc_undef_list, oc, soc_next ); 241 ldap_pvt_thread_mutex_unlock( &oc_undef_mutex ); 242 243 return oc; 244} 245 246static int 247oc_create_required( 248 ObjectClass *soc, 249 char **attrs, 250 int *op, 251 const char **err ) 252{ 253 char **attrs1; 254 AttributeType *sat; 255 AttributeType **satp; 256 int i; 257 258 if ( attrs ) { 259 attrs1 = attrs; 260 while ( *attrs1 ) { 261 sat = at_find(*attrs1); 262 if ( !sat ) { 263 *err = *attrs1; 264 return SLAP_SCHERR_ATTR_NOT_FOUND; 265 } 266 267 if( is_at_operational( sat )) (*op)++; 268 269 if ( at_find_in_list(sat, soc->soc_required) < 0) { 270 if ( at_append_to_list(sat, &soc->soc_required) ) { 271 *err = *attrs1; 272 return SLAP_SCHERR_OUTOFMEM; 273 } 274 } 275 attrs1++; 276 } 277 /* Now delete duplicates from the allowed list */ 278 for ( satp = soc->soc_required; *satp; satp++ ) { 279 i = at_find_in_list(*satp, soc->soc_allowed); 280 if ( i >= 0 ) { 281 at_delete_from_list(i, &soc->soc_allowed); 282 } 283 } 284 } 285 return 0; 286} 287 288static int 289oc_create_allowed( 290 ObjectClass *soc, 291 char **attrs, 292 int *op, 293 const char **err ) 294{ 295 char **attrs1; 296 AttributeType *sat; 297 298 if ( attrs ) { 299 attrs1 = attrs; 300 while ( *attrs1 ) { 301 sat = at_find(*attrs1); 302 if ( !sat ) { 303 *err = *attrs1; 304 return SLAP_SCHERR_ATTR_NOT_FOUND; 305 } 306 307 if( is_at_operational( sat )) (*op)++; 308 309 if ( at_find_in_list(sat, soc->soc_required) < 0 && 310 at_find_in_list(sat, soc->soc_allowed) < 0 ) { 311 if ( at_append_to_list(sat, &soc->soc_allowed) ) { 312 *err = *attrs1; 313 return SLAP_SCHERR_OUTOFMEM; 314 } 315 } 316 attrs1++; 317 } 318 } 319 return 0; 320} 321 322static int 323oc_add_sups( 324 ObjectClass *soc, 325 char **sups, 326 int *op, 327 const char **err ) 328{ 329 int code; 330 ObjectClass *soc1; 331 int nsups; 332 char **sups1; 333 int add_sups = 0; 334 335 if ( sups ) { 336 if ( !soc->soc_sups ) { 337 /* We are at the first recursive level */ 338 add_sups = 1; 339 nsups = 1; 340 sups1 = sups; 341 while ( *sups1 ) { 342 nsups++; 343 sups1++; 344 } 345 soc->soc_sups = (ObjectClass **)ch_calloc(nsups, 346 sizeof(ObjectClass *)); 347 } 348 349 nsups = 0; 350 sups1 = sups; 351 while ( *sups1 ) { 352 soc1 = oc_find(*sups1); 353 if ( !soc1 ) { 354 *err = *sups1; 355 return SLAP_SCHERR_CLASS_NOT_FOUND; 356 } 357 358 /* check object class usage 359 * abstract classes can only sup abstract classes 360 * structural classes can not sup auxiliary classes 361 * auxiliary classes can not sup structural classes 362 */ 363 if( soc->soc_kind != soc1->soc_kind 364 && soc1->soc_kind != LDAP_SCHEMA_ABSTRACT ) 365 { 366 *err = *sups1; 367 return SLAP_SCHERR_CLASS_BAD_SUP; 368 } 369 370 if( soc1->soc_obsolete && !soc->soc_obsolete ) { 371 *err = *sups1; 372 return SLAP_SCHERR_CLASS_BAD_SUP; 373 } 374 375 if( soc->soc_flags & SLAP_OC_OPERATIONAL ) (*op)++; 376 377 if ( add_sups ) { 378 soc->soc_sups[nsups] = soc1; 379 } 380 381 code = oc_add_sups( soc, soc1->soc_sup_oids, op, err ); 382 if ( code ) return code; 383 384 code = oc_create_required( soc, soc1->soc_at_oids_must, op, err ); 385 if ( code ) return code; 386 387 code = oc_create_allowed( soc, soc1->soc_at_oids_may, op, err ); 388 if ( code ) return code; 389 390 nsups++; 391 sups1++; 392 } 393 } 394 395 return 0; 396} 397 398static void 399oc_delete_names( ObjectClass *oc ) 400{ 401 char **names = oc->soc_names; 402 403 while (*names) { 404 struct oindexrec tmpoir, *oir; 405 406 ber_str2bv( *names, 0, 0, &tmpoir.oir_name ); 407 tmpoir.oir_oc = oc; 408 oir = (struct oindexrec *)avl_delete( &oc_index, 409 (caddr_t)&tmpoir, oc_index_cmp ); 410 assert( oir != NULL ); 411 ldap_memfree( oir ); 412 names++; 413 } 414} 415 416/* Mark the ObjectClass as deleted, remove from list, and remove all its 417 * names from the AVL tree. Leave the OID in the tree. 418 */ 419void 420oc_delete( ObjectClass *oc ) 421{ 422 oc->soc_flags |= SLAP_OC_DELETED; 423 424 LDAP_STAILQ_REMOVE(&oc_list, oc, ObjectClass, soc_next); 425 426 oc_delete_names( oc ); 427} 428 429static void 430oc_clean( ObjectClass *o ) 431{ 432 if (o->soc_sups) { 433 ldap_memfree(o->soc_sups); 434 o->soc_sups = NULL; 435 } 436 if (o->soc_required) { 437 ldap_memfree(o->soc_required); 438 o->soc_required = NULL; 439 } 440 if (o->soc_allowed) { 441 ldap_memfree(o->soc_allowed); 442 o->soc_allowed = NULL; 443 } 444 if (o->soc_oidmacro) { 445 ldap_memfree(o->soc_oidmacro); 446 o->soc_oidmacro = NULL; 447 } 448} 449 450static void 451oc_destroy_one( void *v ) 452{ 453 struct oindexrec *oir = v; 454 ObjectClass *o = oir->oir_oc; 455 456 oc_clean( o ); 457 ldap_objectclass_free((LDAPObjectClass *)o); 458 ldap_memfree(oir); 459} 460 461void 462oc_destroy( void ) 463{ 464 ObjectClass *o; 465 466 while( !LDAP_STAILQ_EMPTY(&oc_list) ) { 467 o = LDAP_STAILQ_FIRST(&oc_list); 468 LDAP_STAILQ_REMOVE_HEAD(&oc_list, soc_next); 469 470 oc_delete_names( o ); 471 } 472 473 avl_free( oc_index, oc_destroy_one ); 474 475 while( !LDAP_STAILQ_EMPTY(&oc_undef_list) ) { 476 o = LDAP_STAILQ_FIRST(&oc_undef_list); 477 LDAP_STAILQ_REMOVE_HEAD(&oc_undef_list, soc_next); 478 479 ch_free( (ObjectClass *)o ); 480 } 481} 482 483int 484oc_start( ObjectClass **oc ) 485{ 486 assert( oc != NULL ); 487 488 *oc = LDAP_STAILQ_FIRST(&oc_list); 489 490 return (*oc != NULL); 491} 492 493int 494oc_next( ObjectClass **oc ) 495{ 496 assert( oc != NULL ); 497 498#if 0 /* pedantic check: breaks when deleting an oc, don't use it. */ 499 { 500 ObjectClass *tmp = NULL; 501 502 LDAP_STAILQ_FOREACH(tmp,&oc_list,soc_next) { 503 if ( tmp == *oc ) { 504 break; 505 } 506 } 507 508 assert( tmp != NULL ); 509 } 510#endif 511 512 if ( *oc == NULL ) { 513 return 0; 514 } 515 516 *oc = LDAP_STAILQ_NEXT(*oc,soc_next); 517 518 return (*oc != NULL); 519} 520 521/* 522 * check whether the two ObjectClasses actually __are__ identical, 523 * or rather inconsistent 524 */ 525static int 526oc_check_dup( 527 ObjectClass *soc, 528 ObjectClass *new_soc ) 529{ 530 if ( new_soc->soc_oid != NULL ) { 531 if ( soc->soc_oid == NULL ) { 532 return SLAP_SCHERR_CLASS_INCONSISTENT; 533 } 534 535 if ( strcmp( soc->soc_oid, new_soc->soc_oid ) != 0 ) { 536 return SLAP_SCHERR_CLASS_INCONSISTENT; 537 } 538 539 } else { 540 if ( soc->soc_oid != NULL ) { 541 return SLAP_SCHERR_CLASS_INCONSISTENT; 542 } 543 } 544 545 if ( new_soc->soc_names ) { 546 int i; 547 548 if ( soc->soc_names == NULL ) { 549 return SLAP_SCHERR_CLASS_INCONSISTENT; 550 } 551 552 for ( i = 0; new_soc->soc_names[ i ]; i++ ) { 553 if ( soc->soc_names[ i ] == NULL ) { 554 return SLAP_SCHERR_CLASS_INCONSISTENT; 555 } 556 557 if ( strcasecmp( soc->soc_names[ i ], 558 new_soc->soc_names[ i ] ) != 0 ) 559 { 560 return SLAP_SCHERR_CLASS_INCONSISTENT; 561 } 562 } 563 } else { 564 if ( soc->soc_names != NULL ) { 565 return SLAP_SCHERR_CLASS_INCONSISTENT; 566 } 567 } 568 569 return SLAP_SCHERR_CLASS_DUP; 570} 571 572static struct oindexrec *oir_old; 573 574static int 575oc_dup_error( void *left, void *right ) 576{ 577 oir_old = left; 578 return -1; 579} 580 581static int 582oc_insert( 583 ObjectClass **roc, 584 ObjectClass *prev, 585 const char **err ) 586{ 587 struct oindexrec *oir; 588 char **names; 589 ObjectClass *soc = *roc; 590 591 if ( soc->soc_oid ) { 592 oir = (struct oindexrec *) 593 ch_calloc( 1, sizeof(struct oindexrec) ); 594 ber_str2bv( soc->soc_oid, 0, 0, &oir->oir_name ); 595 oir->oir_oc = soc; 596 oir_old = NULL; 597 598 if ( avl_insert( &oc_index, (caddr_t) oir, 599 oc_index_cmp, oc_dup_error ) ) 600 { 601 ObjectClass *old_soc; 602 int rc; 603 604 *err = soc->soc_oid; 605 606 assert( oir_old != NULL ); 607 old_soc = oir_old->oir_oc; 608 609 /* replacing a deleted definition? */ 610 if ( old_soc->soc_flags & SLAP_OC_DELETED ) { 611 ObjectClass tmp; 612 613 /* Keep old oid, free new oid; 614 * Keep new everything else, free old 615 */ 616 tmp = *old_soc; 617 *old_soc = *soc; 618 old_soc->soc_oid = tmp.soc_oid; 619 tmp.soc_oid = soc->soc_oid; 620 *soc = tmp; 621 622 oc_clean( soc ); 623 oc_destroy_one( oir ); 624 625 oir = oir_old; 626 soc = old_soc; 627 *roc = soc; 628 } else { 629 rc = oc_check_dup( old_soc, soc ); 630 631 ldap_memfree( oir ); 632 return rc; 633 } 634 } 635 636 /* FIX: temporal consistency check */ 637 assert( oc_bvfind( &oir->oir_name ) != NULL ); 638 } 639 640 assert( soc != NULL ); 641 642 if ( (names = soc->soc_names) ) { 643 while ( *names ) { 644 oir = (struct oindexrec *) 645 ch_calloc( 1, sizeof(struct oindexrec) ); 646 oir->oir_name.bv_val = *names; 647 oir->oir_name.bv_len = strlen( *names ); 648 oir->oir_oc = soc; 649 650 if ( avl_insert( &oc_index, (caddr_t) oir, 651 oc_index_cmp, avl_dup_error ) ) 652 { 653 ObjectClass *old_soc; 654 int rc; 655 656 *err = *names; 657 658 old_soc = oc_bvfind( &oir->oir_name ); 659 assert( old_soc != NULL ); 660 rc = oc_check_dup( old_soc, soc ); 661 662 ldap_memfree( oir ); 663 664 while ( names > soc->soc_names ) { 665 struct oindexrec tmpoir; 666 667 names--; 668 ber_str2bv( *names, 0, 0, &tmpoir.oir_name ); 669 tmpoir.oir_oc = soc; 670 oir = (struct oindexrec *)avl_delete( &oc_index, 671 (caddr_t)&tmpoir, oc_index_cmp ); 672 assert( oir != NULL ); 673 ldap_memfree( oir ); 674 } 675 676 if ( soc->soc_oid ) { 677 struct oindexrec tmpoir; 678 679 ber_str2bv( soc->soc_oid, 0, 0, &tmpoir.oir_name ); 680 tmpoir.oir_oc = soc; 681 oir = (struct oindexrec *)avl_delete( &oc_index, 682 (caddr_t)&tmpoir, oc_index_cmp ); 683 assert( oir != NULL ); 684 ldap_memfree( oir ); 685 } 686 687 return rc; 688 } 689 690 /* FIX: temporal consistency check */ 691 assert( oc_bvfind(&oir->oir_name) != NULL ); 692 693 names++; 694 } 695 } 696 if ( soc->soc_flags & SLAP_OC_HARDCODE ) { 697 prev = oc_sys_tail; 698 oc_sys_tail = soc; 699 } 700 if ( prev ) { 701 LDAP_STAILQ_INSERT_AFTER( &oc_list, prev, soc, soc_next ); 702 } else { 703 LDAP_STAILQ_INSERT_TAIL( &oc_list, soc, soc_next ); 704 } 705 706 return 0; 707} 708 709int 710oc_add( 711 LDAPObjectClass *oc, 712 int user, 713 ObjectClass **rsoc, 714 ObjectClass *prev, 715 const char **err ) 716{ 717 ObjectClass *soc; 718 int code; 719 int op = 0; 720 char *oidm = NULL; 721 722 if ( oc->oc_names != NULL ) { 723 int i; 724 725 for( i=0; oc->oc_names[i]; i++ ) { 726 if( !slap_valid_descr( oc->oc_names[i] ) ) { 727 return SLAP_SCHERR_BAD_DESCR; 728 } 729 } 730 } 731 732 if ( !OID_LEADCHAR( oc->oc_oid[0] )) { 733 /* Expand OID macros */ 734 char *oid = oidm_find( oc->oc_oid ); 735 if ( !oid ) { 736 *err = oc->oc_oid; 737 return SLAP_SCHERR_OIDM; 738 } 739 if ( oid != oc->oc_oid ) { 740 oidm = oc->oc_oid; 741 oc->oc_oid = oid; 742 } 743 } 744 745 soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) ); 746 AC_MEMCPY( &soc->soc_oclass, oc, sizeof(LDAPObjectClass) ); 747 748 soc->soc_oidmacro = oidm; 749 if( oc->oc_names != NULL ) { 750 soc->soc_cname.bv_val = soc->soc_names[0]; 751 } else { 752 soc->soc_cname.bv_val = soc->soc_oid; 753 } 754 soc->soc_cname.bv_len = strlen( soc->soc_cname.bv_val ); 755 756 if( soc->soc_sup_oids == NULL && 757 soc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) 758 { 759 /* structural object classes implicitly inherit from 'top' */ 760 static char *top_oids[] = { SLAPD_TOP_OID, NULL }; 761 code = oc_add_sups( soc, top_oids, &op, err ); 762 } else { 763 code = oc_add_sups( soc, soc->soc_sup_oids, &op, err ); 764 } 765 766 if ( code != 0 ) { 767 goto done; 768 } 769 770 if ( user && op ) { 771 code = SLAP_SCHERR_CLASS_BAD_SUP; 772 goto done; 773 } 774 775 code = oc_create_required( soc, soc->soc_at_oids_must, &op, err ); 776 if ( code != 0 ) { 777 goto done; 778 } 779 780 code = oc_create_allowed( soc, soc->soc_at_oids_may, &op, err ); 781 if ( code != 0 ) { 782 goto done; 783 } 784 785 if ( user && op ) { 786 code = SLAP_SCHERR_CLASS_BAD_USAGE; 787 goto done; 788 } 789 790 if ( !user ) { 791 soc->soc_flags |= SLAP_OC_HARDCODE; 792 } 793 794 code = oc_insert(&soc,prev,err); 795done:; 796 if ( code != 0 ) { 797 if ( soc->soc_sups ) { 798 ch_free( soc->soc_sups ); 799 } 800 801 if ( soc->soc_required ) { 802 ch_free( soc->soc_required ); 803 } 804 805 if ( soc->soc_allowed ) { 806 ch_free( soc->soc_allowed ); 807 } 808 809 if ( soc->soc_oidmacro ) { 810 ch_free( soc->soc_oidmacro ); 811 } 812 813 ch_free( soc ); 814 815 } else if ( rsoc ) { 816 *rsoc = soc; 817 } 818 return code; 819} 820 821void 822oc_unparse( BerVarray *res, ObjectClass *start, ObjectClass *end, int sys ) 823{ 824 ObjectClass *oc; 825 int i, num; 826 struct berval bv, *bva = NULL, idx; 827 char ibuf[32]; 828 829 if ( !start ) 830 start = LDAP_STAILQ_FIRST( &oc_list ); 831 832 /* count the result size */ 833 i = 0; 834 for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) { 835 if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) break; 836 i++; 837 if ( oc == end ) break; 838 } 839 if (!i) return; 840 841 num = i; 842 bva = ch_malloc( (num+1) * sizeof(struct berval) ); 843 BER_BVZERO( bva ); 844 idx.bv_val = ibuf; 845 if ( sys ) { 846 idx.bv_len = 0; 847 ibuf[0] = '\0'; 848 } 849 i = 0; 850 for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) { 851 LDAPObjectClass loc, *locp; 852 if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) break; 853 if ( oc->soc_oidmacro ) { 854 loc = oc->soc_oclass; 855 loc.oc_oid = oc->soc_oidmacro; 856 locp = &loc; 857 } else { 858 locp = &oc->soc_oclass; 859 } 860 if ( ldap_objectclass2bv( locp, &bv ) == NULL ) { 861 ber_bvarray_free( bva ); 862 } 863 if ( !sys ) { 864 idx.bv_len = sprintf(idx.bv_val, "{%d}", i); 865 } 866 bva[i].bv_len = idx.bv_len + bv.bv_len; 867 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 ); 868 strcpy( bva[i].bv_val, ibuf ); 869 strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val ); 870 i++; 871 bva[i].bv_val = NULL; 872 ldap_memfree( bv.bv_val ); 873 if ( oc == end ) break; 874 } 875 *res = bva; 876} 877 878int 879oc_schema_info( Entry *e ) 880{ 881 AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses; 882 ObjectClass *oc; 883 struct berval val; 884 struct berval nval; 885 886 LDAP_STAILQ_FOREACH( oc, &oc_list, soc_next ) { 887 if( oc->soc_flags & SLAP_OC_HIDE ) continue; 888 889 if ( ldap_objectclass2bv( &oc->soc_oclass, &val ) == NULL ) { 890 return -1; 891 } 892 893 nval = oc->soc_cname; 894 895#if 0 896 Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s (%s)\n", 897 (long) val.bv_len, val.bv_val, nval.bv_val ); 898#endif 899 900 if( attr_merge_one( e, ad_objectClasses, &val, &nval ) ) { 901 return -1; 902 } 903 ldap_memfree( val.bv_val ); 904 } 905 return 0; 906} 907 908int 909register_oc( const char *def, ObjectClass **soc, int dupok ) 910{ 911 LDAPObjectClass *oc; 912 int code; 913 const char *err; 914 915 oc = ldap_str2objectclass( def, &code, &err, LDAP_SCHEMA_ALLOW_ALL ); 916 if ( !oc ) { 917 Debug( LDAP_DEBUG_ANY, 918 "register_oc: objectclass \"%s\": %s, %s\n", 919 def, ldap_scherr2str(code), err ); 920 return code; 921 } 922 code = oc_add(oc,0,NULL,NULL,&err); 923 if ( code && ( code != SLAP_SCHERR_CLASS_DUP || !dupok )) { 924 Debug( LDAP_DEBUG_ANY, 925 "register_oc: objectclass \"%s\": %s, %s\n", 926 def, scherr2str(code), err ); 927 ldap_objectclass_free(oc); 928 return code; 929 } 930 if ( soc ) 931 *soc = oc_find(oc->oc_names[0]); 932 if ( code ) { 933 ldap_objectclass_free(oc); 934 } else { 935 ldap_memfree(oc); 936 } 937 return 0; 938} 939