Index: dsdb/schema/schema_init.c =================================================================== --- dsdb/schema/schema_init.c (revision 24009) +++ dsdb/schema/schema_init.c (working copy) @@ -492,16 +492,18 @@ GET_STRING_LDB(msg, "subClassOf", mem_ctx, obj, subClassOf, True); obj->systemAuxiliaryClass = NULL; - obj->systemPossSuperiors = NULL; obj->auxiliaryClass = NULL; - obj->possSuperiors = NULL; GET_STRING_LIST_LDB(msg, "systemMustContain", mem_ctx, obj, systemMustContain, False); GET_STRING_LIST_LDB(msg, "systemMayContain", mem_ctx, obj, systemMayContain, False); GET_STRING_LIST_LDB(msg, "mustContain", mem_ctx, obj, mustContain, False); GET_STRING_LIST_LDB(msg, "mayContain", mem_ctx, obj, mayContain, False); + GET_STRING_LIST_LDB(msg, "systemPossSuperiors", mem_ctx, obj, systemPossSuperiors, False); + GET_STRING_LIST_LDB(msg, "possSuperiors", mem_ctx, obj, possSuperiors, False); + GET_STRING_LIST_LDB(msg, "possibleInferiors", mem_ctx, obj, possibleInferiors, False); + GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False); GET_UINT32_LDB(msg, "schemaFlagsEx", obj, schemaFlagsEx); @@ -832,6 +834,8 @@ obj->mustContain = NULL; obj->mayContain = NULL; + obj->possibleInferiors = NULL; + GET_STRING_DS(schema, r, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, False); GET_UINT32_DS(schema, r, "schemaFlagsEx", obj, schemaFlagsEx); Index: dsdb/schema/schema.h =================================================================== --- dsdb/schema/schema.h (revision 24009) +++ dsdb/schema/schema.h (working copy) @@ -111,6 +111,7 @@ const char **possSuperiors; const char **mustContain; const char **mayContain; + const char **possibleInferiors; const char *defaultSecurityDescriptor; Index: dsdb/samdb/ldb_modules/kludge_acl.c =================================================================== --- dsdb/samdb/ldb_modules/kludge_acl.c (revision 24010) +++ dsdb/samdb/ldb_modules/kludge_acl.c (working copy) @@ -107,13 +107,15 @@ enum user_is user_type; bool allowedAttributes; bool allowedAttributesEffective; + bool allowedChildClasses; + bool allowedChildClassesEffective; const char **attrs; }; /* read all objectClasses */ static int kludge_acl_allowedAttributes(struct ldb_context *ldb, struct ldb_message *msg, - const char *attrName) + const char *attrName) { struct ldb_message_element *oc_el; struct ldb_message_element *allowedAttributes; @@ -129,12 +131,13 @@ we alter the element array in ldb_msg_add_empty() */ oc_el = ldb_msg_find_element(msg, "objectClass"); - for (i=0; i < oc_el->num_values; i++) { + for (i=0; oc_el && i < oc_el->num_values; i++) { class = dsdb_class_by_lDAPDisplayName(schema, (const char *)oc_el->values[i].data); if (!class) { /* We don't know this class? what is going on? */ continue; } + for (j=0; class->mayContain && class->mayContain[j]; j++) { ldb_msg_add_string(msg, attrName, class->mayContain[j]); } @@ -169,7 +172,58 @@ return 0; } +/* read all objectClasses */ +static int kludge_acl_childClasses(struct ldb_context *ldb, struct ldb_message *msg, + const char *attrName) +{ + struct ldb_message_element *oc_el; + struct ldb_message_element *allowedClasses; + const struct dsdb_schema *schema = dsdb_get_schema(ldb); + const struct dsdb_class *class; + int i, j, ret; + ret = ldb_msg_add_empty(msg, attrName, 0, &allowedClasses); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* To ensure that oc_el is valid, we must look for it after + we alter the element array in ldb_msg_add_empty() */ + oc_el = ldb_msg_find_element(msg, "objectClass"); + + for (i=0; oc_el && i < oc_el->num_values; i++) { + class = dsdb_class_by_lDAPDisplayName(schema, (const char *)oc_el->values[i].data); + if (!class) { + /* We don't know this class? what is going on? */ + continue; + } + + for (j=0; class->possibleInferiors && class->possibleInferiors[j]; j++) { + ldb_msg_add_string(msg, attrName, class->possibleInferiors[j]); + } + } + + if (allowedClasses->num_values > 1) { + qsort(allowedClasses->values, + allowedClasses->num_values, + sizeof(*allowedClasses->values), + (comparison_fn_t)data_blob_cmp); + + for (i=1 ; i < allowedClasses->num_values; i++) { + struct ldb_val *val1 = &allowedClasses->values[i-1]; + struct ldb_val *val2 = &allowedClasses->values[i]; + if (data_blob_cmp(val1, val2) == 0) { + memmove(val1, val2, (allowedClasses->num_values - i) * sizeof( struct ldb_val)); + allowedClasses->num_values--; + i--; + } + } + } + + return 0; + +} + /* find all attributes allowed by all these objectClasses */ static int kludge_acl_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) @@ -194,8 +248,15 @@ ret = kludge_acl_allowedAttributes(ldb, ares->message, "allowedAttributes"); if (ret != LDB_SUCCESS) { return ret; + } } + if (ac->allowedChildClasses) { + ret = kludge_acl_childClasses(ldb, ares->message, "allowedChildClasses"); + if (ret != LDB_SUCCESS) { + return ret; + } + } if (data && data->password_attrs) /* if we are not initialized just get through */ { @@ -208,6 +269,12 @@ return ret; } } + if (ac->allowedChildClassesEffective) { + ret = kludge_acl_childClasses(ldb, ares->message, "allowedChildClassesEffective"); + if (ret != LDB_SUCCESS) { + return ret; + } + } break; default: /* remove password attributes */ @@ -217,7 +284,8 @@ } } - if ((ac->allowedAttributes || ac->allowedAttributesEffective) && + if ((ac->allowedAttributes || ac->allowedAttributesEffective + || ac->allowedChildClasses || ac->allowedChildClassesEffective) && (!ldb_attr_in_list(ac->attrs, "objectClass") && !ldb_attr_in_list(ac->attrs, "*"))) { ldb_msg_remove_attr(ares->message, "objectClass"); @@ -267,7 +335,11 @@ ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective"); - if (ac->allowedAttributes || ac->allowedAttributesEffective) { + ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses"); + + ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective"); + + if (ac->allowedAttributes || ac->allowedAttributesEffective || ac->allowedChildClasses || ac->allowedChildClassesEffective) { down_req->op.search.attrs = ldb_attr_list_copy_add(down_req, down_req->op.search.attrs, "objectClass"); }