ldap/servers/slapd/attrsyntax.c | 50 - ldap/servers/slapd/charray.c | 9 ldap/servers/slapd/proto-slap.h | 10 ldap/servers/slapd/schema.c | 1776 ++++++++++++++++++++++++++++---------- ldap/servers/slapd/slap.h | 40 ldap/servers/slapd/slapi-plugin.h | 15 6 files changed, 1397 insertions(+), 503 deletions(-)
New commits: commit 305dac5202b43448069ce7fa9715f62dab2b10bd Author: Mark Reynolds mreynolds@redhat.com Date: Tue Apr 30 11:49:54 2013 -0400
Ticket 153 - use openldap's schema parser
Bug Description: After running ol-schema-migrate.pl(which converts openldap schema to 389 DS schema format), 389 still doesn't parse the schema correctly as it expects the syntax to be in a certain order.
Fix Description: First, instead of only recording the "X-ORIGIN" values, I have created a linked list for all the schema extensions, not just "X-ORIGIN". Then on systems that have openldap, we use the openldap schema parser. On systems that only have mozldap, we use the old parser.
Also did some code cleanup.
https://fedorahosted.org/389/ticket/153
Reviewed by: richm(Thanks!)
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c index 4326f03..05aca7d 100644 --- a/ldap/servers/slapd/attrsyntax.c +++ b/ldap/servers/slapd/attrsyntax.c @@ -208,7 +208,7 @@ attr_syntax_free( struct asyntaxinfo *a ) slapi_ch_free( (void **)&a->asi_mr_equality ); slapi_ch_free( (void **)&a->asi_mr_ordering ); slapi_ch_free( (void **)&a->asi_mr_substring ); - cool_charray_free( a->asi_origin ); + schema_free_extensions(a->asi_extensions); slapi_ch_free( (void **) &a ); }
@@ -584,7 +584,7 @@ attr_syntax_dup( struct asyntaxinfo *a ) newas->asi_mr_equality = slapi_ch_strdup( a->asi_mr_equality ); newas->asi_mr_ordering = slapi_ch_strdup( a->asi_mr_ordering ); newas->asi_mr_substring = slapi_ch_strdup( a->asi_mr_substring ); - newas->asi_origin = cool_charray_dup( a->asi_origin ); + newas->asi_extensions = schema_copy_extensions( a->asi_extensions ); newas->asi_plugin = a->asi_plugin; newas->asi_flags = a->asi_flags; newas->asi_oid = slapi_ch_strdup( a->asi_oid); @@ -622,9 +622,9 @@ attr_syntax_add( struct asyntaxinfo *asip ) goto cleanup_and_return; } } - - /* make sure the primary name is unique OR, if override is allowed, that - * the primary name and OID point to the same schema definition. + /* + * Make sure the primary name is unique OR, if override is allowed, that + * the primary name and OID point to the same schema definition. */ if ( NULL != ( oldas_from_name = attr_syntax_get_by_name_locking_optional( asip->asi_name, !nolock))) { @@ -687,23 +687,22 @@ cleanup_and_return: */ int attr_syntax_create( - const char *attr_oid, - char *const *attr_names, - int num_names, - const char *attr_desc, - const char *attr_superior, - const char *mr_equality, - const char *mr_ordering, - const char *mr_substring, - char *const *attr_origins, - const char *attr_syntax, - int syntaxlength, + const char *attr_oid, + char *const *attr_names, + const char *attr_desc, + const char *attr_superior, + const char *mr_equality, + const char *mr_ordering, + const char *mr_substring, + schemaext *extensions, + const char *attr_syntax, + int syntaxlength, unsigned long flags, struct asyntaxinfo **asip ) { - char *s; - struct asyntaxinfo a; + char *s; + struct asyntaxinfo a; int rc = LDAP_SUCCESS;
/* XXXmcs: had to cast away const in many places below */ @@ -719,7 +718,7 @@ attr_syntax_create( a.asi_mr_equality = (char*)mr_equality; a.asi_mr_ordering = (char*)mr_ordering; a.asi_mr_substring = (char*)mr_substring; - a.asi_origin = (char **)attr_origins; + a.asi_extensions = extensions; a.asi_plugin = plugin_syntax_find( attr_syntax ); a.asi_syntaxlength = syntaxlength; /* ideally, we would report an error and fail to start if there was some problem @@ -905,6 +904,8 @@ attr_syntax_printnode(PLHashEntry *he, PRIntn i, void *arg) { char *alias = (char *)he->key; struct asyntaxinfo *a = (struct asyntaxinfo *)he->value; + schemaext *ext = a->asi_extensions; + printf( " name: %s\n", a->asi_name ); printf( "\t flags : 0x%x\n", a->asi_flags ); printf( "\t alias : %s\n", alias ); @@ -914,10 +915,11 @@ attr_syntax_printnode(PLHashEntry *he, PRIntn i, void *arg) printf( "\t mr_equality : %s\n", a->asi_mr_equality ); printf( "\t mr_ordering : %s\n", a->asi_mr_ordering ); printf( "\t mr_substring: %s\n", a->asi_mr_substring ); - if ( NULL != a->asi_origin ) { - for ( i = 0; NULL != a->asi_origin[i]; ++i ) { - printf( "\t origin : %s\n", a->asi_origin[i] ); + while( ext ) { + for ( i = 0; ext->values && ext->values[i]; i++ ) { + printf( "\t %s : %s\n", ext->term, ext->values[i]); } + ext = ext->next; } printf( "\tplugin: %p\n", a->asi_plugin ); printf( "--------------\n" ); @@ -1236,11 +1238,11 @@ slapi_add_internal_attr_syntax( const char *name, const char *oid, origins[0] = SLAPD_VERSION_STR; origins[1] = NULL;
- rc = attr_syntax_create( oid, names, 1, + rc = attr_syntax_create( oid, names, "internal server defined attribute type", NULL, /* superior */ mr_equality, NULL, NULL, /* matching rules */ - origins, syntax, + NULL, syntax, SLAPI_SYNTAXLENGTH_NONE, std_flags | extraflags, &asip ); diff --git a/ldap/servers/slapd/charray.c b/ldap/servers/slapd/charray.c index 7df9a08..f86ddc2 100644 --- a/ldap/servers/slapd/charray.c +++ b/ldap/servers/slapd/charray.c @@ -56,6 +56,13 @@ charray_add( char *s ) { + slapi_ch_array_add_ext(a, s); +} + +/* return the total number of elements that are now in the array */ +int +slapi_ch_array_add_ext(char ***a, char *s) +{ int n;
if ( *a == NULL ) { @@ -81,10 +88,10 @@ charray_add( #endif
/* Putting code back so that thread conflict can be made visible */ - (*a)[n++] = s; (*a)[n] = NULL;
+ return n; }
void diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index 10dec7a..9fe26ff 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -121,11 +121,10 @@ int attr_syntax_exists (const char *attr_name); void attr_syntax_delete ( struct asyntaxinfo *asip ); #define SLAPI_SYNTAXLENGTH_NONE (-1) /* for syntaxlength parameter */ int attr_syntax_create( const char *attr_oid, char *const*attr_names, - int num_names, const char *attr_desc, const char *attr_superior, + const char *attr_desc, const char *attr_superior, const char *mr_equality, const char *mr_ordering, - const char *mr_substring, char *const *attr_origins, - const char *attr_syntax, int syntaxlength, unsigned long flags, - struct asyntaxinfo **asip ); + const char *mr_substring, schemaext *extensions, const char *attr_syntax, + int syntaxlength, unsigned long flags, struct asyntaxinfo **asip ); void attr_syntax_free( struct asyntaxinfo *a ); int attr_syntax_add( struct asyntaxinfo *asip ); char *attr_syntax_normalize_no_lookup( const char *s ); @@ -1000,7 +999,8 @@ void slapi_schema_expand_objectclasses( Slapi_Entry *e ); int slapi_validate_schema_files(char *schemadir); /* API to reload the schema files */ int slapi_reload_schema_files(char *schemadir); - +void schema_free_extensions(schemaext *extensions); +schemaext *schema_copy_extensions(schemaext *extensions); /* * schemaparse.c */ diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c index dc56534..7b33593 100644 --- a/ldap/servers/slapd/schema.c +++ b/ldap/servers/slapd/schema.c @@ -51,17 +51,18 @@ #include <plhash.h> #include "slap.h"
+#if defined(USE_OPENLDAP) +#include <ldap_schema.h> /* openldap schema parser */ +#endif + typedef struct sizedbuffer { char *buffer; size_t size; } sizedbuffer;
- typedef char *(*schema_strstr_fn_t)( const char *big, const char *little);
- - /* * The schema_oc_kind_strings array is indexed by oc_kind values, i.e., * OC_KIND_STRUCTURAL (0), OC_KIND_AUXILIARY (1), or OC_KIND_ABSTRACT (2). @@ -69,9 +70,9 @@ typedef char *(*schema_strstr_fn_t)( const char *big, const char *little); */ #define SCHEMA_OC_KIND_COUNT 3 static char *schema_oc_kind_strings_with_spaces[] = { + " ABSTRACT ", " STRUCTURAL ", " AUXILIARY ", - " ABSTRACT ", };
/* constant strings (used in a few places) */ @@ -96,7 +97,6 @@ static int oc_delete_nolock (char *ocname); static int oc_replace_nolock(const char *ocname, struct objclass *newoc); static int oc_check_required(Slapi_PBlock *, Slapi_Entry *,struct objclass *); static int oc_check_allowed_sv(Slapi_PBlock *, Slapi_Entry *e, const char *type, struct objclass **oclist ); -static char **read_dollar_values ( char *vals); static int schema_delete_objectclasses ( Slapi_Entry *entryBefore, LDAPMod *mod, char *errorbuf, size_t errorbufsize, int schema_ds4x_compat ); @@ -110,9 +110,6 @@ static int schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf, size_t errorbufsize ); static int schema_replace_objectclasses ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf, size_t errorbufsize ); -static int read_oc_ldif ( const char *input, struct objclass **oc, - char *errorbuf, size_t errorbufsize, PRUint32 flags, int is_user_defined, - int schema_ds4x_compat ); static int schema_check_name(char *name, PRBool isAttribute, char *errorbuf, size_t errorbufsize ); static int schema_check_oid(const char *name, const char *oid, @@ -120,27 +117,14 @@ static int schema_check_oid(const char *name, const char *oid, static int isExtensibleObjectclass(const char *objectclass); static int strip_oc_options ( struct objclass *poc ); static char *stripOption (char *attr); -static int read_at_ldif(const char *input, struct asyntaxinfo **asipp, - char *errorbuf, size_t errorbufsize, PRUint32 flags, - int is_user_defined, int schema_ds4x_compat, int is_remote); -static char **parse_qdlist(const char *s, int *n, int strip_options); -static void free_qdlist(char **vals, int n); -static char **parse_qdescrs(const char *s, int *n); -static char **parse_qdstrings(const char *s, int *n); -static int get_flag_keyword( const char *keyword, int flag_value, - const char **inputp, schema_strstr_fn_t strstr_fn ); -static char *get_tagged_oid( const char *tag, const char **inputp, - schema_strstr_fn_t strstr_fn ); +static int schema_extension_cmp(schemaext *e1, schemaext *e2); static int put_tagged_oid( char *outp, const char *tag, const char *oid, const char *suffix, int enquote ); static void strcat_oids( char *buf, char *prefix, char **oids, int schema_ds4x_compat ); -static size_t strcat_qdlist( char *buf, char *prefix, char **qdlist ); +static size_t strcat_extensions( char *buf, schemaext *extension ); static size_t strlen_null_ok(const char *s); static int strcpy_count( char *dst, const char *src ); -static int element_is_user_defined( char * const * origins ); -static char **parse_origin_list( const char *schema_value, int *num_originsp, - char **default_list ); static int refresh_user_defined_schema(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg); static int schema_check_oc_attrs ( struct objclass *poc, char *errorbuf, size_t errorbufsize, int stripOptions ); @@ -156,20 +140,56 @@ static int schema_strcmp_array( char **sa1, char **sa2, static PRBool schema_type_is_interesting( const char *type ); static void schema_create_errormsg( char *errorbuf, size_t errorbufsize, const char *prefix, const char *name, const char *fmt, ... ) -#ifdef __GNUC__ +#ifdef __GNUC__ __attribute__ ((format (printf, 5, 6))); #else ; #endif +static int parse_at_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf, size_t errorbufsize, + PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat, int is_remote); +static int extension_is_user_defined( schemaext *extensions ); +static size_t strcat_qdlist( char *buf, char *prefix, char **qdlist ); +#if defined (USE_OPENLDAP) +/* + * openldap + */ +static int parse_attr_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf, size_t errorbufsize, + PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat, int is_remote); +static int parse_objclass_str(const char *input, struct objclass **oc, char *errorbuf, size_t errorbufsize, + PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat ); + +#else +/* + * mozldap + */ +static char **parse_qdescrs(const char *s, int *n); +static char **parse_qdstrings(const char *s, int *n); +static char **parse_qdlist(const char *s, int *n, int strip_options); +static void free_qdlist(char **vals, int n); +static int read_at_ldif(const char *input, struct asyntaxinfo **asipp, + char *errorbuf, size_t errorbufsize, PRUint32 flags, + int is_user_defined, int schema_ds4x_compat, int is_remote); +static int read_oc_ldif ( const char *input, struct objclass **oc, + char *errorbuf, size_t errorbufsize, PRUint32 flags, int is_user_defined, + int schema_ds4x_compat ); +static int get_flag_keyword( const char *keyword, int flag_value, + const char **inputp, schema_strstr_fn_t strstr_fn ); +static char *get_tagged_oid( const char *tag, const char **inputp, + schema_strstr_fn_t strstr_fn ); +static char **read_dollar_values ( char *vals); +static schemaext *parse_extensions( const char *schema_value, char **default_list ); +#endif
-/* Some utility functions for dealing with a dynamic buffer */
+ +/* + * Some utility functions for dealing with a dynamic buffer + */ static struct sizedbuffer *sizedbuffer_construct(size_t size); static void sizedbuffer_destroy(struct sizedbuffer *p); static void sizedbuffer_allocate(struct sizedbuffer *p, size_t sizeneeded);
- /* * Constant strings that we pass to schema_create_errormsg(). */ @@ -196,6 +216,27 @@ static Slapi_RWLock *schema_dse_lock = NULL; */ static PRCallOnceType schema_dse_mandatory_init_callonce = { 0, 0, 0 };
+static int parse_at_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf, size_t errorbufsize, + PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat, int is_remote) +{ +#ifdef USE_OPENLDAP + return parse_attr_str(input, asipp, errorbuf, errorbufsize, schema_flags, is_user_defined,schema_ds4x_compat,is_remote); +#else + return read_at_ldif(input, asipp, errorbuf, errorbufsize, schema_flags, is_user_defined,schema_ds4x_compat,is_remote); +#endif +} + +static int parse_oc_str(const char *input, struct objclass **oc, char *errorbuf, + size_t errorbufsize, PRUint32 schema_flags, int is_user_defined, + int schema_ds4x_compat ) +{ +#ifdef USE_OPENLDAP + return parse_objclass_str (input, oc, errorbuf, errorbufsize, schema_flags, is_user_defined, schema_ds4x_compat ); +#else + return read_oc_ldif (input, oc, errorbuf, errorbufsize, schema_flags, is_user_defined, schema_ds4x_compat ); +#endif +} +
/* Essential initialization. Returns PRSuccess if successful */ static PRStatus @@ -250,6 +291,7 @@ dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int return SLAPI_DSE_CALLBACK_ERROR; }
+#if !defined(USE_OPENLDAP) static const char * skipWS(const char *s) { @@ -281,8 +323,6 @@ strchr_skip_quoted_strings( char *s, int c )
return( NULL ); } - - /** * parses a string containing a qdescrs or qdstrings (as described by * RFC 2252, section 4.1) into an array of strings; the second parameter @@ -381,17 +421,6 @@ parse_qdlist(const char *s, int *n, int strip_options) return retval; }
- -static void -free_qdlist(char **vals, int n) -{ - int ii; - for (ii = 0; ii < n; ++ii) - slapi_ch_free((void **)&(vals[ii])); - slapi_ch_free((void **)&vals); -} - - /** * parses a string containing a qdescrs (as described by RFC 2252, section 4.1) * into an array of strings; the second parameter will hold the actual number @@ -415,6 +444,16 @@ parse_qdstrings(const char *s, int *n) return parse_qdlist( s, n, 0 /* DO NOT strip attribute options */ ); }
+static void +free_qdlist(char **vals, int n) +{ + int ii; + for (ii = 0; ii < n; ++ii) + slapi_ch_free((void **)&(vals[ii])); + slapi_ch_free((void **)&vals); +} + +#endif /* not openldap */
/* * slapi_entry_schema_check - check that entry e conforms to the schema @@ -960,8 +999,7 @@ oc_equal( struct objclass *oc1, struct objclass *oc2 ) NULL ) != 0 || schema_strcmp_array( oc1->oc_orig_allowed, oc2->oc_orig_allowed, NULL ) != 0 - || schema_strcmp_array( oc1->oc_origin, oc2->oc_origin, - schema_user_defined_origin[0] ) != 0 ) { + || schema_extension_cmp( oc1->oc_extensions, oc2->oc_extensions ) != 0 ) { return PR_FALSE; }
@@ -995,6 +1033,114 @@ oc_print( struct objclass *oc ) } #endif
+/* + * Compare the X-ORIGIN extension, other extensions can be ignored + */ +static int +schema_extension_cmp(schemaext *e1, schemaext *e2) +{ + schemaext *e1_head = e1; + schemaext *e2_head = e2; + int found = 0; + int e1_has_origin = 0; + int e2_has_origin = 0; + int i, ii; + + if(e1 == NULL && e2 == NULL){ + return 0; /* match */ + } else if (e1 == NULL || e2 == NULL){ + return -1; + } + while(e1){ + if(strcmp(e1->term, "X-ORIGIN")){ + e1 = e1->next; + continue; + } + e1_has_origin = 1; + while(e2){ + if(strcmp(e1->term, e2->term) == 0) + { + e2_has_origin = 1; + if(e1->values == NULL && e2->values == NULL){ + return 0; + } else if (e1->values == NULL || e2->values == NULL){ + return -1; + } + for (i = 0; e1->values[i]; i++) + { + found = 0; + for(ii = 0; e2->values[ii]; ii++) + { + if(strcmp(e1->values[i], e2->values[ii]) == 0){ + found = 1; + break; + } + } + if(!found){ + return -1; + } + } + /* So far so good, move on to the next check */ + goto next; + } + e2 = e2->next; + } + e2 = e2_head; + e1 = e1->next; + } + + if(e1_has_origin != e2_has_origin){ + return -1; + } else if (e1_has_origin == 0 && e2_has_origin == 0){ + return 0; + } + +next: + /* + * We know that e2 has the same extensions as e1, but does e1 have all the extensions as e2? + * Run the compare in reverse... + */ + found = 0; + e1 = e1_head; + e2 = e2_head; + + while(e2){ + if(strcmp(e2->term, "X-ORIGIN")){ + e2 = e2->next; + continue; + } + while(e1){ + if(strcmp(e2->term, e1->term) == 0) + { + if(e2->values == NULL && e1->values == NULL){ + return 0; + } else if (e1->values == NULL || e2->values == NULL){ + return -1; + } + for (i = 0; e2->values[i]; i++) + { + found = 0; + for(ii = 0; e1->values[ii]; ii++) + { + if(strcmp(e2->values[i], e1->values[ii]) == 0){ + found = 1; + break; + } + } + if(!found){ + return -1; + } + } + return 0; + } + e1 = e1->next; + } + e1 = e1_head; + e2 = e2->next; + } + + return 0; +}
/* * Compare two attrsyntax definitions for equality. Return PR_TRUE if @@ -1028,8 +1174,7 @@ attr_syntax_equal( struct asyntaxinfo *asi1, struct asyntaxinfo *asi2 ) }
if ( schema_strcmp_array( asi1->asi_aliases, asi2->asi_aliases, NULL ) != 0 - || schema_strcmp_array( asi1->asi_origin, asi2->asi_origin, - schema_user_defined_origin[0] ) != 0 + || schema_extension_cmp (asi1->asi_extensions, asi2->asi_extensions) != 0 || asi1->asi_plugin != asi2->asi_plugin || ( asi1->asi_flags & flagmask ) != ( asi2->asi_flags & flagmask ) @@ -1196,7 +1341,7 @@ schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg) strlen_null_ok(asip->asi_mr_equality) + strlen_null_ok(asip->asi_mr_ordering) + strlen_null_ok(asip->asi_mr_substring) + - strcat_qdlist( NULL, "X-ORIGIN", asip->asi_origin )); + strcat_extensions( NULL, asip->asi_extensions ));
/* * Overall strategy is to maintain a pointer to the next location in @@ -1257,9 +1402,8 @@ schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg) outp += strcpy_count(outp, "USAGE directoryOperation "); }
- outp += strcat_qdlist( outp, "X-ORIGIN", asip->asi_origin ); + outp += strcat_extensions( outp, asip->asi_extensions ); } - outp += strcpy_count(outp, ")");
val.bv_val = aew->psbAttrTypes->buffer; @@ -1410,213 +1554,203 @@ read_schema_dse( char *returntext /* not used */, void *arg /* not used */ ) { - struct berval val; - struct berval *vals[2]; - int i; - struct objclass *oc; - struct matchingRuleList *mrl=NULL; - struct sizedbuffer *psbObjectClasses= sizedbuffer_construct(BUFSIZ); - struct sizedbuffer *psbAttrTypes= sizedbuffer_construct(BUFSIZ); - struct sizedbuffer *psbMatchingRule= sizedbuffer_construct(BUFSIZ); - struct sizedbuffer *psbSyntaxDescription = sizedbuffer_construct(BUFSIZ); - struct attr_enum_wrapper aew; - struct syntax_enum_wrapper sew; - int enquote_sup_oc = config_get_enquote_sup_oc(); - PRUint32 schema_flags = 0; - int user_defined_only = 0; - char **allowed, **required; - char *mr_desc, *mr_name, *oc_description; - int schema_ds4x_compat = config_get_ds4_compatible_schema(); - const CSN *csn; + struct berval val; + struct berval *vals[2]; + struct objclass *oc; + struct matchingRuleList *mrl=NULL; + struct sizedbuffer *psbObjectClasses= sizedbuffer_construct(BUFSIZ); + struct sizedbuffer *psbAttrTypes= sizedbuffer_construct(BUFSIZ); + struct sizedbuffer *psbMatchingRule= sizedbuffer_construct(BUFSIZ); + struct sizedbuffer *psbSyntaxDescription = sizedbuffer_construct(BUFSIZ); + struct attr_enum_wrapper aew; + struct syntax_enum_wrapper sew; + const CSN *csn; + char *mr_desc, *mr_name, *oc_description; + char **allowed, **required; + PRUint32 schema_flags = 0; + int enquote_sup_oc = config_get_enquote_sup_oc(); + int schema_ds4x_compat = config_get_ds4_compatible_schema(); + int user_defined_only = 0; + int i;
- vals[0] = &val; - vals[1] = NULL; + vals[0] = &val; + vals[1] = NULL;
- slapi_pblock_get(pb, SLAPI_SCHEMA_FLAGS, (void*)&schema_flags); - user_defined_only = (schema_flags & DSE_SCHEMA_USER_DEFINED_ONLY) ? 1 : 0; + slapi_pblock_get(pb, SLAPI_SCHEMA_FLAGS, (void*)&schema_flags); + user_defined_only = (schema_flags & DSE_SCHEMA_USER_DEFINED_ONLY) ? 1 : 0;
- attrlist_delete (&pschema_info_e->e_attrs, "objectclasses"); - attrlist_delete (&pschema_info_e->e_attrs, "attributetypes"); - attrlist_delete (&pschema_info_e->e_attrs, "matchingRules"); - attrlist_delete (&pschema_info_e->e_attrs, "ldapSyntaxes"); - /* - attrlist_delete (&pschema_info_e->e_attrs, "matchingRuleUse"); - */ + attrlist_delete (&pschema_info_e->e_attrs, "objectclasses"); + attrlist_delete (&pschema_info_e->e_attrs, "attributetypes"); + attrlist_delete (&pschema_info_e->e_attrs, "matchingRules"); + attrlist_delete (&pschema_info_e->e_attrs, "ldapSyntaxes"); + /* + * attrlist_delete (&pschema_info_e->e_attrs, "matchingRuleUse"); + */
- schema_dse_lock_read(); + schema_dse_lock_read(); + oc_lock_read();
- /* return the objectclasses */ - oc_lock_read(); - for (oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next) - { - size_t size= 0; - int need_extra_space = 1; + /* return the objectclasses */ + for (oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next) + { + size_t size= 0; + int need_extra_space = 1;
- if (user_defined_only && - !(oc->oc_flags & OC_FLAG_USER_OC || - oc->oc_flags & OC_FLAG_REDEFINED_OC)) { - continue; - } + if (user_defined_only && + !((oc->oc_flags & OC_FLAG_USER_OC) || + (oc->oc_flags & OC_FLAG_REDEFINED_OC) )) + { + continue; + } + /* + * XXX: 256 is a magic number... it must be large enough to fit + * all of the fixed size items including description (DESC), + * kind (STRUCTURAL, AUXILIARY, or ABSTRACT), and the OBSOLETE flag. + */ + if ( schema_ds4x_compat ) { + oc_description = (oc->oc_flags & OC_FLAG_STANDARD_OC) ? + OC_STANDARD_STRING : OC_USERDEF_STRING; + } else { + oc_description = oc->oc_desc; + } + size = 256+strlen_null_ok(oc->oc_oid) + strlen(oc->oc_name) + + strlen_null_ok(oc_description) + strcat_extensions( NULL, oc->oc_extensions ); + required = schema_ds4x_compat ? oc->oc_required : oc->oc_orig_required; + if (required && required[0]) { + for (i = 0 ; required[i]; i++) + size+= 16 + strlen(required[i]); + } + allowed = schema_ds4x_compat ? oc->oc_allowed : oc->oc_orig_allowed; + if (allowed && allowed[0]) { + for (i = 0 ; allowed[i]; i++) + size+= 16 + strlen(allowed[i]); + } + sizedbuffer_allocate(psbObjectClasses,size); + /* put the OID and the NAME */ + sprintf (psbObjectClasses->buffer, "( %s NAME '%s'", (oc->oc_oid) ? oc->oc_oid : "", oc->oc_name); + /* The DESC (description) is OPTIONAL */ + if (oc_description) { + strcat(psbObjectClasses->buffer, " DESC '"); + /* + * We want to list an empty description + * element if it was defined that way. + */ + if (*oc_description) { + strcat(psbObjectClasses->buffer, oc_description); + } + strcat(psbObjectClasses->buffer, "'"); + need_extra_space = 1; + } + /* put the OBSOLETE keyword */ + if (!schema_ds4x_compat && (oc->oc_flags & OC_FLAG_OBSOLETE)) { + strcat(psbObjectClasses->buffer, schema_obsolete_with_spaces); + need_extra_space = 0; + } + /* put the SUP superior objectclass */ + if (0 != strcasecmp(oc->oc_name, "top")) { /* top has no SUP */ + /* + * Some AUXILIARY AND ABSTRACT objectclasses may not have a SUP either + * for compatability, every objectclass other than top must have a SUP + */ + if (schema_ds4x_compat || (oc->oc_superior && *oc->oc_superior)) { + if (need_extra_space) { + strcat(psbObjectClasses->buffer, " "); + } + strcat(psbObjectClasses->buffer, "SUP "); + strcat(psbObjectClasses->buffer, (enquote_sup_oc ? "'" : "")); + strcat(psbObjectClasses->buffer, ((oc->oc_superior && *oc->oc_superior) ? + oc->oc_superior : "top")); + strcat(psbObjectClasses->buffer, (enquote_sup_oc ? "'" : "")); + need_extra_space = 1; + } + } + /* put the kind of objectclass */ + if (schema_ds4x_compat) { + if (need_extra_space) { + strcat(psbObjectClasses->buffer, " "); + } + } else {
- /* - * XXX: 256 is a magic number... it must be large enough to fit - * all of the fixed size items including description (DESC), - * kind (STRUCTURAL, AUXILIARY, or ABSTRACT), and the OBSOLETE flag. - */ - if ( schema_ds4x_compat ) { - oc_description = (oc->oc_flags & OC_FLAG_STANDARD_OC) ? - OC_STANDARD_STRING : OC_USERDEF_STRING; - } else { - oc_description = oc->oc_desc; - } - - size= 256+strlen_null_ok(oc->oc_oid) + strlen(oc->oc_name) + - strlen_null_ok(oc_description) + - strcat_qdlist( NULL, "X-ORIGIN", oc->oc_origin ); - required = schema_ds4x_compat ? oc->oc_required : oc->oc_orig_required; - if (required && required[0]) { - for (i = 0 ; required[i]; i++) - size+= 16 + strlen(required[i]); - } - allowed = schema_ds4x_compat ? oc->oc_allowed : oc->oc_orig_allowed; - if (allowed && allowed[0]) { - for (i = 0 ; allowed[i]; i++) - size+= 16 + strlen(allowed[i]); + strcat(psbObjectClasses->buffer, schema_oc_kind_strings_with_spaces[oc->oc_kind]); + } + strcat_oids( psbObjectClasses->buffer, "MUST", required, schema_ds4x_compat ); + strcat_oids( psbObjectClasses->buffer, "MAY", allowed, schema_ds4x_compat ); + if ( !schema_ds4x_compat ) { + strcat_extensions( psbObjectClasses->buffer, oc->oc_extensions ); + } + strcat( psbObjectClasses->buffer, ")"); + val.bv_val = psbObjectClasses->buffer; + val.bv_len = strlen (psbObjectClasses->buffer); + attrlist_merge (&pschema_info_e->e_attrs, "objectclasses", vals); } - sizedbuffer_allocate(psbObjectClasses,size); - /* put the OID and the NAME */ - sprintf (psbObjectClasses->buffer, - "( %s NAME '%s'", - (oc->oc_oid) ? oc->oc_oid : "", - oc->oc_name); - /* The DESC (description) is OPTIONAL */ - if (oc_description) { - strcat(psbObjectClasses->buffer, " DESC '"); - /* We want to list an empty description - * element if it was defined that way. */ - if (*oc_description) { - strcat(psbObjectClasses->buffer, oc_description); - } - strcat(psbObjectClasses->buffer, "'"); - need_extra_space = 1; - } - /* put the OBSOLETE keyword */ - if (!schema_ds4x_compat && (oc->oc_flags & OC_FLAG_OBSOLETE)) { - strcat(psbObjectClasses->buffer, schema_obsolete_with_spaces); - need_extra_space = 0; - } - /* put the SUP superior objectclass */ - if (0 != strcasecmp(oc->oc_name, "top")) { /* top has no SUP */ - /* some AUXILIARY AND ABSTRACT objectclasses may not have a SUP either */ - /* for compatability, every objectclass other than top must have a SUP */ - if (schema_ds4x_compat || (oc->oc_superior && *oc->oc_superior)) { - if (need_extra_space) { - strcat(psbObjectClasses->buffer, " "); - } - strcat(psbObjectClasses->buffer, "SUP "); - strcat(psbObjectClasses->buffer, (enquote_sup_oc ? "'" : "")); - strcat(psbObjectClasses->buffer, - ((oc->oc_superior && *oc->oc_superior) ? - oc->oc_superior : "top")); - strcat(psbObjectClasses->buffer, (enquote_sup_oc ? "'" : "")); - need_extra_space = 1; - } - } - /* put the kind of objectclass */ - if (schema_ds4x_compat) { - if (need_extra_space) { - strcat(psbObjectClasses->buffer, " "); - } - } else { - strcat(psbObjectClasses->buffer, schema_oc_kind_strings_with_spaces[oc->oc_kind]); - } - - strcat_oids( psbObjectClasses->buffer, "MUST", required, - schema_ds4x_compat ); - strcat_oids( psbObjectClasses->buffer, "MAY", allowed, - schema_ds4x_compat ); - if ( !schema_ds4x_compat ) { - strcat_qdlist( psbObjectClasses->buffer, "X-ORIGIN", oc->oc_origin ); - } - strcat( psbObjectClasses->buffer, ")"); - - val.bv_val = psbObjectClasses->buffer; - val.bv_len = strlen (psbObjectClasses->buffer); - attrlist_merge (&pschema_info_e->e_attrs, "objectclasses", vals); - } - oc_unlock(); - - /* now return the attrs */ - - aew.attrs = &pschema_info_e->e_attrs; - aew.enquote_sup_oc = enquote_sup_oc; - aew.psbAttrTypes = psbAttrTypes; - aew.user_defined_only = user_defined_only; - aew.schema_ds4x_compat = schema_ds4x_compat; - attr_syntax_enumerate_attrs(schema_attr_enum_callback, &aew, PR_FALSE); - - /* return the set of matching rules we support */ - for (mrl = g_get_global_mrl(); !user_defined_only && mrl != NULL; mrl = mrl->mrl_next) { - mr_name = mrl->mr_entry->mr_name ? mrl->mr_entry->mr_name : ""; - mr_desc = mrl->mr_entry->mr_desc ? mrl->mr_entry->mr_desc : ""; - sizedbuffer_allocate(psbMatchingRule,128+ - strlen_null_ok(mrl->mr_entry->mr_oid) + - strlen(mr_name)+ strlen(mr_desc)+ - strlen_null_ok(mrl->mr_entry->mr_syntax)); - if ( schema_ds4x_compat ) { - sprintf(psbMatchingRule->buffer, - "( %s NAME '%s' DESC '%s' SYNTAX %s%s%s )", - (mrl->mr_entry->mr_oid ? mrl->mr_entry->mr_oid : ""), - mr_name, mr_desc, - enquote_sup_oc ? "'" : "", - mrl->mr_entry->mr_syntax ? mrl->mr_entry->mr_syntax : "" , - enquote_sup_oc ? "'" : ""); - } else if ( NULL != mrl->mr_entry->mr_oid && - NULL != mrl->mr_entry->mr_syntax ) { - char *p; - - sprintf(psbMatchingRule->buffer, "( %s ", mrl->mr_entry->mr_oid ); - p = psbMatchingRule->buffer + strlen(psbMatchingRule->buffer); - if ( *mr_name != '\0' ) { - sprintf(p, "NAME '%s' ", mr_name ); - p += strlen(p); - }
- if ( *mr_desc != '\0' ) { - sprintf(p, "DESC '%s' ", mr_desc ); - p += strlen(p); - } - sprintf(p, "SYNTAX %s )", mrl->mr_entry->mr_syntax ); - } + oc_unlock();
- val.bv_val = psbMatchingRule->buffer; - val.bv_len = strlen (psbMatchingRule->buffer); - attrlist_merge (&pschema_info_e->e_attrs, "matchingRules", vals); - } + /* now return the attrs */ + aew.attrs = &pschema_info_e->e_attrs; + aew.enquote_sup_oc = enquote_sup_oc; + aew.psbAttrTypes = psbAttrTypes; + aew.user_defined_only = user_defined_only; + aew.schema_ds4x_compat = schema_ds4x_compat; + attr_syntax_enumerate_attrs(schema_attr_enum_callback, &aew, PR_FALSE); + + /* return the set of matching rules we support */ + for (mrl = g_get_global_mrl(); !user_defined_only && mrl != NULL; mrl = mrl->mrl_next) { + mr_name = mrl->mr_entry->mr_name ? mrl->mr_entry->mr_name : ""; + mr_desc = mrl->mr_entry->mr_desc ? mrl->mr_entry->mr_desc : ""; + sizedbuffer_allocate(psbMatchingRule,128 + strlen_null_ok(mrl->mr_entry->mr_oid) + + strlen(mr_name)+ strlen(mr_desc) + strlen_null_ok(mrl->mr_entry->mr_syntax)); + if ( schema_ds4x_compat ) { + sprintf(psbMatchingRule->buffer, + "( %s NAME '%s' DESC '%s' SYNTAX %s%s%s )", + (mrl->mr_entry->mr_oid ? mrl->mr_entry->mr_oid : ""), + mr_name, mr_desc, enquote_sup_oc ? "'" : "", + mrl->mr_entry->mr_syntax ? mrl->mr_entry->mr_syntax : "" , + enquote_sup_oc ? "'" : ""); + } else if ( NULL != mrl->mr_entry->mr_oid && + NULL != mrl->mr_entry->mr_syntax ){ + char *p; + + sprintf(psbMatchingRule->buffer, "( %s ", mrl->mr_entry->mr_oid ); + p = psbMatchingRule->buffer + strlen(psbMatchingRule->buffer); + if ( *mr_name != '\0' ) { + sprintf(p, "NAME '%s' ", mr_name ); + p += strlen(p); + } + if ( *mr_desc != '\0' ) { + sprintf(p, "DESC '%s' ", mr_desc ); + p += strlen(p); + } + sprintf(p, "SYNTAX %s )", mrl->mr_entry->mr_syntax ); + } + val.bv_val = psbMatchingRule->buffer; + val.bv_len = strlen (psbMatchingRule->buffer); + attrlist_merge (&pschema_info_e->e_attrs, "matchingRules", vals); + } + if ( !schema_ds4x_compat && !user_defined_only ) { + /* return the set of syntaxes we support */ + sew.attrs = &pschema_info_e->e_attrs; + sew.psbSyntaxDescription = psbSyntaxDescription; + plugin_syntax_enumerate(schema_syntax_enum_callback, &sew); + } + csn = g_get_global_schema_csn(); + if (NULL != csn) { + char csn_str[CSN_STRSIZE + 1];
- if ( !schema_ds4x_compat && !user_defined_only ) { - /* return the set of syntaxes we support */ - sew.attrs = &pschema_info_e->e_attrs; - sew.psbSyntaxDescription = psbSyntaxDescription; - plugin_syntax_enumerate(schema_syntax_enum_callback, &sew); - } + csn_as_string(csn, PR_FALSE, csn_str); + slapi_entry_attr_delete(pschema_info_e, "nsschemacsn"); + slapi_entry_add_string(pschema_info_e, "nsschemacsn", csn_str); + }
- csn = g_get_global_schema_csn(); - if (NULL != csn) { - char csn_str[CSN_STRSIZE + 1]; - csn_as_string(csn, PR_FALSE, csn_str); - slapi_entry_attr_delete(pschema_info_e, "nsschemacsn"); - slapi_entry_add_string(pschema_info_e, "nsschemacsn", csn_str); - } + schema_dse_unlock();
- schema_dse_unlock(); + sizedbuffer_destroy(psbObjectClasses); + sizedbuffer_destroy(psbAttrTypes); + sizedbuffer_destroy(psbMatchingRule); + sizedbuffer_destroy(psbSyntaxDescription); + *returncode= LDAP_SUCCESS;
- sizedbuffer_destroy(psbObjectClasses); - sizedbuffer_destroy(psbAttrTypes); - sizedbuffer_destroy(psbMatchingRule); - sizedbuffer_destroy(psbSyntaxDescription); - *returncode= LDAP_SUCCESS; - return SLAPI_DSE_CALLBACK_OK; + return SLAPI_DSE_CALLBACK_OK; }
/* helper for deleting mods (we do not want to be applied) from the mods array */ @@ -1985,23 +2119,6 @@ oc_add_nolock(struct objclass *newoc) newoc->oc_next = NULL; } } - - -static char **read_dollar_values ( char *vals) { - int i,k; - char **retVal; - static const char *charsToRemove = " ()"; - - /* get rid of all the parens and spaces */ - for ( i = 0, k = 0; vals[i]; i++) { - if (!strchr(charsToRemove, vals[i])) { - vals[k++] = vals[i]; - } - } - vals[k] = '\0'; - retVal = slapi_str2charray (vals, "$"); - return retVal; -}
/* * Delete one or more objectClasses from our internal data structure. @@ -2027,7 +2144,7 @@ schema_delete_objectclasses( Slapi_Entry *entryBefore, LDAPMod *mod, }
for (i = 0; mod->mod_bvalues[i]; i++) { - if ( LDAP_SUCCESS != ( rc = read_oc_ldif ( + if ( LDAP_SUCCESS != ( rc = parse_oc_str ( (const char *)mod->mod_bvalues[i]->bv_val, &delete_oc, errorbuf, errorbufsize, 0, 0, schema_ds4x_compat))) { return rc; @@ -2212,7 +2329,7 @@ schema_add_attribute ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf, { int i; char *attr_ldif; -/* LPXXX: Eventually, we should not allocate the buffers in read_at_ldif +/* LPXXX: Eventually, we should not allocate the buffers in parse_at_str * for each attribute, but use the same buffer for all. * This is not done yet, so it's useless to allocate buffers for nothing. */ @@ -2226,7 +2343,7 @@ schema_add_attribute ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf, PRUint32 nolock = 0; /* lock global resources during normal operation */ attr_ldif = (char *) mod->mod_bvalues[i]->bv_val;
- status = read_at_ldif(attr_ldif, NULL, errorbuf, errorbufsize, + status = parse_at_str(attr_ldif, NULL, errorbuf, errorbufsize, nolock, 1 /* user defined */, schema_ds4x_compat, 1); if ( LDAP_SUCCESS != status ) { break; /* stop on first error */ @@ -2422,7 +2539,7 @@ schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf, }
for ( i = 0; mod->mod_bvalues[i] != NULL; ++i ) { - if ( LDAP_SUCCESS != ( rc = read_at_ldif( mod->mod_bvalues[i]->bv_val, + if ( LDAP_SUCCESS != ( rc = parse_at_str( mod->mod_bvalues[i]->bv_val, &newasip, errorbuf, errorbufsize, 0, 1, 0, 0 ))) { goto clean_up_and_return; } @@ -2500,7 +2617,7 @@ schema_add_objectclass ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
for (j = 0; mod->mod_bvalues[j]; j++) { newoc_ldif = (char *) mod->mod_bvalues[j]->bv_val; - if ( LDAP_SUCCESS != (rc = read_oc_ldif ( newoc_ldif, &pnew_oc, + if ( LDAP_SUCCESS != (rc = parse_oc_str ( newoc_ldif, &pnew_oc, errorbuf, errorbufsize, 0, 1 /* user defined */, schema_ds4x_compat))) { return rc; @@ -2577,7 +2694,7 @@ schema_replace_objectclasses ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf, for ( i = 0; mod->mod_bvalues[i] != NULL; ++i ) { struct objclass *addocp = NULL;
- if ( LDAP_SUCCESS != ( rc = read_oc_ldif( mod->mod_bvalues[i]->bv_val, + if ( LDAP_SUCCESS != ( rc = parse_oc_str( mod->mod_bvalues[i]->bv_val, &newocp, errorbuf, errorbufsize, DSE_SCHEMA_NO_GLOCK, 1 /* user defined */, 0 /* no DS 4.x compat issues */ ))) { rc = LDAP_INVALID_SYNTAX; @@ -2590,7 +2707,7 @@ schema_replace_objectclasses ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf, /* the names match -- remove from the current list */ if ( tmpocp == curlisthead ) { curlisthead = tmpocp->oc_next; - /* The global oc list is scanned in read_oc_ldif above, + /* The global oc list is scanned in parse_oc_str above, if there are multiple objectclasses to be updated. Needs to maintain the list dynamically. */ g_set_global_oc_nolock( curlisthead ); @@ -2698,6 +2815,66 @@ clean_up_and_return: return rc; }
+schemaext * +schema_copy_extensions(schemaext *extensions) +{ + schemaext *ext = NULL, *head = NULL; + while(extensions){ + schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof(schemaext)); + newext->term = slapi_ch_strdup(extensions->term); + newext->values = charray_dup(extensions->values); + newext->value_count = extensions->value_count; + if(ext == NULL){ + ext = newext; + head = newext; + } else { + ext->next = newext; + ext = newext; + } + extensions = extensions->next; + } + + return head; +} + +void +schema_free_extensions(schemaext *extensions) +{ + if(extensions){ + schemaext *prev; + + while(extensions){ + slapi_ch_free_string(&extensions->term); + charray_free(extensions->values); + prev = extensions; + extensions = extensions->next; + slapi_ch_free( (void **)&prev); + } + } +} + +static void +oc_free( struct objclass **ocp ) +{ + struct objclass *oc; + + if ( NULL != ocp && NULL != *ocp ) { + oc = *ocp; + slapi_ch_free( (void **)&oc->oc_name ); + slapi_ch_free( (void **)&oc->oc_desc ); + slapi_ch_free( (void **)&oc->oc_oid ); + slapi_ch_free( (void **)&oc->oc_superior ); + charray_free( oc->oc_required ); + charray_free( oc->oc_allowed ); + charray_free( oc->oc_orig_required ); + charray_free( oc->oc_orig_allowed ); + schema_free_extensions( oc->oc_extensions ); + slapi_ch_free( (void **)&oc ); + *ocp = NULL; + } +} + +#if !defined (USE_OPENLDAP)
/* * read_oc_ldif_return @@ -2711,14 +2888,11 @@ read_oc_ldif_return( int retVal, char *oid, struct sizedbuffer *name, char *sup, - char **origins, - int num_origins, char *desc ) { slapi_ch_free((void **)&oid); sizedbuffer_destroy( name ); slapi_ch_free((void **)&sup); - free_qdlist( origins, num_origins ); slapi_ch_free((void **)&desc); return retVal; } @@ -2755,17 +2929,17 @@ read_oc_ldif ( const char *input, struct objclass **oc, char *errorbuf, size_t errorbufsize, PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat ) { - int i, j, num_origins; + int i, j; const char *pstart, *nextinput; struct objclass *pnew_oc, *psup_oc; char **RequiredAttrsArray, **AllowedAttrsArray; char **OrigRequiredAttrsArray, **OrigAllowedAttrsArray; - char **oc_origins; char *pend, *pOcOid, *pOcSup, *pOcDesc; struct sizedbuffer *psbOcName= sizedbuffer_construct(BUFSIZ); PRUint8 kind, flags; int invalid_syntax_error; schema_strstr_fn_t keyword_strstr_fn; + schemaext *extensions = NULL;
/* * From RFC 2252 section 4.4: @@ -2811,8 +2985,6 @@ read_oc_ldif ( const char *input, struct objclass **oc, char *errorbuf, }
flags = 0; - num_origins = 0; - oc_origins = NULL; pOcOid = pOcSup = pOcDesc = NULL;
if ( NULL == input || '\0' == input[0] ) { @@ -2821,10 +2993,9 @@ read_oc_ldif ( const char *input, struct objclass **oc, char *errorbuf, "One or more values are required for the objectClasses attribute" ); LDAPDebug ( LDAP_DEBUG_ANY, "NULL args passed to read_oc_ldif\n",0,0,0); return read_oc_ldif_return( LDAP_OPERATIONS_ERROR, pOcOid, psbOcName, - pOcSup, oc_origins, num_origins, pOcDesc ); + pOcSup, pOcDesc ); }
- nextinput = input;
/* look for the OID */ @@ -2833,7 +3004,7 @@ read_oc_ldif ( const char *input, struct objclass **oc, char *errorbuf, schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, input, "Value is malformed. It must include a "(""); return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName, - pOcSup, oc_origins, num_origins, pOcDesc ); + pOcSup, pOcDesc ); }
if ( schema_ds4x_compat || ( strcasecmp(pOcOid, "NAME") == 0)) @@ -2853,15 +3024,14 @@ read_oc_ldif ( const char *input, struct objclass **oc, char *errorbuf, input, "Value is malformed. It must include a single quote around" " the name" ); return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName, - pOcSup, oc_origins, num_origins, pOcDesc ); + pOcSup, pOcDesc ); } } - } - else { + } else { schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, input, "Value is malformed. It must include a "NAME '""); - return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName, - pOcSup, oc_origins, num_origins, pOcDesc ); + return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName, + pOcSup, pOcDesc ); }
/* @@ -2996,27 +3166,15 @@ read_oc_ldif ( const char *input, struct objclass **oc, char *errorbuf, /* look for X-ORIGIN list */ if (is_user_defined) { /* add X-ORIGIN 'user defined' */ - oc_origins = parse_origin_list( nextinput, &num_origins, - schema_user_defined_origin ); + extensions = parse_extensions( nextinput, schema_user_defined_origin ); + flags |= OC_FLAG_USER_OC; } else { /* add nothing */ - oc_origins = parse_origin_list( nextinput, &num_origins, NULL ); - } - - /* set remaining flags */ - if ( element_is_user_defined( oc_origins )) { - flags |= OC_FLAG_USER_OC; - } else if ( is_user_defined ) { - flags |= OC_FLAG_USER_OC; - /* add missing user defined origin string */ - charray_add( &oc_origins, slapi_ch_strdup( schema_user_defined_origin[0] )); - ++num_origins; - } else { - flags |= OC_FLAG_STANDARD_OC; + extensions = parse_extensions( nextinput, NULL ); + flags |= OC_FLAG_STANDARD_OC; }
/* generate OrigRequiredAttrsArray and OrigAllowedAttrsArray */ - if (psup_oc) { int found_it;
@@ -3073,36 +3231,29 @@ read_oc_ldif ( const char *input, struct objclass **oc, char *errorbuf, pnew_oc->oc_allowed = AllowedAttrsArray; pnew_oc->oc_orig_required = OrigRequiredAttrsArray; pnew_oc->oc_orig_allowed = OrigAllowedAttrsArray; - pnew_oc->oc_origin = cool_charray_dup( oc_origins ); + pnew_oc->oc_extensions = extensions; pnew_oc->oc_next = NULL; pnew_oc->oc_flags = flags; pnew_oc->oc_kind = kind;
*oc = pnew_oc; - return read_oc_ldif_return( LDAP_SUCCESS, pOcOid, psbOcName, pOcSup, - oc_origins, num_origins, pOcDesc ); + return read_oc_ldif_return( LDAP_SUCCESS, pOcOid, psbOcName, pOcSup, pOcDesc ); }
+static char **read_dollar_values ( char *vals) { + int i,k; + char **retVal; + static const char *charsToRemove = " ()";
-static void -oc_free( struct objclass **ocp ) -{ - struct objclass *oc; - - if ( NULL != ocp && NULL != *ocp ) { - oc = *ocp; - slapi_ch_free( (void **)&oc->oc_name ); - slapi_ch_free( (void **)&oc->oc_desc ); - slapi_ch_free( (void **)&oc->oc_oid ); - slapi_ch_free( (void **)&oc->oc_superior ); - charray_free( oc->oc_required ); - charray_free( oc->oc_allowed ); - charray_free( oc->oc_orig_required ); - charray_free( oc->oc_orig_allowed ); - cool_charray_free( oc->oc_origin ); - slapi_ch_free( (void **)&oc ); - *ocp = NULL; + /* get rid of all the parens and spaces */ + for ( i = 0, k = 0; vals[i]; i++) { + if (!strchr(charsToRemove, vals[i])) { + vals[k++] = vals[i]; } + } + vals[k] = '\0'; + retVal = slapi_str2charray (vals, "$"); + return retVal; }
/* @@ -3137,14 +3288,13 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf, int syntaxlength; char **attr_names = NULL; char *first_attr_name = NULL; - char **attr_origins = NULL; int num_names = 0; - int num_origins = 0; unsigned long flags = SLAPI_ATTR_FLAG_OVERRIDE; const char *ss = 0; struct asyntaxinfo *tmpasip; int invalid_syntax_error; schema_strstr_fn_t keyword_strstr_fn; + schemaext *extensions = NULL;
/* * From RFC 2252 section 4.2: @@ -3344,11 +3494,11 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf, /* X-ORIGIN list */ if (is_user_defined) { /* add X-ORIGIN 'user defined' */ - attr_origins = parse_origin_list( nextinput, &num_origins, - schema_user_defined_origin ); + extensions = parse_extensions( nextinput, schema_user_defined_origin ); } else { - /* add nothing */ - attr_origins = parse_origin_list( nextinput, &num_origins, NULL ); + /* add nothing extra*/ + extensions = parse_extensions( nextinput, NULL ); + flags |= SLAPI_ATTR_FLAG_STD_ATTR; }
/* Do some sanity checking to make sure everything was read correctly */ @@ -3440,17 +3590,6 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf, oc_unlock(); }
- if (!status && !element_is_user_defined( attr_origins )) { - if ( is_user_defined ) { - /* add missing user defined origin string */ - charray_add( &attr_origins, - slapi_ch_strdup( schema_user_defined_origin[0] )); - ++num_origins; - } else { - flags |= SLAPI_ATTR_FLAG_STD_ATTR; - } - } - if (!(schema_flags & DSE_SCHEMA_NO_CHECK) && !status) { int ii; /* check to see if the attribute name is valid */ @@ -3492,10 +3631,9 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf,
if (!status) { - status = attr_syntax_create( pOid, attr_names, num_names, + status = attr_syntax_create( pOid, attr_names, *psbAttrDesc->buffer == '\0' ? NULL : psbAttrDesc->buffer, - pSuperior, - pMREquality, pMROrdering, pMRSubstring, attr_origins, + pSuperior, pMREquality, pMROrdering, pMRSubstring, extensions, pSyntax, syntaxlength, flags, &tmpasip ); }
@@ -3529,7 +3667,6 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf, done: /* free everything */ free_qdlist(attr_names, num_names); - free_qdlist(attr_origins, num_origins); sizedbuffer_destroy(psbAttrName); sizedbuffer_destroy(psbAttrDesc); slapi_ch_free((void **)&pOid); @@ -3538,10 +3675,655 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf, slapi_ch_free((void **)&pMROrdering); slapi_ch_free((void **)&pMRSubstring); slapi_ch_free((void **)&pSyntax); + schema_free_extensions(extensions); + return status; +} + +#else /* (USE_OPENLDAP) */ + + +/* openldap attribute parser */ +/* + * if asipp is NULL, the attribute type is added to the global set of schema. + * if asipp is not NULL, the AT is not added but *asipp is set. When you are + * finished with *asipp, use attr_syntax_free() to dispose of it. + * + * schema_flags: Any or none of the following bits could be set + * DSE_SCHEMA_NO_CHECK -- schema won't be checked + * DSE_SCHEMA_NO_GLOCK -- locking of global resources is turned off; + * this saves time during initialization since + * the server operates in single threaded mode + * at that time or in reload_schemafile_lock. + * DSE_SCHEMA_LOCKED -- already locked with reload_schemafile_lock; + * no further lock needed + * + * if is_user_defined is true, force attribute type to be user defined. + * + * returns an LDAP error code (LDAP_SUCCESS if all goes well) +*/ +static int +parse_attr_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf, + size_t errorbufsize, PRUint32 schema_flags, int is_user_defined, + int schema_ds4x_compat, int is_remote) +{ + struct asyntaxinfo *tmpasip; + struct asyntaxinfo *tmpasi; + schemaext *extensions = NULL, *head = NULL; + struct objclass *poc; + LDAPAttributeType *atype = NULL; + const char *errp; + char *first_attr_name = NULL; + char **attr_names = NULL; + unsigned long flags = SLAPI_ATTR_FLAG_OVERRIDE; + /* If we ever accept openldap schema directly, then make parser_flags configurable */ + const int parser_flags = LDAP_SCHEMA_ALLOW_NONE | LDAP_SCHEMA_ALLOW_NO_OID; + int invalid_syntax_error; + int syntaxlength = SLAPI_SYNTAXLENGTH_NONE; + int num_names = 0; + int status = 0; + int rc = 0; + int a, aa; + + /* + * OpenLDAP AttributeType struct + * + * typedef struct ldap_attributetype { + * char *at_oid; OID + * char **at_names; Names + * char *at_desc; Description + * int at_obsolete; Is obsolete? + * char *at_sup_oid; OID of superior type + * char *at_equality_oid; OID of equality matching rule + * char *at_ordering_oid; OID of ordering matching rule + * char *at_substr_oid; OID of substrings matching rule + * char *at_syntax_oid; OID of syntax of values + * int at_syntax_len; Suggested minimum maximum length + * int at_single_value; Is single-valued? + * int at_collective; Is collective? + * int at_no_user_mod; Are changes forbidden through LDAP? + * int at_usage; Usage, see below + * LDAPSchemaExtensionItem **at_extensions; Extensions + * } LDAPAttributeType; + */ + + /* + * Set the appropriate error code + */ + if ( schema_ds4x_compat ) { + invalid_syntax_error = LDAP_OPERATIONS_ERROR; + } else { + invalid_syntax_error = LDAP_INVALID_SYNTAX; + } + /* + * Verify we have input + */ + if(input == NULL || '\0' == input[0]){ + schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, NULL, + "One or more values are required for the attributeTypes attribute" ); + LDAPDebug ( LDAP_DEBUG_ANY, "NULL args passed to parse_attr_str\n",0,0,0); + return invalid_syntax_error; + } + /* + * Parse the line and create of attribute structure + */ + while(isspace(*input)){ + /* trim any leading spaces */ + input++; + } + if((atype = ldap_str2attributetype(input, &rc, &errp, parser_flags )) == NULL){ + schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, input, + "Failed to parse attribute, error(%d - %s) at (%s)", rc, ldap_scherr2str(rc), errp ); + return invalid_syntax_error; + } + + if (schema_flags & DSE_SCHEMA_NO_GLOCK){ + flags |= SLAPI_ATTR_FLAG_NOLOCKING; + } + /* + * Check the NAME and update our name list + */ + if ( NULL != atype->at_names ) { + for(; atype->at_names[num_names]; num_names++){ + charray_add(&attr_names, slapi_ch_strdup(atype->at_names[num_names])); + } + first_attr_name = atype->at_names[0]; + } else { /* NAME followed by nothing violates syntax */ + schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, input, + "Missing or invalid attribute name" ); + status = invalid_syntax_error; + goto done; + } + /* + * If the attribute type doesn't have an OID, we'll make the oid attrname-oid. + */ + if (NULL == atype->at_oid) { + atype->at_oid = slapi_ch_smprintf("%s-oid", first_attr_name ); + } + /* + * Set the flags + */ + if(atype->at_obsolete){ + flags |= SLAPI_ATTR_FLAG_OBSOLETE; + } + if(atype->at_single_value){ + flags |= SLAPI_ATTR_FLAG_SINGLE; + } + if(atype->at_collective){ + flags |= SLAPI_ATTR_FLAG_COLLECTIVE; + } + if(atype->at_no_user_mod){ + flags |= SLAPI_ATTR_FLAG_NOUSERMOD; + } + if(atype->at_usage == LDAP_SCHEMA_DIRECTORY_OPERATION){ + flags |= SLAPI_ATTR_FLAG_OPATTR; + } + /* + * Check the superior, and use it fill in any missing oids on this attribute + */ + if (NULL != atype->at_sup_oid) { + struct asyntaxinfo *asi_parent; + + asi_parent = attr_syntax_get_by_name(atype->at_sup_oid); + /* if we find no match then server won't start or add the attribute type */ + if (asi_parent == NULL) { + LDAPDebug (LDAP_DEBUG_PARSE, "Cannot find parent attribute type "%s"\n", + atype->at_sup_oid, NULL, NULL); + schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, first_attr_name, + "Missing parent attribute syntax OID"); + status = invalid_syntax_error; + goto done; + + } else if ((NULL == atype->at_syntax_oid) || (NULL == atype->at_equality_oid) || + (NULL == atype->at_substr_oid) || (NULL == atype->at_ordering_oid)) + { + /* + * We only want to use the parent syntax if a SYNTAX + * wasn't explicitly specified for this attribute. + */ + char *pso = asi_parent->asi_plugin->plg_syntax_oid; + + if (pso && (NULL == atype->at_syntax_oid)) { + atype->at_syntax_oid = slapi_ch_strdup(pso); + LDAPDebug (LDAP_DEBUG_TRACE, + "Inheriting syntax %s from parent type %s\n", + atype->at_syntax_oid, atype->at_sup_oid,NULL); + } else if (NULL == atype->at_syntax_oid) { + schema_create_errormsg( errorbuf, errorbufsize, + schema_errprefix_at, first_attr_name, + "Missing parent attribute syntax OID"); + status = invalid_syntax_error; + goto done; + } + + if (NULL == atype->at_equality_oid) { + atype->at_equality_oid = slapi_ch_strdup(asi_parent->asi_mr_equality); + } + if (NULL == atype->at_substr_oid) { + atype->at_substr_oid = slapi_ch_strdup(asi_parent->asi_mr_substring); + } + if (NULL == atype->at_ordering_oid) { + atype->at_ordering_oid = slapi_ch_strdup(asi_parent->asi_mr_ordering); + } + attr_syntax_return( asi_parent ); + } + } + /* + * Make sure we have a syntax oid set + */ + if (NULL == atype->at_syntax_oid) { + schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, + first_attr_name, "Missing attribute syntax OID"); + status = invalid_syntax_error; + goto done; + } + /* + * Make sure the OID is known + */ + if (!status && (plugin_syntax_find ( atype->at_syntax_oid ) == NULL) ) { + schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, + first_attr_name, "Unknown attribute syntax OID "%s"", + atype->at_syntax_oid ); + status = invalid_syntax_error; + goto done; + } + /* + * Check to make sure that the OID isn't being used by an objectclass + */ + if (!(schema_flags & DSE_SCHEMA_LOCKED)){ + oc_lock_read(); + } + poc = oc_find_oid_nolock( atype->at_oid ); + if ( poc != NULL) { + schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, first_attr_name, + "The OID "%s" is also used by the object class "%s"", atype->at_oid, poc->oc_name); + status = LDAP_TYPE_OR_VALUE_EXISTS; + } + if (!(schema_flags & DSE_SCHEMA_LOCKED)){ + oc_unlock(); + } + if(status){ + goto done; + } + /* + * Walk the "at_extensions" and set the schema extensions + */ + for(a = 0; atype->at_extensions && atype->at_extensions[a]; a++){ + schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext)); + newext->term = slapi_ch_strdup(atype->at_extensions[a]->lsei_name); + for (aa = 0; atype->at_extensions[a]->lsei_values && atype->at_extensions[a]->lsei_values[aa]; aa++){ + charray_add(&newext->values, slapi_ch_strdup(atype->at_extensions[a]->lsei_values[aa])); + newext->value_count++; + } + if(extensions == NULL){ + extensions = newext; + head = newext; + } else { + extensions->next = newext; + extensions = newext; + } + } + extensions = head; /* reset to the top of the list */ + /* + * Make sure if we are user-defined, that the attr_origins represents it + */ + if (!extension_is_user_defined( extensions )) { + if ( is_user_defined ) { + int added = 0; + /* see if we have a X-ORIGIN term already */ + while(extensions){ + if(strcmp(extensions->term, "X-ORIGIN") == 0){ + charray_add(&extensions->values, slapi_ch_strdup(schema_user_defined_origin[0])); + extensions->value_count++; + added = 1; + break; + } + extensions = extensions->next; + } + if(!added){ + /* X-ORIGIN is completely missing, add it */ + extensions = head; + schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext)); + newext->term = slapi_ch_strdup("X-ORIGIN"); + charray_add(&newext->values, slapi_ch_strdup(schema_user_defined_origin[0])); + newext->value_count++; + while(extensions && extensions->next){ + /* move to the end of the list */ + extensions = extensions->next; + } + if(extensions == NULL){ + extensions = newext; + head = extensions; + } else { + extensions->next = newext; + } + } + } else { + flags |= SLAPI_ATTR_FLAG_STD_ATTR; + } + } + extensions = head; /* reset to the top of the list */ + /* + * Check to see if the attribute name is valid + */ + if (!(schema_flags & DSE_SCHEMA_NO_CHECK)) { + for (a = 0; a < num_names; ++a) { + if ( schema_check_name(attr_names[a], PR_TRUE, errorbuf, errorbufsize) == 0 ) { + status = invalid_syntax_error; + goto done; + } else if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) && attr_syntax_exists(attr_names[a])) { + schema_create_errormsg( errorbuf, errorbufsize, + schema_errprefix_at, attr_names[a], + "Could not be added because it already exists" ); + status = LDAP_TYPE_OR_VALUE_EXISTS; + goto done; + } + } + } + /* + * Check if the OID is valid + */ + if (!(schema_flags & DSE_SCHEMA_NO_CHECK)) { + if ( schema_check_oid ( first_attr_name, atype->at_oid, PR_TRUE, errorbuf, + errorbufsize ) == 0 ) { + status = invalid_syntax_error; + goto done; + } + } + /* + * Check if the OID is already being used + */ + if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) && ( NULL != (tmpasi = attr_syntax_get_by_oid(atype->at_oid)))) { + schema_create_errormsg( errorbuf, errorbufsize, + schema_errprefix_at, first_attr_name, + "Could not be added because the OID "%s" is already in use", atype->at_oid); + status = LDAP_TYPE_OR_VALUE_EXISTS; + attr_syntax_return( tmpasi ); + goto done; + } + /* + * Finally create the attribute + */ + status = attr_syntax_create( atype->at_oid, attr_names, atype->at_desc, atype->at_sup_oid, + atype->at_equality_oid, atype->at_ordering_oid, atype->at_substr_oid, + extensions, atype->at_syntax_oid, syntaxlength, flags, &tmpasip ); + if (!status) { + if ( NULL != asipp ) { + *asipp = tmpasip; /* just return it */ + } else { + /* add the new attribute to the global store */ + status = attr_syntax_add( tmpasip ); + if ( LDAP_SUCCESS != status ) { + if ( 0 != (flags & SLAPI_ATTR_FLAG_OVERRIDE) && + LDAP_TYPE_OR_VALUE_EXISTS == status ) { + /* + * This can only occur if the name and OID don't match the + * attribute we are trying to override (all other cases of + * "type or value exists" were trapped above). + */ + schema_create_errormsg( errorbuf, errorbufsize, + schema_errprefix_at, first_attr_name, + "Does not match the OID "%s". Another attribute " + "type is already using the name or OID.", atype->at_oid); + } else { + schema_create_errormsg( errorbuf, errorbufsize, + schema_errprefix_at, first_attr_name, + "Could not be added (OID is "%s")", atype->at_oid ); + } + attr_syntax_free( tmpasip ); + } + } + } + + done: + /* free everything */ + ldap_attributetype_free(atype); + charray_free(attr_names); + schema_free_extensions(extensions);
return status; }
+/* + * parse_objclass_str + * + * Read the value of the objectclasses attribute in cn=schema, convert it + * into an objectclass struct. + * + * Arguments: + * + * input : value of objectclasses attribute to read + * oc : pointer write the objectclass to + * errorbuf : buffer to write any errors to + * is_user_defined : if non-zero, force objectclass to be user defined + * schema_flags : Any or none of the following bits could be set + * DSE_SCHEMA_NO_CHECK -- schema won't be checked + * DSE_SCHEMA_NO_GLOCK -- don't lock global resources + * DSE_SCHEMA_LOCKED -- already locked with + * reload_schemafile_lock; + * no further lock needed + * schema_ds4x_compat: if non-zero, act like Netscape DS 4.x + * + * Returns: an LDAP error code + * + * LDAP_SUCCESS if the objectclass was sucessfully read, the new + * objectclass will be written to oc + * + * All others: there was an error, an error message will + * be written to errorbuf + */ +static int +parse_objclass_str ( const char *input, struct objclass **oc, char *errorbuf, + size_t errorbufsize, PRUint32 schema_flags, int is_user_defined, + int schema_ds4x_compat ) +{ + LDAPObjectClass *objClass; + struct objclass *pnew_oc = NULL, *psup_oc = NULL; + schemaext *extensions = NULL, *head = NULL; + const char *errp; + char **OrigRequiredAttrsArray, **OrigAllowedAttrsArray; + char *first_oc_name = NULL; + /* If we ever accept openldap schema directly, then make parser_flags configurable */ + const int parser_flags = LDAP_SCHEMA_ALLOW_NONE | LDAP_SCHEMA_ALLOW_NO_OID; + PRUint8 flags = 0; + int invalid_syntax_error; + int i, j; + int rc = 0; + + /* + * openLDAP Objectclass struct + * + * typedef struct ldap_objectclass { + * char *oc_oid; OID + * char **oc_names; Names + * char *oc_desc; Description + * int oc_obsolete; Is obsolete? + * char **oc_sup_oids; OIDs of superior classes + * int oc_kind; Kind + * char **oc_at_oids_must; OIDs of required attribute types + * char **oc_at_oids_may; OIDs of optional attribute types + * LDAPSchemaExtensionItem **oc_extensions; Extensions + * } LDAPObjectClass; + */ + + /* + * Set the appropriate error code + */ + if ( schema_ds4x_compat ) { + invalid_syntax_error = LDAP_OPERATIONS_ERROR; + } else { + invalid_syntax_error = LDAP_INVALID_SYNTAX; + } + /* + * Verify we have input + */ + if ( NULL == input || '\0' == input[0] ) { + schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, NULL, + "One or more values are required for the objectClasses attribute" ); + LDAPDebug ( LDAP_DEBUG_ANY, "NULL args passed to read_oc_ldif\n",0,0,0); + return LDAP_OPERATIONS_ERROR; + } + /* + * Parse the input and create the openLdap objectclass structure + */ + while(isspace(*input)){ + /* trim any leading spaces */ + input++; + } + if((objClass = ldap_str2objectclass(input, &rc, &errp, parser_flags )) == NULL){ + schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, input, + "Failed to parse objectclass, error(%d) at (%s)", rc, errp ); + return invalid_syntax_error; + } + /* + * Check the NAME and update our name list + */ + if ( NULL != objClass->oc_names ) { + first_oc_name = objClass->oc_names[0]; + } else { /* NAME followed by nothing violates syntax */ + schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, input, + "Missing or invalid objectclass name" ); + rc = invalid_syntax_error; + goto done; + } + /* + * If the objectclass type doesn't have an OID, we'll make the oid objClass-oid. + */ + if (NULL == objClass->oc_oid) { + objClass->oc_oid = slapi_ch_smprintf("%s-oid", first_oc_name ); + } + /* + * Check to see if the objectclass name is valid + */ + if (!(schema_flags & DSE_SCHEMA_NO_CHECK)) { + for (i = 0; objClass->oc_names[i]; ++i) { + if ( schema_check_name(objClass->oc_names[i], PR_TRUE, errorbuf, errorbufsize) == 0 ) { + rc = invalid_syntax_error; + goto done; + } + } + } + /* + * Check if the OID is valid + */ + if (!(schema_flags & DSE_SCHEMA_NO_CHECK)) { + if ( schema_check_oid ( first_oc_name, objClass->oc_oid, PR_TRUE, errorbuf, + errorbufsize ) == 0 ) { + rc = invalid_syntax_error; + goto done; + } + } + /* + * Look for the superior objectclass. We first look for a parenthesized + * list and if not found we look for a simple OID. + * + * XXXmcs: Since we do not yet support multiple superior objectclasses, we + * just grab the first OID in a parenthesized list. + */ + if (!(schema_flags & DSE_SCHEMA_NO_GLOCK)) { + /* needed because we access the superior oc */ + oc_lock_read(); + } + if(objClass->oc_sup_oids && objClass->oc_sup_oids[0]){ + psup_oc = oc_find_nolock ( objClass->oc_sup_oids[0] ); + } + /* + * Walk the "oc_extensions" and set the schema extensions + */ + for(i = 0; objClass->oc_extensions && objClass->oc_extensions[i]; i++){ + schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext)); + newext->term = slapi_ch_strdup(objClass->oc_extensions[i]->lsei_name); + for (j = 0; objClass->oc_extensions[i]->lsei_values && objClass->oc_extensions[i]->lsei_values[j]; j++){ + charray_add(&newext->values, slapi_ch_strdup(objClass->oc_extensions[i]->lsei_values[j])); + newext->value_count++; + } + if(extensions == NULL){ + extensions = newext; + head = extensions; + } else { + extensions->next = newext; + extensions = newext; + } + } + extensions = head; /* reset to the top of the list */ + /* + * Set the remaining flags + */ + if(objClass->oc_obsolete){ + flags |= OC_FLAG_OBSOLETE; + } + if ( extension_is_user_defined( extensions )) { + flags |= OC_FLAG_USER_OC; + } else if ( is_user_defined ) { + int added = 0; + /* see if we have a X-ORIGIN term already */ + while(extensions){ + if(strcmp(extensions->term, "X-ORIGIN") == 0){ + charray_add(&extensions->values, slapi_ch_strdup(schema_user_defined_origin[0])); + extensions->value_count++; + added = 1; + break; + } + extensions = extensions->next; + } + if(!added){ + /* X-ORIGIN is completely missing, add it */ + extensions = head; + schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext)); + newext->term = slapi_ch_strdup("X-ORIGIN"); + charray_add( &newext->values, slapi_ch_strdup( schema_user_defined_origin[0] )); + newext->value_count++; + while(extensions && extensions->next){ + extensions = extensions->next; + } + if(extensions == NULL){ + extensions = newext; + head = extensions; + } else { + extensions->next = newext; + } + } + flags |= OC_FLAG_USER_OC; + } else { + flags |= OC_FLAG_STANDARD_OC; + } + extensions = head; /* reset to the top of the list */ + /* + * Generate OrigRequiredAttrsArray and OrigAllowedAttrsArray from the superior oc + */ + if (psup_oc) { + int found_it; + + OrigRequiredAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ; + OrigRequiredAttrsArray[0] = NULL; + OrigAllowedAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ; + OrigAllowedAttrsArray[0] = NULL; + if (psup_oc->oc_required && objClass->oc_at_oids_must) { + for (i = 0, found_it = 0; objClass->oc_at_oids_must[i]; i++) { + for (j = 0; psup_oc->oc_required[j]; j++) { + if (strcasecmp (psup_oc->oc_required[j], objClass->oc_at_oids_must[i]) == 0) { + found_it = 1; + break; + } + } + if (!found_it) { + charray_add (&OrigRequiredAttrsArray, slapi_ch_strdup ( objClass->oc_at_oids_must[i] ) ); + } + } + } else { + /* we still need to set the originals */ + OrigRequiredAttrsArray = charray_dup(objClass->oc_at_oids_must); + } + if (psup_oc->oc_allowed && objClass->oc_at_oids_may) { + for (i = 0, found_it = 0; objClass->oc_at_oids_may[i]; i++) { + for (j = 0; psup_oc->oc_allowed[j]; j++) { + if (strcasecmp (psup_oc->oc_allowed[j], objClass->oc_at_oids_may[i]) == 0) { + found_it = 1; + break; + } + } + if (!found_it) { + charray_add (&OrigAllowedAttrsArray, slapi_ch_strdup (objClass->oc_at_oids_may[i]) ); + } + } + } else { + /* we still need to set the originals */ + OrigAllowedAttrsArray = charray_dup(objClass->oc_at_oids_may); + } + } else { + /* if no parent oc */ + OrigRequiredAttrsArray = charray_dup ( objClass->oc_at_oids_must ); + OrigAllowedAttrsArray = charray_dup ( objClass->oc_at_oids_may ); + } + if (!(schema_flags & DSE_SCHEMA_NO_GLOCK)) { + oc_unlock(); /* we are done accessing superior oc (psup_oc) */ + } + /* + * Finally - create new the objectclass + */ + pnew_oc = (struct objclass *) slapi_ch_calloc (1, sizeof (struct objclass)); + pnew_oc->oc_name = slapi_ch_strdup ( objClass->oc_names[0] ); + if(objClass->oc_sup_oids){ + pnew_oc->oc_superior = slapi_ch_strdup( objClass->oc_sup_oids[0] ); + } + pnew_oc->oc_oid = slapi_ch_strdup( objClass->oc_oid ); + pnew_oc->oc_desc = slapi_ch_strdup( objClass->oc_desc ); + pnew_oc->oc_required = charray_dup( objClass->oc_at_oids_must ); + pnew_oc->oc_allowed = charray_dup( objClass->oc_at_oids_may ); + pnew_oc->oc_orig_required = OrigRequiredAttrsArray; + pnew_oc->oc_orig_allowed = OrigAllowedAttrsArray; + pnew_oc->oc_kind = objClass->oc_kind; + pnew_oc->oc_extensions = extensions; + pnew_oc->oc_next = NULL; + pnew_oc->oc_flags = flags; + + *oc = pnew_oc; + +done: + ldap_objectclass_free(objClass); + + return rc; +} +#endif
/* * schema_check_oc_attrs: @@ -3925,7 +4707,7 @@ load_schema_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *ignored, if (flags & DSE_SCHEMA_NO_LOAD) { struct asyntaxinfo *tmpasip = NULL; - if ((*returncode = read_at_ldif(s, &tmpasip, returntext, + if ((*returncode = parse_at_str(s, &tmpasip, returntext, SLAPI_DSE_RETURNTEXT_SIZE, flags, primary_file /* force user defined? */, schema_ds4x_compat, 0)) != 0) @@ -3934,7 +4716,7 @@ load_schema_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *ignored, } else { - if ((*returncode = read_at_ldif(s, NULL, returntext, + if ((*returncode = parse_at_str(s, NULL, returntext, SLAPI_DSE_RETURNTEXT_SIZE, flags, primary_file /* force user defined? */, schema_ds4x_compat, 0)) != 0) @@ -3962,7 +4744,7 @@ load_schema_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *ignored, const char *s = slapi_value_get_string(v); if (!s) continue; - if ( LDAP_SUCCESS != (*returncode = read_oc_ldif(s, &oc, returntext, + if ( LDAP_SUCCESS != (*returncode = parse_oc_str(s, &oc, returntext, SLAPI_DSE_RETURNTEXT_SIZE, flags, primary_file /* force user defined? */, schema_ds4x_compat))) { @@ -4091,6 +4873,7 @@ init_schema_dse_ext(char *schemadir, Slapi_Backend *be, if(rc) { char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE] = {0}; + char *attr_str; int dont_write = 1; int merge = 1; int dont_dup_check = 1; @@ -4108,22 +4891,26 @@ init_schema_dse_ext(char *schemadir, Slapi_Backend *be, /* add the objectclass attribute so we can do some basic schema checking during initialization; this will be overridden when its "real" definition is read from the schema conf files */ + +#ifdef USE_OPENLDAP + attr_str = "( 2.5.4.0 NAME 'objectClass' " + "DESC 'Standard schema for LDAP' SYNTAX " + "1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )"; +#else + attr_str = "attributeTypes: ( 2.5.4.0 NAME 'objectClass' " + "DESC 'Standard schema for LDAP' SYNTAX " + "1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )"; +#endif if (schema_flags & DSE_SCHEMA_NO_LOAD) { struct asyntaxinfo *tmpasip = NULL; - rc = read_at_ldif("attributeTypes: ( 2.5.4.0 NAME 'objectClass' " - "DESC 'Standard schema for LDAP' SYNTAX " - "1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )", - &tmpasip, errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + rc = parse_at_str(attr_str, &tmpasip, errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, DSE_SCHEMA_NO_GLOCK|schema_flags, 0, 0, 0); attr_syntax_free( tmpasip ); /* trash it */ } else { - rc = read_at_ldif("attributeTypes: ( 2.5.4.0 NAME 'objectClass' " - "DESC 'Standard schema for LDAP' SYNTAX " - "1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )", - NULL, errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + rc = parse_at_str(attr_str, NULL, errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, schema_flags, 0, 0, 0); } if (rc) @@ -4202,6 +4989,127 @@ init_schema_dse(const char *configdir) return rc; }
+#if !defined (USE_OPENLDAP) + +static char ** +parse_xstring_list( const char *schema_value, const char *name, size_t namelen, int *num_xvalsp, + char **default_list ) +{ + char *start, *end, *xval_tmp; + char **xvals = NULL; + + if (( start = PL_strstr ( schema_value, name )) != NULL) { + start += namelen+1; /* +1 for space */ + xval_tmp = slapi_ch_strdup( start ); + if ( *start == '(' ) { + end = strchr( xval_tmp, ')' ); + } else { + end = strchr( xval_tmp + 1, ''' ); + } + if (end) { + *(end+1) = 0; + } + xvals = parse_qdstrings( xval_tmp, num_xvalsp ); + slapi_ch_free( (void **)&xval_tmp ); + } else { + xvals = NULL; + *num_xvalsp = 0; + } + + if ( NULL == xvals && NULL != default_list ) { + int i; + + for ( i = 0; default_list[i] != NULL; ++i ) { + ; + } + *num_xvalsp = i; + xvals = (char **)slapi_ch_malloc( (i+1) * sizeof(char *)); + for ( i = 0; default_list[i] != NULL; ++i ) { + xvals[i] = slapi_ch_strdup( default_list[i] ); + } + xvals[i] = NULL; + } + +/* for debugging +if ( xvals == NULL || xvals[0] == NULL ) { + LDAPDebug( LDAP_DEBUG_ANY, "no xstring values for xstring (%s) in (%s)\n", name, schema_value, 0 ); +} +*/ + + return xvals; +} + +/* used by mozldap read_at_ldif() & read_oc_ldif() */ +static schemaext* +parse_extensions( const char *schema_value, char **default_list ) +{ + schemaext *extensions = NULL, *head = NULL; + char *input, *token, *iter = NULL; + int i; + + /* + * First make a copy of the input, then grab all the "X-" words, + * and extract the values. + */ + input = slapi_ch_strdup(schema_value); + token = ldap_utf8strtok_r(input, " ", &iter); + while(token){ + if(strncmp(token,"X-", 2) == 0){ + /* we have a new extension */ + schemaext *newext; + newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext)); + newext->term = slapi_ch_strdup(token); + newext->values = parse_xstring_list(schema_value, token, strlen(token), &newext->value_count, default_list); + if(extensions == NULL){ + extensions = newext; + head = newext; + } else { + extensions->next = newext; + extensions = extensions->next; + } + } + token = ldap_utf8strtok_r(iter, " ", &iter); + } + extensions = head; + /* + * Ok, if X-ORIGIN was not specified, then add it with the default values + */ + if ( !extension_is_user_defined(extensions) && default_list ) { + int added = 0; + while(extensions){ + if(strcmp(extensions->term, "X-ORIGIN") == 0){ + charray_add(&extensions->values, slapi_ch_strdup(default_list[0]) ); + extensions->value_count++; + added = 1; + extensions = head; + break; + } + extensions = extensions->next; + } + if(!added){ + schemaext *newext = (schemaext *)slapi_ch_calloc(1, sizeof (schemaext)); + newext->term = slapi_ch_strdup("X-ORIGIN"); + for ( i = 0; default_list[i]; ++i ){ + newext->value_count++; + charray_add(&newext->values, slapi_ch_strdup(default_list[i]) ); + } + extensions = head; + while(extensions && extensions->next){ + /* move to the end of the list */ + extensions = extensions->next; + } + if(extensions == NULL){ + extensions = newext; + } else { + extensions->next = newext; + } + } + } + slapi_ch_free_string(&input); + + return extensions; +} + /* * Look for `keyword' within `*inputp' and return the flag_value if found * (zero if returned if not found). @@ -4318,6 +5226,7 @@ get_tagged_oid( const char *tag, const char **inputp, return( oid ); }
+#endif
/* * sprintf to `outp' the contents of `tag' followed by `oid' followed by a @@ -4387,7 +5296,6 @@ strcat_oids( char *buf, char *prefix, char **oids, int schema_ds4x_compat ) } }
- /* * Add to `buf' a string of the form: * @@ -4404,49 +5312,62 @@ strcat_oids( char *buf, char *prefix, char **oids, int schema_ds4x_compat ) * is calculated and returned. This is useful if you need to allocate * space before calling this function will a buffer. * - * If qdlist is NULL or an empty array, `buf' is not touched and zero - * is returned. */ static size_t strcat_qdlist( char *buf, char *prefix, char **qdlist ) { - int i; - char *start, *p; - size_t len = 0; - - if ( NULL != qdlist && NULL != qdlist[0] ) { - if ( NULL == buf ) { /* calculate length only */ - len += strlen( prefix ); - if ( NULL != qdlist[1] ) { - len += 4; /* surrounding spaces and '(' and ')' */ - } - for ( i = 0; NULL != qdlist[i]; ++i ) { - len += 3; /* leading space and quote marks */ - len += strlen(qdlist[i]); - } - ++len; /* trailing space */ + int i; + char *start, *p; + size_t len = 0; + + if ( NULL != qdlist && NULL != qdlist[0] ) { + if ( NULL == buf ) { /* calculate length only */ + len += strlen( prefix ); + if ( NULL != qdlist[1] ) { + len += 4; /* surrounding spaces and '(' and ')' */ + } + for ( i = 0; NULL != qdlist[i]; ++i ) { + len += 3; /* leading space and quote marks */ + len += strlen(qdlist[i]); + } + ++len; /* trailing space */
- } else { - p = start = buf + strlen(buf); /* skip past existing content */ - if ( NULL == qdlist[1] ) { /* just one string */ - p += sprintf( p, "%s '%s' ", prefix, qdlist[0] ); - } else { /* a list of strings */ - p += sprintf( p, "%s (", prefix ); - for ( i = 0; qdlist[i] != NULL; ++i ) { - p += sprintf( p, " '%s'", qdlist[i] ); - } - *p++ = ' '; - *p++ = ')'; - *p++ = ' '; - *p = '\0'; - } - len = p - start; - } - } + } else { + p = start = buf + strlen(buf); /* skip past existing content */ + if ( NULL == qdlist[1] ) { /* just one string */ + p += sprintf( p, "%s '%s' ", prefix, qdlist[0] ); + } else { /* a list of strings */ + p += sprintf( p, "%s (", prefix ); + for ( i = 0; qdlist[i] != NULL; ++i ) { + p += sprintf( p, " '%s'", qdlist[i] ); + } + *p++ = ' '; + *p++ = ')'; + *p++ = ' '; + *p = '\0'; + } + len = p - start; + } + }
- return( len ); + return( len ); }
+/* + * Loop over the extensions calling strcat_qdlist for each one. + */ +static size_t +strcat_extensions( char *buf, schemaext *extension ) +{ + size_t len = 0; + + while(extension){ + len += strcat_qdlist(buf, extension->term, extension->values); + extension = extension->next; + } + + return( len ); +}
/* * Just like strlen() except that 0 is returned if `s' is NULL. @@ -4480,83 +5401,23 @@ strcpy_count( char *dst, const char *src ) return( p - dst ); }
- -/* - * Look for an X-ORIGIN list in `schema_value' and return a - * qdstrings array (or NULL if no list is present). *num_originsp is - * set to a count of the number of origin strings returned. - * - * If no X-ORIGIN list is found and `default_list' is non-NULL, a copy - * of default list is returned. - */ -static char ** -parse_origin_list( const char *schema_value, int *num_originsp, - char **default_list ) -{ - char *start, *end, *origin_tmp; - char **origins = NULL; - - if (( start = PL_strstr ( schema_value, "X-ORIGIN ")) != NULL ) { - start += 9; - origin_tmp = slapi_ch_strdup( start ); - if ( *start == '(' ) { - end = strchr( origin_tmp, ')' ); - } else { - end = strchr( origin_tmp + 1, ''' ); - } - if (end) { - *(end+1) = 0; - } - origins = parse_qdstrings( origin_tmp, num_originsp ); - slapi_ch_free( (void **)&origin_tmp ); - } else { - origins = NULL; - *num_originsp = 0; - } - - if ( NULL == origins && NULL != default_list ) { - int i; - - for ( i = 0; default_list[i] != NULL; ++i ) { - ; - } - *num_originsp = i; - origins = (char **)slapi_ch_malloc( (i+1) * sizeof(char *)); - for ( i = 0; default_list[i] != NULL; ++i ) { - origins[i] = slapi_ch_strdup( default_list[i] ); - } - origins[i] = NULL; - } - -/* for debugging -if ( origins == NULL || origins[0] == NULL ) { - LDAPDebug( LDAP_DEBUG_ANY, "no origin (%s)\n", schema_value, 0, 0 ); -} -*/ - - return origins; -} - - -/* - * Determine based on origin whether a schema element is standard or - * user-defined. Algorithm: perform a case insensitive search for - * "user defined". If found, return 1 (user defined); if not, return 0. - */ static int -element_is_user_defined( char * const *origins ) +extension_is_user_defined( schemaext *extensions ) { - int i; - - if ( origins != NULL ) { - for ( i = 0; origins[i] != NULL; ++i ) { - if ( 0 == strcasecmp( schema_user_defined_origin[0], origins[i] )) { - return 1; - } - } - } + while(extensions){ + if(strcasecmp(extensions->term, "X-ORIGIN") == 0 ){ + int i = 0; + while(extensions->values && extensions->values[i]){ + if(strcasecmp(schema_user_defined_origin[0], extensions->values[i]) == 0) { + return 1; + } + i++; + } + } + extensions = extensions->next; + }
- return 0; + return 0; }
@@ -4981,3 +5842,4 @@ slapi_schema_get_superior_name(const char *ocname_or_oid) oc_unlock(); return superior; } + diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index b0ac7b3..b84dd15 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -491,6 +491,14 @@ typedef struct oid_item { struct oid_item *oi_next; } oid_item_t;
+/* schema extension item: X-ORIGIN, X-CSN, etc */ +typedef struct schemaext { + char *term; + char **values; + int value_count; + struct schemaext *next; +} schemaext; + /* attribute description (represents an attribute, but not the value) */ typedef struct asyntaxinfo { char *asi_oid; /* OID */ @@ -501,7 +509,7 @@ typedef struct asyntaxinfo { char *asi_mr_equality; /* equality matching rule */ char *asi_mr_ordering; /* ordering matching rule */ char *asi_mr_substring; /* substring matching rule */ - char **asi_origin; /* X-ORIGIN extension */ + schemaext *asi_extensions; /* schema extensions (X-ORIGIN, X-?????, ...) */ struct slapdplugin *asi_plugin; /* syntax */ unsigned long asi_flags; /* SLAPI_ATTR_FLAG_... */ int asi_syntaxlength; /* length associated w/syntax */ @@ -676,25 +684,25 @@ extern struct attrs_in_extension attrs_in_extension[]; #define OC_FLAG_OBSOLETE 8
/* values for oc_kind */ -#define OC_KIND_STRUCTURAL 0 -#define OC_KIND_AUXILIARY 1 -#define OC_KIND_ABSTRACT 2 +#define OC_KIND_ABSTRACT 0 +#define OC_KIND_STRUCTURAL 1 +#define OC_KIND_AUXILIARY 2
/* XXXmcs: ../plugins/cos/cos_cache.c has its own copy of this definition! */ struct objclass { - char *oc_name; /* NAME */ - char *oc_desc; /* DESC */ - char *oc_oid; /* object identifier */ - char *oc_superior; /* SUP -- XXXmcs: should be an array */ - PRUint8 oc_kind; /* ABSTRACT/STRUCTURAL/AUXILIARY */ - PRUint8 oc_flags; /* misc. flags, e.g., OBSOLETE */ - char **oc_required; - char **oc_allowed; - char **oc_orig_required; /* MUST */ - char **oc_orig_allowed; /* MAY */ - char **oc_origin; /* X-ORIGIN extension */ - struct objclass *oc_next; + char *oc_name; /* NAME */ + char *oc_desc; /* DESC */ + char *oc_oid; /* object identifier */ + char *oc_superior; /* SUP -- XXXmcs: should be an array */ + PRUint8 oc_kind; /* ABSTRACT/STRUCTURAL/AUXILIARY */ + PRUint8 oc_flags; /* misc. flags, e.g., OBSOLETE */ + char **oc_required; + char **oc_allowed; + char **oc_orig_required; /* MUST */ + char **oc_orig_allowed; /* MAY */ + schemaext *oc_extensions; /* schema extensions (X-ORIGIN, X-?????, ...) */ + struct objclass *oc_next; };
struct matchingRuleList { diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index 05b9742..ffcc928 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -5440,6 +5440,21 @@ char ** slapi_ch_array_dup( char **array ); void slapi_ch_array_add( char ***array, char *string );
/** + * Add a string to an array of strings + * + * \param array The array to add the string to + * \param string The string to add to the array + * \warning The \c string parameter is not copied. If you do not + * want to hand the memory used by \c string over to the + * array, you should duplicate it first by calling the + * slapi_ch_strdup() function. + * \warning If \c *a is \c NULL, a new array will be allocated. + * \see slapi_ch_array_free() + * \return the total number of elements in the array. + */ +int slapi_ch_array_add_ext(char ***array, char *string); + +/** * Find a string in an array of strings * * \param array The array of strings
389-commits@lists.fedoraproject.org