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