Back to index

openldap  2.4.31
oc.c
Go to the documentation of this file.
00001 /* oc.c - object class routines */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 
00021 #include <ac/ctype.h>
00022 #include <ac/string.h>
00023 #include <ac/socket.h>
00024 
00025 #include "slap.h"
00026 
00027 int is_object_subclass(
00028        ObjectClass *sup,
00029        ObjectClass *sub )
00030 {
00031        int i;
00032 
00033        if( sub == NULL || sup == NULL ) return 0;
00034 
00035 #if 0
00036        Debug( LDAP_DEBUG_TRACE, "is_object_subclass(%s,%s) %d\n",
00037               sup->soc_oid, sub->soc_oid, sup == sub );
00038 #endif
00039 
00040        if ( sup == sub ) {
00041               return 1;
00042        }
00043 
00044        if ( sub->soc_sups == NULL ) {
00045               return 0;
00046        }
00047 
00048        for ( i = 0; sub->soc_sups[i] != NULL; i++ ) {
00049               if ( is_object_subclass( sup, sub->soc_sups[i] ) ) {
00050                      return 1;
00051               }
00052        }
00053 
00054        return 0;
00055 }
00056 
00057 int is_entry_objectclass(
00058        Entry* e,
00059        ObjectClass *oc,
00060        unsigned flags )
00061 {
00062        /*
00063         * set_flags should only be true if oc is one of operational
00064         * object classes which we support objectClass flags for
00065         * (e.g., referral, alias, ...).  See <slap.h>.
00066         */
00067 
00068        Attribute *attr;
00069        struct berval *bv;
00070 
00071        assert( !( e == NULL || oc == NULL ) );
00072        assert( ( flags & SLAP_OCF_MASK ) != SLAP_OCF_MASK );
00073 
00074        if ( e == NULL || oc == NULL ) {
00075               return 0;
00076        }
00077 
00078        if ( flags == SLAP_OCF_SET_FLAGS && ( e->e_ocflags & SLAP_OC__END ) )
00079        {
00080               /* flags are set, use them */
00081               return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0;
00082        }
00083 
00084        /*
00085         * find objectClass attribute
00086         */
00087        attr = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
00088        if ( attr == NULL ) {
00089               /* no objectClass attribute */
00090               Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") "
00091                      "no objectClass attribute\n",
00092                      e->e_dn == NULL ? "" : e->e_dn,
00093                      oc->soc_oclass.oc_oid, 0 );
00094 
00095               /* mark flags as set */
00096               e->e_ocflags |= SLAP_OC__END;
00097 
00098               return 0;
00099        }
00100 
00101        for ( bv = attr->a_vals; bv->bv_val; bv++ ) {
00102               ObjectClass *objectClass = oc_bvfind( bv );
00103 
00104               if ( objectClass == NULL ) {
00105                      /* FIXME: is this acceptable? */
00106                      continue;
00107               }
00108 
00109               if ( !( flags & SLAP_OCF_SET_FLAGS ) ) {
00110                      if ( objectClass == oc ) {
00111                             return 1;
00112                      }
00113 
00114                      if ( ( flags & SLAP_OCF_CHECK_SUP )
00115                             && is_object_subclass( oc, objectClass ) )
00116                      {
00117                             return 1;
00118                      }
00119               }
00120               
00121               e->e_ocflags |= objectClass->soc_flags;
00122        }
00123 
00124        /* mark flags as set */
00125        e->e_ocflags |= SLAP_OC__END;
00126 
00127        return ( e->e_ocflags & oc->soc_flags & SLAP_OC__MASK ) != 0;
00128 }
00129 
00130 
00131 struct oindexrec {
00132        struct berval oir_name;
00133        ObjectClass   *oir_oc;
00134 };
00135 
00136 static Avlnode       *oc_index = NULL;
00137 static Avlnode       *oc_cache = NULL;
00138 static LDAP_STAILQ_HEAD(OCList, ObjectClass) oc_list
00139        = LDAP_STAILQ_HEAD_INITIALIZER(oc_list);
00140 
00141 ObjectClass *oc_sys_tail;
00142 
00143 static int
00144 oc_index_cmp(
00145        const void *v_oir1,
00146        const void *v_oir2 )
00147 {
00148        const struct oindexrec *oir1 = v_oir1, *oir2 = v_oir2;
00149        int i = oir1->oir_name.bv_len - oir2->oir_name.bv_len;
00150        if (i) return i;
00151        return strcasecmp( oir1->oir_name.bv_val, oir2->oir_name.bv_val );
00152 }
00153 
00154 static int
00155 oc_index_name_cmp(
00156        const void *v_name,
00157        const void *v_oir )
00158 {
00159        const struct berval    *name = v_name;
00160        const struct oindexrec *oir  = v_oir;
00161        int i = name->bv_len - oir->oir_name.bv_len;
00162        if (i) return i;
00163        return strncasecmp( name->bv_val, oir->oir_name.bv_val, name->bv_len );
00164 }
00165 
00166 ObjectClass *
00167 oc_find( const char *ocname )
00168 {
00169        struct berval bv;
00170 
00171        bv.bv_val = (char *)ocname;
00172        bv.bv_len = strlen( ocname );
00173 
00174        return( oc_bvfind( &bv ) );
00175 }
00176 
00177 ObjectClass *
00178 oc_bvfind( struct berval *ocname )
00179 {
00180        struct oindexrec     *oir;
00181 
00182        if ( oc_cache ) {
00183               oir = avl_find( oc_cache, ocname, oc_index_name_cmp );
00184               if ( oir ) return oir->oir_oc;
00185        }
00186        oir = avl_find( oc_index, ocname, oc_index_name_cmp );
00187 
00188        if ( oir != NULL ) {
00189               if ( at_oc_cache ) {
00190                      avl_insert( &oc_cache, (caddr_t) oir,
00191                             oc_index_cmp, avl_dup_error );
00192               }
00193               return( oir->oir_oc );
00194        }
00195 
00196        return( NULL );
00197 }
00198 
00199 static LDAP_STAILQ_HEAD(OCUList, ObjectClass) oc_undef_list
00200        = LDAP_STAILQ_HEAD_INITIALIZER(oc_undef_list);
00201 
00202 ObjectClass *
00203 oc_bvfind_undef( struct berval *ocname )
00204 {
00205        ObjectClass   *oc = oc_bvfind( ocname );
00206 
00207        if ( oc ) {
00208               return oc;
00209        }
00210 
00211        LDAP_STAILQ_FOREACH( oc, &oc_undef_list, soc_next ) {
00212               int    d = oc->soc_cname.bv_len - ocname->bv_len;
00213 
00214               if ( d ) {
00215                      continue;
00216               }
00217 
00218               if ( strcasecmp( oc->soc_cname.bv_val, ocname->bv_val ) == 0 ) {
00219                      break;
00220               }
00221        }
00222        
00223        if ( oc ) {
00224               return oc;
00225        }
00226        
00227        oc = ch_malloc( sizeof( ObjectClass ) + ocname->bv_len + 1 );
00228        memset( oc, 0, sizeof( ObjectClass ) );
00229 
00230        oc->soc_cname.bv_len = ocname->bv_len;
00231        oc->soc_cname.bv_val = (char *)&oc[ 1 ];
00232        AC_MEMCPY( oc->soc_cname.bv_val, ocname->bv_val, ocname->bv_len );
00233        oc->soc_cname.bv_val[ oc->soc_cname.bv_len ] = '\0';
00234 
00235        /* canonical to upper case */
00236        ldap_pvt_str2upper( oc->soc_cname.bv_val );
00237 
00238        LDAP_STAILQ_NEXT( oc, soc_next ) = NULL;
00239        ldap_pvt_thread_mutex_lock( &oc_undef_mutex );
00240        LDAP_STAILQ_INSERT_HEAD( &oc_undef_list, oc, soc_next );
00241        ldap_pvt_thread_mutex_unlock( &oc_undef_mutex );
00242 
00243        return oc;
00244 }
00245 
00246 static int
00247 oc_create_required(
00248        ObjectClass          *soc,
00249        char                 **attrs,
00250        int                  *op,
00251        const char           **err )
00252 {
00253        char          **attrs1;
00254        AttributeType *sat;
00255        AttributeType **satp;
00256        int           i;
00257 
00258        if ( attrs ) {
00259               attrs1 = attrs;
00260               while ( *attrs1 ) {
00261                      sat = at_find(*attrs1);
00262                      if ( !sat ) {
00263                             *err = *attrs1;
00264                             return SLAP_SCHERR_ATTR_NOT_FOUND;
00265                      }
00266 
00267                      if( is_at_operational( sat )) (*op)++;
00268 
00269                      if ( at_find_in_list(sat, soc->soc_required) < 0) {
00270                             if ( at_append_to_list(sat, &soc->soc_required) ) {
00271                                    *err = *attrs1;
00272                                    return SLAP_SCHERR_OUTOFMEM;
00273                             }
00274                      }
00275                      attrs1++;
00276               }
00277               /* Now delete duplicates from the allowed list */
00278               for ( satp = soc->soc_required; *satp; satp++ ) {
00279                      i = at_find_in_list(*satp, soc->soc_allowed);
00280                      if ( i >= 0 ) {
00281                             at_delete_from_list(i, &soc->soc_allowed);
00282                      }
00283               }
00284        }
00285        return 0;
00286 }
00287 
00288 static int
00289 oc_create_allowed(
00290     ObjectClass             *soc,
00291     char             **attrs,
00292        int                  *op,
00293     const char              **err )
00294 {
00295        char          **attrs1;
00296        AttributeType *sat;
00297 
00298        if ( attrs ) {
00299               attrs1 = attrs;
00300               while ( *attrs1 ) {
00301                      sat = at_find(*attrs1);
00302                      if ( !sat ) {
00303                             *err = *attrs1;
00304                             return SLAP_SCHERR_ATTR_NOT_FOUND;
00305                      }
00306 
00307                      if( is_at_operational( sat )) (*op)++;
00308 
00309                      if ( at_find_in_list(sat, soc->soc_required) < 0 &&
00310                           at_find_in_list(sat, soc->soc_allowed) < 0 ) {
00311                             if ( at_append_to_list(sat, &soc->soc_allowed) ) {
00312                                    *err = *attrs1;
00313                                    return SLAP_SCHERR_OUTOFMEM;
00314                             }
00315                      }
00316                      attrs1++;
00317               }
00318        }
00319        return 0;
00320 }
00321 
00322 static int
00323 oc_add_sups(
00324        ObjectClass          *soc,
00325        char                 **sups,
00326        int                  *op,
00327        const char           **err )
00328 {
00329        int           code;
00330        ObjectClass   *soc1;
00331        int           nsups;
00332        char   **sups1;
00333        int           add_sups = 0;
00334 
00335        if ( sups ) {
00336               if ( !soc->soc_sups ) {
00337                      /* We are at the first recursive level */
00338                      add_sups = 1;
00339                      nsups = 1;
00340                      sups1 = sups;
00341                      while ( *sups1 ) {
00342                             nsups++;
00343                             sups1++;
00344                      }
00345                      soc->soc_sups = (ObjectClass **)ch_calloc(nsups,
00346                                      sizeof(ObjectClass *));
00347               }
00348 
00349               nsups = 0;
00350               sups1 = sups;
00351               while ( *sups1 ) {
00352                      soc1 = oc_find(*sups1);
00353                      if ( !soc1 ) {
00354                             *err = *sups1;
00355                             return SLAP_SCHERR_CLASS_NOT_FOUND;
00356                      }
00357 
00358                      /* check object class usage
00359                       * abstract classes can only sup abstract classes 
00360                       * structural classes can not sup auxiliary classes
00361                       * auxiliary classes can not sup structural classes
00362                       */
00363                      if( soc->soc_kind != soc1->soc_kind
00364                             && soc1->soc_kind != LDAP_SCHEMA_ABSTRACT )
00365                      {
00366                             *err = *sups1;
00367                             return SLAP_SCHERR_CLASS_BAD_SUP;
00368                      }
00369 
00370                      if( soc1->soc_obsolete && !soc->soc_obsolete ) {
00371                             *err = *sups1;
00372                             return SLAP_SCHERR_CLASS_BAD_SUP;
00373                      }
00374 
00375                      if( soc->soc_flags & SLAP_OC_OPERATIONAL ) (*op)++;
00376 
00377                      if ( add_sups ) {
00378                             soc->soc_sups[nsups] = soc1;
00379                      }
00380 
00381                      code = oc_add_sups( soc, soc1->soc_sup_oids, op, err );
00382                      if ( code ) return code;
00383 
00384                      code = oc_create_required( soc, soc1->soc_at_oids_must, op, err );
00385                      if ( code ) return code;
00386 
00387                      code = oc_create_allowed( soc, soc1->soc_at_oids_may, op, err );
00388                      if ( code ) return code;
00389 
00390                      nsups++;
00391                      sups1++;
00392               }
00393        }
00394 
00395        return 0;
00396 }
00397 
00398 static void
00399 oc_delete_names( ObjectClass *oc )
00400 {
00401        char                 **names = oc->soc_names;
00402 
00403        if (!names) return;
00404 
00405        while (*names) {
00406               struct oindexrec     tmpoir, *oir;
00407 
00408               ber_str2bv( *names, 0, 0, &tmpoir.oir_name );
00409               tmpoir.oir_oc = oc;
00410               oir = (struct oindexrec *)avl_delete( &oc_index,
00411                      (caddr_t)&tmpoir, oc_index_cmp );
00412               assert( oir != NULL );
00413               ldap_memfree( oir );
00414               names++;
00415        }
00416 }
00417 
00418 /* Mark the ObjectClass as deleted, remove from list, and remove all its
00419  * names from the AVL tree. Leave the OID in the tree.
00420  */
00421 void
00422 oc_delete( ObjectClass *oc )
00423 {
00424        oc->soc_flags |= SLAP_OC_DELETED;
00425 
00426        LDAP_STAILQ_REMOVE(&oc_list, oc, ObjectClass, soc_next);
00427 
00428        oc_delete_names( oc );
00429 }
00430 
00431 static void
00432 oc_clean( ObjectClass *o )
00433 {
00434        if (o->soc_sups) {
00435               ldap_memfree(o->soc_sups);
00436               o->soc_sups = NULL;
00437        }
00438        if (o->soc_required) {
00439               ldap_memfree(o->soc_required);
00440               o->soc_required = NULL;
00441        }
00442        if (o->soc_allowed) {
00443               ldap_memfree(o->soc_allowed);
00444               o->soc_allowed = NULL;
00445        }
00446        if (o->soc_oidmacro) {
00447               ldap_memfree(o->soc_oidmacro);
00448               o->soc_oidmacro = NULL;
00449        }
00450 }
00451 
00452 static void
00453 oc_destroy_one( void *v )
00454 {
00455        struct oindexrec *oir = v;
00456        ObjectClass *o = oir->oir_oc;
00457 
00458        oc_clean( o );
00459        ldap_objectclass_free((LDAPObjectClass *)o);
00460        ldap_memfree(oir);
00461 }
00462 
00463 void
00464 oc_destroy( void )
00465 {
00466        ObjectClass *o;
00467 
00468        while( !LDAP_STAILQ_EMPTY(&oc_list) ) {
00469               o = LDAP_STAILQ_FIRST(&oc_list);
00470               LDAP_STAILQ_REMOVE_HEAD(&oc_list, soc_next);
00471 
00472               oc_delete_names( o );
00473        }
00474        
00475        avl_free( oc_index, oc_destroy_one );
00476 
00477        while( !LDAP_STAILQ_EMPTY(&oc_undef_list) ) {
00478               o = LDAP_STAILQ_FIRST(&oc_undef_list);
00479               LDAP_STAILQ_REMOVE_HEAD(&oc_undef_list, soc_next);
00480 
00481               ch_free( (ObjectClass *)o );
00482        }
00483 }
00484 
00485 int
00486 oc_start( ObjectClass **oc )
00487 {
00488        assert( oc != NULL );
00489 
00490        *oc = LDAP_STAILQ_FIRST(&oc_list);
00491 
00492        return (*oc != NULL);
00493 }
00494 
00495 int
00496 oc_next( ObjectClass **oc )
00497 {
00498        assert( oc != NULL );
00499 
00500 #if 0  /* pedantic check: breaks when deleting an oc, don't use it. */
00501        {
00502               ObjectClass *tmp = NULL;
00503 
00504               LDAP_STAILQ_FOREACH(tmp,&oc_list,soc_next) {
00505                      if ( tmp == *oc ) {
00506                             break;
00507                      }
00508               }
00509 
00510               assert( tmp != NULL );
00511        }
00512 #endif
00513 
00514        if ( *oc == NULL ) {
00515               return 0;
00516        }
00517 
00518        *oc = LDAP_STAILQ_NEXT(*oc,soc_next);
00519 
00520        return (*oc != NULL);
00521 }
00522 
00523 /*
00524  * check whether the two ObjectClasses actually __are__ identical,
00525  * or rather inconsistent
00526  */
00527 static int
00528 oc_check_dup(
00529        ObjectClass   *soc,
00530        ObjectClass   *new_soc )
00531 {
00532        if ( new_soc->soc_oid != NULL ) {
00533               if ( soc->soc_oid == NULL ) {
00534                      return SLAP_SCHERR_CLASS_INCONSISTENT;
00535               }
00536 
00537               if ( strcmp( soc->soc_oid, new_soc->soc_oid ) != 0 ) {
00538                      return SLAP_SCHERR_CLASS_INCONSISTENT;
00539               }
00540 
00541        } else {
00542               if ( soc->soc_oid != NULL ) {
00543                      return SLAP_SCHERR_CLASS_INCONSISTENT;
00544               }
00545        }
00546 
00547        if ( new_soc->soc_names ) {
00548               int    i;
00549 
00550               if ( soc->soc_names == NULL ) {
00551                      return SLAP_SCHERR_CLASS_INCONSISTENT;
00552               }
00553 
00554               for ( i = 0; new_soc->soc_names[ i ]; i++ ) {
00555                      if ( soc->soc_names[ i ] == NULL ) {
00556                             return SLAP_SCHERR_CLASS_INCONSISTENT;
00557                      }
00558                      
00559                      if ( strcasecmp( soc->soc_names[ i ],
00560                                    new_soc->soc_names[ i ] ) != 0 )
00561                      {
00562                             return SLAP_SCHERR_CLASS_INCONSISTENT;
00563                      }
00564               }
00565        } else {
00566               if ( soc->soc_names != NULL ) {
00567                      return SLAP_SCHERR_CLASS_INCONSISTENT;
00568               }
00569        }
00570 
00571        return SLAP_SCHERR_CLASS_DUP;
00572 }
00573 
00574 static struct oindexrec *oir_old;
00575 
00576 static int
00577 oc_dup_error( void *left, void *right )
00578 {
00579        oir_old = left;
00580        return -1;
00581 }
00582 
00583 static int
00584 oc_insert(
00585     ObjectClass             **roc,
00586        ObjectClass          *prev,
00587     const char              **err )
00588 {
00589        struct oindexrec     *oir;
00590        char                 **names;
00591        ObjectClass          *soc = *roc;
00592 
00593        if ( soc->soc_oid ) {
00594               oir = (struct oindexrec *)
00595                      ch_calloc( 1, sizeof(struct oindexrec) );
00596               ber_str2bv( soc->soc_oid, 0, 0, &oir->oir_name );
00597               oir->oir_oc = soc;
00598               oir_old = NULL;
00599 
00600               if ( avl_insert( &oc_index, (caddr_t) oir,
00601                      oc_index_cmp, oc_dup_error ) )
00602               {
00603                      ObjectClass   *old_soc;
00604                      int           rc;
00605 
00606                      *err = soc->soc_oid;
00607 
00608                      assert( oir_old != NULL );
00609                      old_soc = oir_old->oir_oc;
00610 
00611                      /* replacing a deleted definition? */
00612                      if ( old_soc->soc_flags & SLAP_OC_DELETED ) {
00613                             ObjectClass tmp;
00614 
00615                             /* Keep old oid, free new oid;
00616                              * Keep new everything else, free old
00617                              */
00618                             tmp = *old_soc;
00619                             *old_soc = *soc;
00620                             old_soc->soc_oid = tmp.soc_oid;
00621                             tmp.soc_oid = soc->soc_oid;
00622                             *soc = tmp;
00623 
00624                             oc_clean( soc );
00625                             oc_destroy_one( oir );
00626 
00627                             oir = oir_old;
00628                             soc = old_soc;
00629                             *roc = soc;
00630                      } else {
00631                             rc = oc_check_dup( old_soc, soc );
00632 
00633                             ldap_memfree( oir );
00634                             return rc;
00635                      }
00636               }
00637 
00638               /* FIX: temporal consistency check */
00639               assert( oc_bvfind( &oir->oir_name ) != NULL );
00640        }
00641 
00642        assert( soc != NULL );
00643 
00644        if ( (names = soc->soc_names) ) {
00645               while ( *names ) {
00646                      oir = (struct oindexrec *)
00647                             ch_calloc( 1, sizeof(struct oindexrec) );
00648                      oir->oir_name.bv_val = *names;
00649                      oir->oir_name.bv_len = strlen( *names );
00650                      oir->oir_oc = soc;
00651 
00652                      if ( avl_insert( &oc_index, (caddr_t) oir,
00653                             oc_index_cmp, avl_dup_error ) )
00654                      {
00655                             ObjectClass   *old_soc;
00656                             int           rc;
00657 
00658                             *err = *names;
00659 
00660                             old_soc = oc_bvfind( &oir->oir_name );
00661                             assert( old_soc != NULL );
00662                             rc = oc_check_dup( old_soc, soc );
00663 
00664                             ldap_memfree( oir );
00665 
00666                             while ( names > soc->soc_names ) {
00667                                    struct oindexrec     tmpoir;
00668 
00669                                    names--;
00670                                    ber_str2bv( *names, 0, 0, &tmpoir.oir_name );
00671                                    tmpoir.oir_oc = soc;
00672                                    oir = (struct oindexrec *)avl_delete( &oc_index,
00673                                           (caddr_t)&tmpoir, oc_index_cmp );
00674                                    assert( oir != NULL );
00675                                    ldap_memfree( oir );
00676                             }
00677 
00678                             if ( soc->soc_oid ) {
00679                                    struct oindexrec     tmpoir;
00680 
00681                                    ber_str2bv( soc->soc_oid, 0, 0, &tmpoir.oir_name );
00682                                    tmpoir.oir_oc = soc;
00683                                    oir = (struct oindexrec *)avl_delete( &oc_index,
00684                                           (caddr_t)&tmpoir, oc_index_cmp );
00685                                    assert( oir != NULL );
00686                                    ldap_memfree( oir );
00687                             }
00688 
00689                             return rc;
00690                      }
00691 
00692                      /* FIX: temporal consistency check */
00693                      assert( oc_bvfind(&oir->oir_name) != NULL );
00694 
00695                      names++;
00696               }
00697        }
00698        if ( soc->soc_flags & SLAP_OC_HARDCODE ) {
00699               prev = oc_sys_tail;
00700               oc_sys_tail = soc;
00701        }
00702        if ( prev ) {
00703               LDAP_STAILQ_INSERT_AFTER( &oc_list, prev, soc, soc_next );
00704        } else {
00705               LDAP_STAILQ_INSERT_TAIL( &oc_list, soc, soc_next );
00706        }
00707 
00708        return 0;
00709 }
00710 
00711 int
00712 oc_add(
00713     LDAPObjectClass  *oc,
00714        int user,
00715        ObjectClass          **rsoc,
00716        ObjectClass          *prev,
00717     const char              **err )
00718 {
00719        ObjectClass   *soc;
00720        int           code;
00721        int           op = 0;
00722        char   *oidm = NULL;
00723 
00724        if ( oc->oc_names != NULL ) {
00725               int i;
00726 
00727               for( i=0; oc->oc_names[i]; i++ ) {
00728                      if( !slap_valid_descr( oc->oc_names[i] ) ) {
00729                             return SLAP_SCHERR_BAD_DESCR;
00730                      }
00731               }
00732        }
00733 
00734        if ( !OID_LEADCHAR( oc->oc_oid[0] )) {
00735               /* Expand OID macros */
00736               char *oid = oidm_find( oc->oc_oid );
00737               if ( !oid ) {
00738                      *err = oc->oc_oid;
00739                      return SLAP_SCHERR_OIDM;
00740               }
00741               if ( oid != oc->oc_oid ) {
00742                      oidm = oc->oc_oid;
00743                      oc->oc_oid = oid;
00744               }
00745        }
00746 
00747        soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
00748        AC_MEMCPY( &soc->soc_oclass, oc, sizeof(LDAPObjectClass) );
00749 
00750        soc->soc_oidmacro = oidm;
00751        if( oc->oc_names != NULL ) {
00752               soc->soc_cname.bv_val = soc->soc_names[0];
00753        } else {
00754               soc->soc_cname.bv_val = soc->soc_oid;
00755        }
00756        soc->soc_cname.bv_len = strlen( soc->soc_cname.bv_val );
00757 
00758        if( soc->soc_sup_oids == NULL &&
00759               soc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
00760        {
00761               /* structural object classes implicitly inherit from 'top' */
00762               static char *top_oids[] = { SLAPD_TOP_OID, NULL };
00763               code = oc_add_sups( soc, top_oids, &op, err );
00764        } else {
00765               code = oc_add_sups( soc, soc->soc_sup_oids, &op, err );
00766        }
00767 
00768        if ( code != 0 ) {
00769               goto done;
00770        }
00771 
00772        if ( user && op ) {
00773               code = SLAP_SCHERR_CLASS_BAD_SUP;
00774               goto done;
00775        }
00776 
00777        code = oc_create_required( soc, soc->soc_at_oids_must, &op, err );
00778        if ( code != 0 ) {
00779               goto done;
00780        }
00781 
00782        code = oc_create_allowed( soc, soc->soc_at_oids_may, &op, err );
00783        if ( code != 0 ) {
00784               goto done;
00785        }
00786 
00787        if ( user && op ) {
00788               code = SLAP_SCHERR_CLASS_BAD_USAGE;
00789               goto done;
00790        }
00791 
00792        if ( !user ) {
00793               soc->soc_flags |= SLAP_OC_HARDCODE;
00794        }
00795 
00796        code = oc_insert(&soc,prev,err);
00797 done:;
00798        if ( code != 0 ) {
00799               if ( soc->soc_sups ) {
00800                      ch_free( soc->soc_sups );
00801               }
00802 
00803               if ( soc->soc_required ) {
00804                      ch_free( soc->soc_required );
00805               }
00806 
00807               if ( soc->soc_allowed ) {
00808                      ch_free( soc->soc_allowed );
00809               }
00810 
00811               if ( soc->soc_oidmacro ) {
00812                      ch_free( soc->soc_oidmacro );
00813               }
00814 
00815               ch_free( soc );
00816 
00817        } else if ( rsoc ) {
00818               *rsoc = soc;
00819        }
00820        return code;
00821 }
00822 
00823 void
00824 oc_unparse( BerVarray *res, ObjectClass *start, ObjectClass *end, int sys )
00825 {
00826        ObjectClass *oc;
00827        int i, num;
00828        struct berval bv, *bva = NULL, idx;
00829        char ibuf[32];
00830 
00831        if ( !start )
00832               start = LDAP_STAILQ_FIRST( &oc_list );
00833 
00834        /* count the result size */
00835        i = 0;
00836        for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) {
00837               if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) break;
00838               i++;
00839               if ( oc == end ) break;
00840        }
00841        if (!i) return;
00842 
00843        num = i;
00844        bva = ch_malloc( (num+1) * sizeof(struct berval) );
00845        BER_BVZERO( bva );
00846        idx.bv_val = ibuf;
00847        if ( sys ) {
00848               idx.bv_len = 0;
00849               ibuf[0] = '\0';
00850        }
00851        i = 0;
00852        for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) {
00853               LDAPObjectClass loc, *locp;
00854               if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) break;
00855               if ( oc->soc_oidmacro ) {
00856                      loc = oc->soc_oclass;
00857                      loc.oc_oid = oc->soc_oidmacro;
00858                      locp = &loc;
00859               } else {
00860                      locp = &oc->soc_oclass;
00861               }
00862               if ( ldap_objectclass2bv( locp, &bv ) == NULL ) {
00863                      ber_bvarray_free( bva );
00864               }
00865               if ( !sys ) {
00866                      idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
00867               }
00868               bva[i].bv_len = idx.bv_len + bv.bv_len;
00869               bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
00870               strcpy( bva[i].bv_val, ibuf );
00871               strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
00872               i++;
00873               bva[i].bv_val = NULL;
00874               ldap_memfree( bv.bv_val );
00875               if ( oc == end ) break;
00876        }
00877        *res = bva;
00878 }
00879 
00880 int
00881 oc_schema_info( Entry *e )
00882 {
00883        AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses;
00884        ObjectClass   *oc;
00885        struct berval val;
00886        struct berval nval;
00887 
00888        LDAP_STAILQ_FOREACH( oc, &oc_list, soc_next ) {
00889               if( oc->soc_flags & SLAP_OC_HIDE ) continue;
00890 
00891               if ( ldap_objectclass2bv( &oc->soc_oclass, &val ) == NULL ) {
00892                      return -1;
00893               }
00894 
00895               nval = oc->soc_cname;
00896 
00897 #if 0
00898               Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s (%s)\n",
00899               (long) val.bv_len, val.bv_val, nval.bv_val );
00900 #endif
00901 
00902               if( attr_merge_one( e, ad_objectClasses, &val, &nval ) ) {
00903                      return -1;
00904               }
00905               ldap_memfree( val.bv_val );
00906        }
00907        return 0;
00908 }
00909 
00910 int
00911 register_oc( const char *def, ObjectClass **soc, int dupok )
00912 {
00913        LDAPObjectClass *oc;
00914        int code;
00915        const char *err;
00916 
00917        oc = ldap_str2objectclass( def, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
00918        if ( !oc ) {
00919               Debug( LDAP_DEBUG_ANY,
00920                      "register_oc: objectclass \"%s\": %s, %s\n",
00921                      def, ldap_scherr2str(code), err );
00922               return code;
00923        }
00924        code = oc_add(oc,0,NULL,NULL,&err);
00925        if ( code && ( code != SLAP_SCHERR_CLASS_DUP || !dupok )) {
00926               Debug( LDAP_DEBUG_ANY,
00927                      "register_oc: objectclass \"%s\": %s, %s\n",
00928                      def, scherr2str(code), err );
00929               ldap_objectclass_free(oc);
00930               return code;
00931        }
00932        if ( soc )
00933               *soc = oc_find(oc->oc_names[0]);
00934        if ( code ) {
00935               ldap_objectclass_free(oc);
00936        } else {
00937               ldap_memfree(oc);
00938        }
00939        return 0;
00940 }