This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
#include "ldb/include/ldb_private.h"
#include "auth/auth.h"
#include "libcli/security/security.h"
+#include "dsdb/samdb/samdb.h"
/* Kludge ACL rules:
*
int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
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)
+{
+ struct ldb_message_element *oc_el;
+ struct ldb_message_element *allowedAttributes;
+ const struct dsdb_schema *schema = dsdb_get_schema(ldb);
+ const struct dsdb_class *class;
+ int i, j, ret;
+ /* Must remove any existing attribute, or else confusion reins */
+ ldb_msg_remove_attr(msg, attrName);
+ ret = ldb_msg_add_empty(msg, attrName, 0, &allowedAttributes);
+ 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->mayContain && class->mayContain[j]; j++) {
+ ldb_msg_add_string(msg, attrName, class->mayContain[j]);
+ }
+ for (j=0; class->mustContain && class->mustContain[j]; j++) {
+ ldb_msg_add_string(msg, attrName, class->mustContain[j]);
+ }
+ for (j=0; class->systemMayContain && class->systemMayContain[j]; j++) {
+ ldb_msg_add_string(msg, attrName, class->systemMayContain[j]);
+ }
+ for (j=0; class->systemMustContain && class->systemMustContain[j]; j++) {
+ ldb_msg_add_string(msg, attrName, class->systemMustContain[j]);
+ }
+ }
+
+ if (allowedAttributes->num_values > 1) {
+ qsort(allowedAttributes->values,
+ allowedAttributes->num_values,
+ sizeof(*allowedAttributes->values),
+ (comparison_fn_t)data_blob_cmp);
+
+ for (i=1 ; i < allowedAttributes->num_values; i++) {
+ struct ldb_val *val1 = &allowedAttributes->values[i-1];
+ struct ldb_val *val2 = &allowedAttributes->values[i];
+ if (data_blob_cmp(val1, val2) == 0) {
+ memmove(val1, val2, (allowedAttributes->num_values - i) * sizeof( struct ldb_val));
+ allowedAttributes->num_values--;
+ i--;
+ }
+ }
+ }
+
+ 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;
+ /* Must remove any existing attribute, or else confusion reins */
+ ldb_msg_remove_attr(msg, attrName);
+ 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)
{
struct kludge_acl_context *ac;
struct kludge_private_data *data;
- int i;
+ int i, ret;
if (!context || !ares) {
ldb_set_errstring(ldb, "NULL Context or Result in callback");
ac = talloc_get_type(context, struct kludge_acl_context);
data = talloc_get_type(ac->module->private_data, struct kludge_private_data);
- if (ares->type == LDB_REPLY_ENTRY
- && data->password_attrs) /* if we are not initialized just get through */
+ if (ares->type != LDB_REPLY_ENTRY) {
+ return ac->up_callback(ldb, ac->up_context, ares);
+ }
+
+ if (ac->allowedAttributes) {
+ 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 */
{
switch (ac->user_type) {
case SYSTEM:
case ADMINISTRATOR:
+ if (ac->allowedAttributesEffective) {
+ ret = kludge_acl_allowedAttributes(ldb, ares->message, "allowedAttributesEffective");
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ if (ac->allowedChildClassesEffective) {
+ ret = kludge_acl_childClasses(ldb, ares->message, "allowedChildClassesEffective");
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
break;
default:
/* remove password attributes */
}
}
+ 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");
+ }
+
return ac->up_callback(ldb, ac->up_context, ares);
error:
ac->up_context = req->context;
ac->up_callback = req->callback;
ac->user_type = what_is_user(module);
+ ac->attrs = req->op.search.attrs;
down_req = talloc_zero(req, struct ldb_request);
if (down_req == NULL) {
down_req->op.search.scope = req->op.search.scope;
down_req->op.search.tree = req->op.search.tree;
down_req->op.search.attrs = req->op.search.attrs;
-
+
+ ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
+
+ ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "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");
+ }
/* FIXME: I hink we should copy the tree and keep the original
* unmodified. SSS */
just as we would not allow that attribute to be returned */
switch (ac->user_type) {
case SYSTEM:
- case ADMINISTRATOR:
break;
default:
/* remove password attributes */
.modify = kludge_acl_change,
.del = kludge_acl_change,
.rename = kludge_acl_change,
+ .extended = kludge_acl_change,
.init_context = kludge_acl_init
};