From 628e2b353e2dd6ac6aaac39067667ed27cacfb59 Mon Sep 17 00:00:00 2001 From: Noriko Hosoi Date: Sep 25 2012 04:23:36 +0000 Subject: Trac Ticket #470 - 389 prevents from adding a posixaccount with userpassword after schema reload https://fedorahosted.org/389/ticket/470 Bug description: Schema reload task reloads schema files in the schema directory. Not just them, DS has several internal schema which are not stored in the schema file, which were lost after the schema reload task is executed. One of them unhashed# user#password was necessary for adding a posixaccount. Fix description: When registering an internal schema, the schema is stashed in a hash table. When schema reload is executed, the internal schema are reloaded with the external schema. --- diff --git a/ldap/servers/plugins/schema_reload/schema_reload.c b/ldap/servers/plugins/schema_reload/schema_reload.c index 82d8e2e..efc0de2 100644 --- a/ldap/servers/plugins/schema_reload/schema_reload.c +++ b/ldap/servers/plugins/schema_reload/schema_reload.c @@ -170,6 +170,13 @@ schemareload_thread(void *arg) slapi_task_log_notice(task, "Schema reload task finished."); slapi_task_log_status(task, "Schema reload task finished."); slapi_log_error(SLAPI_LOG_FATAL, "schemareload", "Schema reload task finished.\n"); + + slapi_log_error(SLAPI_LOG_FATAL, "schemareload", + "Register internal schema.\n"); + rv = slapi_reload_internal_attr_syntax(); + slapi_log_error(SLAPI_LOG_FATAL, "schemareload", + "Register internal schema finished.\n"); + } else { slapi_task_log_notice(task, "Schema reload task failed."); slapi_task_log_status(task, "Schema reload task failed."); @@ -209,8 +216,8 @@ schemareload_destructor(Slapi_Task *task) if (task) { task_data *mydata = (task_data *)slapi_task_get_data(task); if (mydata) { - slapi_ch_free_string(&mydata->schemadir); - slapi_ch_free_string(&mydata->bind_dn); + slapi_ch_free_string(&mydata->schemadir); + slapi_ch_free_string(&mydata->bind_dn); /* Need to cast to avoid a compiler warning */ slapi_ch_free((void **)&mydata); } diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c index 36ed768..f134fa4 100644 --- a/ldap/servers/slapd/attrsyntax.c +++ b/ldap/servers/slapd/attrsyntax.c @@ -56,6 +56,7 @@ static PLHashTable *oid2asi = NULL; /* read/write lock to protect table */ static Slapi_RWLock *oid2asi_lock = NULL; +static PLHashTable *internalasi = NULL; /* * This hashtable maps the name or alias of the attribute to the @@ -888,13 +889,23 @@ attr_syntax_enumerate_internal(PLHashEntry *he, PRIntn i, void *arg) return rc; } -void -attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock ) +static void +attr_syntax_enumerate_attrs_ext( PLHashTable *ht, + AttrEnumFunc aef, void *arg ) { struct enum_arg_wrapper eaw; eaw.aef = aef; eaw.arg = arg; + if (!ht) + return; + + PL_HashTableEnumerateEntries(ht, attr_syntax_enumerate_internal, &eaw); +} + +void +attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock ) +{ if (!oid2asi) return; @@ -906,7 +917,7 @@ attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock ) AS_LOCK_READ(name2asi_lock); } - PL_HashTableEnumerateEntries(oid2asi, attr_syntax_enumerate_internal, &eaw); + attr_syntax_enumerate_attrs_ext(oid2asi, aef, arg); if ( writelock ) { AS_UNLOCK_WRITE(oid2asi_lock); @@ -1053,6 +1064,36 @@ slapi_attr_syntax_exists(const char *attr_name) } /* + * Keep the internally added schema in the hash table, + * which are re-added if the schema is reloaded. + */ +static int +attr_syntax_internal_asi_add_ht(struct asyntaxinfo *asip) +{ + if (!internalasi) { + internalasi = PL_NewHashTable(64, hashNocaseString, + hashNocaseCompare, + PL_CompareValues, 0, 0); + } + if (!internalasi) { + slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_internal_asi_add_ht", + "Failed to create HashTable.\n"); + return 1; + } + if (!PL_HashTableLookup(internalasi, asip->asi_oid)) { + struct asyntaxinfo *asip_copy = attr_syntax_dup(asip); + if (!asip_copy) { + slapi_log_error(SLAPI_LOG_FATAL, "attr_syntax_internal_asi_add_ht", + "Failed to duplicate asyntaxinfo: %s.\n", + asip->asi_name); + return 1; + } + PL_HashTableAdd(internalasi, asip_copy->asi_oid, asip_copy); + } + return 0; +} + +/* * Add an attribute syntax using some default flags, etc. * Returns an LDAP error code (LDAP_SUCCESS if all goes well) */ @@ -1083,7 +1124,43 @@ slapi_add_internal_attr_syntax( const char *name, const char *oid, if ( rc == LDAP_SUCCESS ) { rc = attr_syntax_add( asip ); + if ( rc == LDAP_SUCCESS ) { + if (attr_syntax_internal_asi_add_ht(asip)) { + slapi_log_error(SLAPI_LOG_FATAL, + "slapi_add_internal_attr_syntax", + "Failed to stash internal asyntaxinfo: %s.\n", + asip->asi_name); + } + } } return rc; } + +/* Adding internal asyncinfo via slapi_reload_internal_attr_syntax */ +static int +attr_syntax_internal_asi_add(struct asyntaxinfo *asip, void *arg) +{ + struct asyntaxinfo *asip_copy; + if (!asip) { + return 1; + } + /* Copy is needed since when reloading the schema, + * existing syntax info is cleaned up. */ + asip_copy = attr_syntax_dup(asip); + return attr_syntax_add(asip_copy); +} + +/* Reload internal attribute syntax stashed in the internalasi hashtable. */ +int +slapi_reload_internal_attr_syntax() +{ + int rc = LDAP_SUCCESS; + if (!internalasi) { + slapi_log_error(SLAPI_LOG_TRACE, "attr_reload_internal_attr_syntax", + "No internal attribute syntax to reload.\n"); + return rc; + } + attr_syntax_enumerate_attrs_ext(internalasi, attr_syntax_internal_asi_add, NULL); + return rc; +} diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index f277fd3..880ad2c 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -4921,6 +4921,15 @@ void slapi_filter_normalize(Slapi_Filter *f, PRBool norm_values); */ int slapi_attr_syntax_exists(const char *type); +/** + * Reload internally registered attribute syntaxes. + * + * \param none + * \return \c 0 if the reload was successful. + * \return non-0 if the reload failed. + */ +int slapi_reload_internal_attr_syntax(); + /* * slapi_filter_apply() is used to apply a function to each simple filter * component within a complex filter. A 'simple filter' is anything other