+ /* Check we have a valid parent */
+ if (ac->search_res == NULL) {
+ if (ldb_dn_compare(ldb_get_root_basedn(ldb),
+ msg->dn) == 0) {
+ /* Allow the tree to be started */
+
+ /* but don't keep any error string, it's meaningless */
+ ldb_set_errstring(ldb, NULL);
+ } else {
+ ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
+ ldb_dn_get_linearized(msg->dn));
+ talloc_free(mem_ctx);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ } else {
+ const struct ldb_val *parent_guid;
+
+ /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
+ ret = fix_dn(msg,
+ ac->req->op.add.message->dn,
+ ac->search_res->message->dn,
+ &msg->dn);
+
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
+ ldb_dn_get_linearized(ac->req->op.add.message->dn));
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ parent_guid = ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID");
+ if (parent_guid == NULL) {
+ ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not have an objectGUID!",
+ ldb_dn_get_linearized(msg->dn));
+ talloc_free(mem_ctx);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ /* TODO: Check this is a valid child to this parent,
+ * by reading the allowedChildClasses and
+ * allowedChildClasssesEffective attributes */
+ ret = ldb_msg_add_steal_value(msg, "parentGUID", discard_const(parent_guid));
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, failed to add parentGUID",
+ ldb_dn_get_linearized(msg->dn));
+ talloc_free(mem_ctx);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ }
+ if (schema) {
+ ret = fix_attributes(ldb, schema, msg);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ /* This is now the objectClass list from the database */
+ objectclass_element = ldb_msg_find_element(msg, "objectClass");
+
+ if (!objectclass_element) {
+ /* Where did it go? bail now... */
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ ldb_msg_remove_attr(msg, "objectClass");
+ ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
+