summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/schemaparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/slapd/schemaparse.c')
-rw-r--r--ldap/servers/slapd/schemaparse.c262
1 files changed, 262 insertions, 0 deletions
diff --git a/ldap/servers/slapd/schemaparse.c b/ldap/servers/slapd/schemaparse.c
new file mode 100644
index 00000000..c6fb51fe
--- /dev/null
+++ b/ldap/servers/slapd/schemaparse.c
@@ -0,0 +1,262 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* schemaparse.c - routines to support objectclass definitions */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "slap.h"
+
+
+/* global_oc and global_schema_csn are both protected by oc locks */
+struct objclass *global_oc;
+CSN *global_schema_csn = NULL; /* Timestamp for last update CSN. NULL = epoch */
+
+static int is_duplicate( char *target, char **list, int list_max );
+static void normalize_list( char **list );
+
+
+
+/* R/W lock used to protect the global objclass linked list. */
+static PRRWLock *oc_lock = NULL;
+
+/*
+ * The oc_init_lock_callonce structure is used by NSPR to ensure
+ * that oc_init_lock() is called at most once.
+ */
+static PRCallOnceType oc_init_lock_callonce = { 0, 0, 0 };
+
+
+/* Create the objectclass read/write lock. Returns PRSuccess if successful */
+static PRStatus
+oc_init_lock( void )
+{
+ if ( NULL == ( oc_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
+ "objectclass rwlock" ))) {
+ slapi_log_error( SLAPI_LOG_FATAL, "oc_init_lock",
+ "PR_NewRWLock() for objectclass lock failed\n" );
+ return PR_FAILURE;
+ }
+
+ return PR_SUCCESS;
+}
+
+
+void
+oc_lock_read( void )
+{
+ if ( NULL != oc_lock ||
+ PR_SUCCESS == PR_CallOnce( &oc_init_lock_callonce, oc_init_lock )) {
+ PR_RWLock_Rlock( oc_lock );
+ }
+}
+
+
+void
+oc_lock_write( void )
+{
+ if ( NULL != oc_lock ||
+ PR_SUCCESS == PR_CallOnce( &oc_init_lock_callonce, oc_init_lock )) {
+ PR_RWLock_Wlock( oc_lock );
+ }
+}
+
+
+void
+oc_unlock( void )
+{
+ if ( oc_lock != NULL ) {
+ PR_RWLock_Unlock( oc_lock );
+ }
+}
+
+
+/*
+ * Note: callers of g_get_global_oc_nolock() must hold a read or write lock
+ */
+struct objclass* g_get_global_oc_nolock()
+{
+ return global_oc;
+}
+
+/*
+ * Note: callers of g_set_global_oc_nolock() must hold a write lock
+ */
+void
+g_set_global_oc_nolock( struct objclass *newglobaloc )
+{
+ global_oc = newglobaloc;
+}
+
+/*
+ * Note: callers of g_get_global_schema_csn() must hold a read lock
+ */
+const CSN *
+g_get_global_schema_csn()
+{
+ return global_schema_csn;
+}
+
+/*
+ * Note: callers of g_set_global_schema_csn() must hold a write lock.
+ * csn is consumed.
+ */
+void
+g_set_global_schema_csn(CSN *csn)
+{
+ CSN *tmp = NULL;
+ if (NULL != global_schema_csn)
+ {
+ tmp = global_schema_csn;
+ }
+ global_schema_csn = csn;
+ if (NULL != tmp)
+ {
+ csn_free(&tmp);
+ }
+}
+
+/*
+ * There are two kinds of objectclasses:
+ * Standard Objectclasses and User Defined Objectclasses
+ *
+ * Standard Objectclasses are the objectclasses which come with the Directory Server.
+ * These objectclasses are always expected to be there and shouldn't be accidentally
+ * changed by the end user. We dont' allow these objectclasses to be deleted, and the
+ * admin CGIs will not allow the end user to change their definitions. However, we
+ * will allow these objectclasses to be redefined via ldap_modify, by doing an LDAP_MOD_ADD.
+ * The new definition will override the previous definition. The updated objectclass
+ * will be written out the 00user.ldif and the original definition will stay
+ * whereever it was originally defined. At startup, slapd will use the last definition
+ * read as the real definition of an objectclass.
+ *
+ * User Defined ObjectClasses are objectclasses which were added to the Directory Server
+ * by the end user. These objectclasses are also kept in 99user.ldif. These objectclasses
+ * can be deleted by the end user.
+ *
+ * Every objectclass contains an array of attributes called oc_orig_required,
+ * which are the required attributes for that objectclass which were not inherited from
+ * any other objectclass. Likewise, there's also an array called oc_orig_allowed which
+ * contains the allowed attributes which were not inherited from any other objectclass.
+ *
+ * The arrays oc_required and oc_allowed contain all the required and allowed attributes for
+ * that objectclass, including the ones inherited from its parent and also the ones in
+ * oc_orig_required and oc_orig_allowed.
+ *
+ * When an oc is updated, we go through the global list of objectclasses and see if
+ * any ocs inherited from it. If so, we delete its oc_required and oc_allowed arrays,
+ * copy the oc_orig_required and oc_orig_allowed arrays to oc_required and oc_allowed,
+ * and then merge the parent's oc_required and oc_allowed onto oc_required and oc_allowed.
+ *
+ *
+ */
+
+
+static int
+is_duplicate( char *target, char **list, int list_size ) {
+ int i;
+ for ( i = 0; i < list_size; i++ ) {
+ if ( !strcasecmp( target, list[i] ) ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Make normalized copies of all non-duplicate values in a list; free all old
+ * values. The list is not resized.
+ */
+static void
+normalize_list( char **list ) {
+ int i, j;
+
+ for ( i = 0, j = 0; list != NULL && list[i] != NULL; i++ ) {
+ char *norm = slapi_attr_syntax_normalize( list[i] );
+ char *save = list[i];
+ if ( !is_duplicate( norm, list, j ) ) {
+ list[j++] = norm;
+ } else {
+ slapi_ch_free((void **)&norm );
+ }
+ slapi_ch_free((void**)&save );
+ }
+ for ( ; j < i; j++ ) {
+ list[j] = NULL;
+ }
+}
+
+/*
+ * normalize types contained in object class definitions. do this
+ * after the whole config file is read so there is no order dependency
+ * on inclusion of attributes and object classes.
+ */
+
+void
+normalize_oc( void )
+{
+ struct objclass *oc;
+
+ oc_lock_write();
+
+ for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
+ LDAPDebug (LDAP_DEBUG_PARSE,
+ "normalize_oc: normalizing '%s'\n", oc->oc_name, 0, 0);
+ /* required attributes */
+ normalize_list( oc->oc_required );
+ normalize_list( oc->oc_orig_required );
+
+ /* optional attributes */
+ normalize_list( oc->oc_allowed );
+ normalize_list( oc->oc_orig_allowed );
+ }
+
+ oc_unlock();
+}
+
+/*
+ * oc_update_inheritance_nolock:
+ * If an objectclass is redefined, we need to make sure that any objectclasses
+ * which inherit from the redefined objectclass have their required and allowed
+ * attributes updated.
+ *
+ * Every objectclass contains an array of attributes called oc_orig_required,
+ * which are the required attributes for that objectclass which were not inherited from
+ * any other objectclass. Likewise, there's also an array called oc_orig_allowed which
+ * contains the allowed attributes which were not inherited from any other objectclass.
+ *
+ * The arrays oc_required and oc_allowed contain all the required and allowed attributes for
+ * that objectclass, including the ones inherited from its parent and also the ones in
+ * oc_orig_required and oc_orig_allowed.
+ *
+ * When an oc is updated, we go through the global list of objectclasses and see if
+ * any ocs inherited from it. If so, we delete its oc_requried and oc_allowed arrays,
+ * copy the oc_orig_required and oc_orig_allowed arrays to oc_required and oc_allowed,
+ * and then merge the parent's oc_required and oc_allowed onto oc_required and oc_allowed.
+ */
+
+void
+oc_update_inheritance_nolock( struct objclass *psuperior_oc )
+{
+ struct objclass *oc;
+
+ for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
+ if ( oc->oc_superior &&
+ (strcasecmp( oc->oc_superior, psuperior_oc->oc_name ) == 0) ) {
+ if (oc->oc_required ) {
+ charray_free (oc->oc_required);
+ }
+ if (oc->oc_allowed) {
+ charray_free (oc->oc_allowed);
+ }
+ oc->oc_required = charray_dup ( oc->oc_orig_required );
+ oc->oc_allowed = charray_dup ( oc->oc_orig_allowed );
+ charray_merge ( &(oc->oc_required), psuperior_oc->oc_required, 1 );
+ charray_merge ( &(oc->oc_allowed), psuperior_oc->oc_allowed, 1 );
+ oc_update_inheritance_nolock ( oc );
+ }
+ }
+}