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