Added a check for permissions to modify the RDN attribute on rename.
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / acl.c
1 /*
2   ldb database library
3
4   Copyright (C) Simo Sorce 2006-2008
5   Copyright (C) Nadezhda Ivanova 2009
6   Copyright (C) Anatoliy Atanasov  2009
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23  *  Name: ldb
24  *
25  *  Component: ldb ACL module
26  *
27  *  Description: Module that performs authorisation access checks based on the
28  *               account's security context and the DACL of the object being polled.
29  *               Only DACL checks implemented at this point
30  *
31  *  Authors: Nadezhda Ivanova, Anatoliy Atanasov
32  */
33
34 #include "includes.h"
35 #include "ldb_module.h"
36 #include "auth/auth.h"
37 #include "libcli/security/security.h"
38 #include "dsdb/samdb/samdb.h"
39 #include "librpc/gen_ndr/ndr_security.h"
40 #include "param/param.h"
41 #include "dsdb/samdb/ldb_modules/util.h"
42 #include "lib/util/tsort.h"
43
44 struct extended_access_check_attribute {
45         const char *oa_name;
46         const uint32_t requires_rights;
47 };
48
49 struct acl_private {
50         bool acl_perform;
51         const char **password_attrs;
52 };
53
54 struct acl_context {
55         struct ldb_module *module;
56         struct ldb_request *req;
57         bool am_system;
58         bool allowedAttributes;
59         bool allowedAttributesEffective;
60         bool allowedChildClasses;
61         bool allowedChildClassesEffective;
62         bool sDRightsEffective;
63         const char * const *attrs;
64 };
65
66 bool is_root_base_dn(struct ldb_context *ldb, struct ldb_dn *dn_to_check)
67 {
68         int result;
69         struct ldb_dn *root_base_dn = ldb_get_root_basedn(ldb);
70         result = ldb_dn_compare(root_base_dn,dn_to_check);
71         return (result==0);
72 }
73
74 static struct security_token *acl_user_token(struct ldb_module *module)
75 {
76         struct ldb_context *ldb = ldb_module_get_ctx(module);
77         struct auth_session_info *session_info
78                 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
79         if(!session_info) {
80                 return NULL;
81         }
82         return session_info->security_token;
83 }
84
85 static int acl_module_init(struct ldb_module *module)
86 {
87         struct ldb_context *ldb;
88         struct acl_private *data;
89         int ret, i;
90         TALLOC_CTX *mem_ctx = talloc_new(module);
91         static const char *attrs[] = { "passwordAttribute", NULL };
92         struct ldb_result *res;
93         struct ldb_message *msg;
94         struct ldb_message_element *password_attributes;
95
96         ldb = ldb_module_get_ctx(module);
97
98         ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
99         if (ret != LDB_SUCCESS) {
100                 ldb_debug(ldb, LDB_DEBUG_ERROR,
101                           "acl_module_init: Unable to register control with rootdse!\n");
102                 return LDB_ERR_OPERATIONS_ERROR;
103         }
104
105         data = talloc(module, struct acl_private);
106         if (data == NULL) {
107                 ldb_oom(ldb);
108                 return LDB_ERR_OPERATIONS_ERROR;
109         }
110
111         data->password_attrs = NULL;
112         data->acl_perform = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
113                                          NULL, "acl", "perform", false);
114         ldb_module_set_private(module, data);
115
116         if (!mem_ctx) {
117                 ldb_oom(ldb);
118                 return LDB_ERR_OPERATIONS_ERROR;
119         }
120
121         ret = ldb_search(ldb, mem_ctx, &res,
122                          ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"),
123                          LDB_SCOPE_BASE, attrs, NULL);
124         if (ret != LDB_SUCCESS) {
125                 goto done;
126         }
127         if (res->count == 0) {
128                 goto done;
129         }
130
131         if (res->count > 1) {
132                 talloc_free(mem_ctx);
133                 return LDB_ERR_CONSTRAINT_VIOLATION;
134         }
135
136         msg = res->msgs[0];
137
138         password_attributes = ldb_msg_find_element(msg, "passwordAttribute");
139         if (!password_attributes) {
140                 goto done;
141         }
142         data->password_attrs = talloc_array(data, const char *, password_attributes->num_values + 1);
143         if (!data->password_attrs) {
144                 talloc_free(mem_ctx);
145                 ldb_oom(ldb);
146                 return LDB_ERR_OPERATIONS_ERROR;
147         }
148         for (i=0; i < password_attributes->num_values; i++) {
149                 data->password_attrs[i] = (const char *)password_attributes->values[i].data;
150                 talloc_steal(data->password_attrs, password_attributes->values[i].data);
151         }
152         data->password_attrs[i] = NULL;
153
154 done:
155         talloc_free(mem_ctx);
156         return ldb_next_init(module);
157 }
158
159 static int get_sd_from_ldb_message(TALLOC_CTX *mem_ctx,
160                                    struct ldb_message *acl_res,
161                                    struct security_descriptor **sd)
162 {
163         struct ldb_message_element *sd_element;
164         enum ndr_err_code ndr_err;
165
166         sd_element = ldb_msg_find_element(acl_res, "nTSecurityDescriptor");
167         if (!sd_element) {
168                 *sd = NULL;
169                 return LDB_SUCCESS;
170         }
171         *sd = talloc(mem_ctx, struct security_descriptor);
172         if(!*sd) {
173                 return LDB_ERR_OPERATIONS_ERROR;
174         }
175         ndr_err = ndr_pull_struct_blob(&sd_element->values[0], *sd, NULL, *sd,
176                                        (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
177
178         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
179                 return LDB_ERR_OPERATIONS_ERROR;
180         }
181
182         return LDB_SUCCESS;
183 }
184
185 static const struct GUID *get_oc_guid_from_message(struct ldb_module *module,
186                                                    struct ldb_message *msg)
187 {
188         struct ldb_message_element *oc_el;
189         struct ldb_context *ldb = ldb_module_get_ctx(module);
190
191         oc_el = ldb_msg_find_element(msg, "objectClass");
192         if (!oc_el) {
193                 return NULL;
194         }
195
196         return class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb),
197                                                       (char *)oc_el->values[oc_el->num_values-1].data);
198 }
199
200 static int get_dom_sid_from_ldb_message(TALLOC_CTX *mem_ctx,
201                                    struct ldb_message *acl_res,
202                                    struct dom_sid **sid)
203 {
204         struct ldb_message_element *sid_element;
205         enum ndr_err_code ndr_err;
206
207         sid_element = ldb_msg_find_element(acl_res, "objectSid");
208         if (!sid_element) {
209                 *sid = NULL;
210                 return LDB_SUCCESS;
211         }
212         *sid = talloc(mem_ctx, struct dom_sid);
213         if(!*sid) {
214                 return LDB_ERR_OPERATIONS_ERROR;
215         }
216         ndr_err = ndr_pull_struct_blob(&sid_element->values[0], *sid, NULL, *sid,
217                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
218
219         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
220                 return LDB_ERR_OPERATIONS_ERROR;
221         }
222
223         return LDB_SUCCESS;
224 }
225
226
227 static void acl_debug(struct security_descriptor *sd,
228                       struct security_token *token,
229                       struct ldb_dn *dn,
230                       bool denied,
231                       int level)
232 {
233         if (denied) {
234                 DEBUG(level, ("Access on %s denied", ldb_dn_get_linearized(dn)));
235         } else {
236                 DEBUG(level, ("Access on %s granted", ldb_dn_get_linearized(dn)));
237         }
238
239         DEBUG(level,("Security context: %s\n",
240                      ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_token,"", token)));
241         DEBUG(level,("Security descriptor: %s\n",
242                      ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_descriptor,"", sd)));
243 }
244
245 static int check_access_on_dn(struct ldb_module *module,
246                               TALLOC_CTX *mem_ctx,
247                               struct ldb_dn *dn,
248                               uint32_t access,
249                               struct object_tree *tree)
250 {
251         int ret;
252         struct ldb_context *ldb = ldb_module_get_ctx(module);
253         struct ldb_result *acl_res;
254         struct security_descriptor *sd = NULL;
255         struct dom_sid *sid = NULL;
256         NTSTATUS status;
257         uint32_t access_granted;
258         static const char *acl_attrs[] = {
259                 "nTSecurityDescriptor",
260                 "objectSid",
261                 NULL
262         };
263
264         ret = ldb_search(ldb, mem_ctx, &acl_res, dn, LDB_SCOPE_BASE, acl_attrs, NULL);
265         /* we sould be able to find the parent */
266         if (ret != LDB_SUCCESS) {
267                 DEBUG(10,("acl: failed to find object %s\n", ldb_dn_get_linearized(dn)));
268                 return ret;
269         }
270
271         ret = get_sd_from_ldb_message(mem_ctx, acl_res->msgs[0], &sd);
272         if (ret != LDB_SUCCESS) {
273                 return LDB_ERR_OPERATIONS_ERROR;
274         }
275         /* Theoretically we pass the check if the object has no sd */
276         if (!sd) {
277                 return LDB_SUCCESS;
278         }
279         ret = get_dom_sid_from_ldb_message(mem_ctx, acl_res->msgs[0], &sid);
280         if (ret != LDB_SUCCESS) {
281                 return LDB_ERR_OPERATIONS_ERROR;
282         }
283
284         status = sec_access_check_ds(sd, acl_user_token(module),
285                                      access,
286                                      &access_granted,
287                                      tree,
288                                      sid);
289         if (!NT_STATUS_IS_OK(status)) {
290                 acl_debug(sd,
291                           acl_user_token(module),
292                           dn,
293                           true,
294                           10);
295                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
296         }
297         return LDB_SUCCESS;
298 }
299
300 static int acl_check_access_on_attribute(struct ldb_module *module,
301                                          TALLOC_CTX *mem_ctx,
302                                          struct security_descriptor *sd,
303                                          struct dom_sid *rp_sid,
304                                          uint32_t access,
305                                          const struct dsdb_attribute *attr)
306 {
307         int ret;
308         NTSTATUS status;
309         uint32_t access_granted;
310         struct object_tree *root = NULL;
311         struct object_tree *new_node = NULL;
312         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
313         struct security_token *token = acl_user_token(module);
314         if (attr) {
315                 if (!GUID_all_zero(&attr->attributeSecurityGUID)) {
316                         if (!insert_in_object_tree(tmp_ctx,
317                                                    &attr->attributeSecurityGUID, access,
318                                                    &root, &new_node)) {
319                                 DEBUG(10, ("acl_search: cannot add to object tree securityGUID\n"));
320                                 goto fail;
321                         }
322
323                         if (!insert_in_object_tree(tmp_ctx,
324                                                    &attr->schemaIDGUID, access, &new_node, &new_node)) {
325                                 DEBUG(10, ("acl_search: cannot add to object tree attributeGUID\n"));
326                                 goto fail;
327                         }
328                 }
329                 else {
330                         if (!insert_in_object_tree(tmp_ctx,
331                                                    &attr->schemaIDGUID, access, &root, &new_node)) {
332                                 DEBUG(10, ("acl_search: cannot add to object tree attributeGUID\n"));
333                                 goto fail;
334                         }
335                 }
336         }
337         status = sec_access_check_ds(sd, token,
338                                      access,
339                                      &access_granted,
340                                      root,
341                                      rp_sid);
342         if (!NT_STATUS_IS_OK(status)) {
343                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
344         }
345         else {
346                 ret = LDB_SUCCESS;
347         }
348         return ret;
349 fail:
350         return LDB_ERR_OPERATIONS_ERROR;
351 }
352
353 static int acl_check_access_on_class(struct ldb_module *module,
354                                      TALLOC_CTX *mem_ctx,
355                                      struct security_descriptor *sd,
356                                      struct dom_sid *rp_sid,
357                                      uint32_t access,
358                                      const char *class_name)
359 {
360         int ret;
361         struct ldb_context *ldb = ldb_module_get_ctx(module);
362         NTSTATUS status;
363         uint32_t access_granted;
364         struct object_tree *root = NULL;
365         struct object_tree *new_node = NULL;
366         const struct GUID *guid;
367         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
368         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
369         struct security_token *token = acl_user_token(module);
370         if (class_name) {
371                 guid = class_schemaid_guid_by_lDAPDisplayName(schema, class_name);
372                 if (!guid) {
373                         DEBUG(10, ("acl_search: cannot find class %s\n",
374                                    class_name));
375                         goto fail;
376                 }
377                 if (!insert_in_object_tree(tmp_ctx,
378                                            guid, access,
379                                            &root, &new_node)) {
380                         DEBUG(10, ("acl_search: cannot add to object tree guid\n"));
381                         goto fail;
382                 }
383         }
384         status = sec_access_check_ds(sd, token,
385                                      access,
386                                      &access_granted,
387                                      root,
388                                      rp_sid);
389         if (!NT_STATUS_IS_OK(status)) {
390                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
391         }
392         else {
393                 ret = LDB_SUCCESS;
394         }
395         return ret;
396 fail:
397         return LDB_ERR_OPERATIONS_ERROR;
398 }
399
400 static int acl_allowedAttributes(struct ldb_module *module,
401                                  struct ldb_message *sd_msg,
402                                  struct ldb_message *msg,
403                                  struct acl_context *ac)
404 {
405         struct ldb_message_element *oc_el;
406         struct ldb_context *ldb = ldb_module_get_ctx(module);
407         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
408         TALLOC_CTX *mem_ctx;
409         const char **attr_list;
410         int i, ret;
411
412         /* If we don't have a schema yet, we can't do anything... */
413         if (schema == NULL) {
414                 return LDB_SUCCESS;
415         }
416
417         /* Must remove any existing attribute */
418         if (ac->allowedAttributes) {
419                 ldb_msg_remove_attr(msg, "allowedAttributes");
420         }
421
422         mem_ctx = talloc_new(msg);
423         if (!mem_ctx) {
424                 ldb_oom(ldb);
425                 return LDB_ERR_OPERATIONS_ERROR;
426         }
427
428         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
429         attr_list = dsdb_full_attribute_list(mem_ctx, schema, oc_el, DSDB_SCHEMA_ALL);
430         if (!attr_list) {
431                 ldb_asprintf_errstring(ldb, "acl: Failed to get list of attributes");
432                 talloc_free(mem_ctx);
433                 return LDB_ERR_OPERATIONS_ERROR;
434         }
435         if (ac->allowedAttributes) {
436                 for (i=0; attr_list && attr_list[i]; i++) {
437                         ldb_msg_add_string(msg, "allowedAttributes", attr_list[i]);
438                 }
439         }
440         if (ac->allowedAttributesEffective) {
441                 struct security_descriptor *sd;
442                 struct dom_sid *sid = NULL;
443                 struct ldb_control *as_system = ldb_request_get_control(ac->req,
444                                                                         LDB_CONTROL_AS_SYSTEM_OID);
445
446                 if (as_system != NULL) {
447                         as_system->critical = 0;
448                 }
449
450                 ldb_msg_remove_attr(msg, "allowedAttributesEffective");
451                 if (ac->am_system || as_system) {
452                         for (i=0; attr_list && attr_list[i]; i++) {
453                                 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
454                         }
455                         return LDB_SUCCESS;
456                 }
457
458                 ret = get_sd_from_ldb_message(mem_ctx, sd_msg, &sd);
459
460                 if (ret != LDB_SUCCESS) {
461                         return ret;
462                 }
463                 ret = get_dom_sid_from_ldb_message(mem_ctx, sd_msg, &sid);
464
465                 if (ret != LDB_SUCCESS) {
466                         return ret;
467                 }
468                 for (i=0; attr_list && attr_list[i]; i++) {
469                         const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
470                                                                                         attr_list[i]);
471                         if (!attr) {
472                                 return LDB_ERR_OPERATIONS_ERROR;
473                         }
474                         /* remove constructed attributes */
475                         if (attr->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED
476                             || attr->systemOnly
477                             || (attr->linkID != 0 && attr->linkID % 2 != 0 )) {
478                                 continue;
479                         }
480                         ret = acl_check_access_on_attribute(module,
481                                                             msg,
482                                                             sd,
483                                                             sid,
484                                                             SEC_ADS_WRITE_PROP,
485                                                             attr);
486                         if (ret == LDB_SUCCESS) {
487                                 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
488                         }
489                 }
490         }
491         return LDB_SUCCESS;
492 }
493
494 static int acl_childClasses(struct ldb_module *module,
495                             struct ldb_message *sd_msg,
496                             struct ldb_message *msg,
497                             const char *attrName)
498 {
499         struct ldb_message_element *oc_el;
500         struct ldb_message_element *allowedClasses;
501         struct ldb_context *ldb = ldb_module_get_ctx(module);
502         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
503         const struct dsdb_class *sclass;
504         int i, j, ret;
505
506         /* If we don't have a schema yet, we can't do anything... */
507         if (schema == NULL) {
508                 return LDB_SUCCESS;
509         }
510
511         /* Must remove any existing attribute, or else confusion reins */
512         ldb_msg_remove_attr(msg, attrName);
513         ret = ldb_msg_add_empty(msg, attrName, 0, &allowedClasses);
514         if (ret != LDB_SUCCESS) {
515                 return ret;
516         }
517
518         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
519
520         for (i=0; oc_el && i < oc_el->num_values; i++) {
521                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
522                 if (!sclass) {
523                         /* We don't know this class?  what is going on? */
524                         continue;
525                 }
526
527                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
528                         ldb_msg_add_string(msg, attrName, sclass->possibleInferiors[j]);
529                 }
530         }
531         if (allowedClasses->num_values > 1) {
532                 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
533                 for (i=1 ; i < allowedClasses->num_values; i++) {
534                         struct ldb_val *val1 = &allowedClasses->values[i-1];
535                         struct ldb_val *val2 = &allowedClasses->values[i];
536                         if (data_blob_cmp(val1, val2) == 0) {
537                                 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof(struct ldb_val));
538                                 allowedClasses->num_values--;
539                                 i--;
540                         }
541                 }
542         }
543
544         return LDB_SUCCESS;
545 }
546
547 static int acl_childClassesEffective(struct ldb_module *module,
548                                      struct ldb_message *sd_msg,
549                                      struct ldb_message *msg,
550                                      struct acl_context *ac)
551 {
552         struct ldb_message_element *oc_el;
553         struct ldb_message_element *allowedClasses = NULL;
554         struct ldb_context *ldb = ldb_module_get_ctx(module);
555         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
556         const struct dsdb_class *sclass;
557         struct security_descriptor *sd;
558         struct ldb_control *as_system = ldb_request_get_control(ac->req,
559                                                                 LDB_CONTROL_AS_SYSTEM_OID);
560         struct dom_sid *sid = NULL;
561         int i, j, ret;
562
563         if (as_system != NULL) {
564                 as_system->critical = 0;
565         }
566
567         if (ac->am_system || as_system) {
568                 return acl_childClasses(module, sd_msg, msg, "allowedChildClassesEffective");
569         }
570
571         /* If we don't have a schema yet, we can't do anything... */
572         if (schema == NULL) {
573                 return LDB_SUCCESS;
574         }
575
576         /* Must remove any existing attribute, or else confusion reins */
577         ldb_msg_remove_attr(msg, "allowedChildClassesEffective");
578
579         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
580         ret = get_sd_from_ldb_message(msg, sd_msg, &sd);
581         if (ret != LDB_SUCCESS) {
582                 return ret;
583         }
584         ret = get_dom_sid_from_ldb_message(msg, sd_msg, &sid);
585
586         if (ret != LDB_SUCCESS) {
587                 return ret;
588         }
589         for (i=0; oc_el && i < oc_el->num_values; i++) {
590                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
591                 if (!sclass) {
592                         /* We don't know this class?  what is going on? */
593                         continue;
594                 }
595
596                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
597                         ret = acl_check_access_on_class(module,
598                                                         msg,
599                                                         sd,
600                                                         sid,
601                                                         SEC_ADS_CREATE_CHILD,
602                                                         sclass->possibleInferiors[j]);
603                         if (ret == LDB_SUCCESS) {
604                                 ldb_msg_add_string(msg, "allowedChildClassesEffective",
605                                                    sclass->possibleInferiors[j]);
606                         }
607                 }
608         }
609         allowedClasses = ldb_msg_find_element(msg, "allowedChildClassesEffective");
610         if (!allowedClasses) {
611                 return LDB_SUCCESS;
612         }
613
614         if (allowedClasses->num_values > 1) {
615                 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
616                 for (i=1 ; i < allowedClasses->num_values; i++) {
617                         struct ldb_val *val1 = &allowedClasses->values[i-1];
618                         struct ldb_val *val2 = &allowedClasses->values[i];
619                         if (data_blob_cmp(val1, val2) == 0) {
620                                 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof( struct ldb_val));
621                                 allowedClasses->num_values--;
622                                 i--;
623                         }
624                 }
625         }
626         return LDB_SUCCESS;
627 }
628
629 static int acl_sDRightsEffective(struct ldb_module *module,
630                                  struct ldb_message *sd_msg,
631                                  struct ldb_message *msg,
632                                  struct acl_context *ac)
633 {
634         struct ldb_message_element *rightsEffective;
635         int ret;
636         struct security_descriptor *sd;
637         struct ldb_control *as_system = ldb_request_get_control(ac->req,
638                                                                 LDB_CONTROL_AS_SYSTEM_OID);
639         struct dom_sid *sid = NULL;
640         uint32_t flags = 0;
641
642         if (as_system != NULL) {
643                 as_system->critical = 0;
644         }
645
646         /* Must remove any existing attribute, or else confusion reins */
647         ldb_msg_remove_attr(msg, "sDRightsEffective");
648         ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
649         if (ret != LDB_SUCCESS) {
650                 return ret;
651         }
652         if (ac->am_system || as_system) {
653                 flags = SECINFO_OWNER | SECINFO_GROUP |  SECINFO_SACL |  SECINFO_DACL;
654         }
655         else {
656                 /* Get the security descriptor from the message */
657                 ret = get_sd_from_ldb_message(msg, sd_msg, &sd);
658                 if (ret != LDB_SUCCESS) {
659                         return ret;
660                 }
661                 ret = get_dom_sid_from_ldb_message(msg, sd_msg, &sid);
662
663                 if (ret != LDB_SUCCESS) {
664                         return ret;
665                 }
666                 ret = acl_check_access_on_attribute(module,
667                                                     msg,
668                                                     sd,
669                                                     sid,
670                                                     SEC_STD_WRITE_OWNER,
671                                                     NULL);
672                 if (ret == LDB_SUCCESS) {
673                         flags |= SECINFO_OWNER | SECINFO_GROUP;
674                 }
675                 ret = acl_check_access_on_attribute(module,
676                                                     msg,
677                                                     sd,
678                                                     sid,
679                                                     SEC_STD_WRITE_DAC,
680                                                     NULL);
681                 if (ret == LDB_SUCCESS) {
682                         flags |= SECINFO_DACL;
683                 }
684                 ret = acl_check_access_on_attribute(module,
685                                                     msg,
686                                                     sd,
687                                                     sid,
688                                                     SEC_FLAG_SYSTEM_SECURITY,
689                                                     NULL);
690                 if (ret == LDB_SUCCESS) {
691                         flags |= SECINFO_SACL;
692                 }
693         }
694         ldb_msg_add_fmt(msg, "sDRightsEffective", "%u", flags);
695         return LDB_SUCCESS;
696 }
697
698 static int acl_add(struct ldb_module *module, struct ldb_request *req)
699 {
700         int ret;
701         struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.add.message->dn);
702         struct ldb_context *ldb;
703         struct ldb_message_element *oc_el;
704         const struct GUID *guid;
705         struct object_tree *root = NULL;
706         struct object_tree *new_node = NULL;
707         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
708
709         if (as_system != NULL) {
710                 as_system->critical = 0;
711         }
712
713         if (dsdb_module_am_system(module) || as_system) {
714                 return ldb_next_request(module, req);
715         }
716
717         if (ldb_dn_is_special(req->op.add.message->dn)) {
718                 return ldb_next_request(module, req);
719         }
720         ldb = ldb_module_get_ctx(module);
721         /* Creating an NC. There is probably something we should do here,
722          * but we will establish that later */
723         if ((ldb_dn_compare(req->op.add.message->dn, (ldb_get_schema_basedn(ldb))) == 0) ||
724             (ldb_dn_compare(req->op.add.message->dn, (ldb_get_config_basedn(ldb))) == 0) ||
725             (ldb_dn_compare(req->op.add.message->dn, (ldb_get_root_basedn(ldb))) == 0)) {
726                 return ldb_next_request(module, req);
727         }
728
729         oc_el = ldb_msg_find_element(req->op.add.message, "objectClass");
730         if (!oc_el || oc_el->num_values == 0) {
731                 DEBUG(10,("acl:operation error %s\n", ldb_dn_get_linearized(req->op.add.message->dn)));
732                 return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
733         }
734
735         guid = class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb),
736                                                       (char *)oc_el->values[oc_el->num_values-1].data);
737
738         if (!insert_in_object_tree(req, guid, SEC_ADS_CREATE_CHILD, &root, &new_node)) {
739                 return LDB_ERR_OPERATIONS_ERROR;
740         }
741
742         ret = check_access_on_dn(module, req, parent, SEC_ADS_CREATE_CHILD, root);
743         if (ret != LDB_SUCCESS) {
744                 return ret;
745         }
746
747         return ldb_next_request(module, req);
748 }
749
750 static int acl_modify(struct ldb_module *module, struct ldb_request *req)
751 {
752         int ret;
753         struct ldb_context *ldb = ldb_module_get_ctx(module);
754         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
755         unsigned int i;
756         bool modify_sd = false;
757         const struct GUID *guid;
758         uint32_t access_granted;
759         struct object_tree *root = NULL;
760         struct object_tree *new_node = NULL;
761         NTSTATUS status;
762         struct ldb_result *acl_res;
763         struct security_descriptor *sd;
764         struct dom_sid *sid = NULL;
765         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
766         TALLOC_CTX *tmp_ctx = talloc_new(req);
767         static const char *acl_attrs[] = {
768                 "nTSecurityDescriptor",
769                 "objectClass",
770                 "objectSid",
771                 NULL
772         };
773
774         if (as_system != NULL) {
775                 as_system->critical = 0;
776         }
777
778         /* Don't print this debug statement if elements[0].name is going to be NULL */
779         if(req->op.mod.message->num_elements > 0)
780         {
781                 DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name));
782         }
783         if (dsdb_module_am_system(module) || as_system) {
784                 return ldb_next_request(module, req);
785         }
786         if (ldb_dn_is_special(req->op.mod.message->dn)) {
787                 return ldb_next_request(module, req);
788         }
789         ret = ldb_search(ldb, req, &acl_res, req->op.mod.message->dn,
790                          LDB_SCOPE_BASE, acl_attrs, NULL);
791
792         if (ret != LDB_SUCCESS) {
793                 return ret;
794         }
795
796         ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd);
797         if (ret != LDB_SUCCESS) {
798                 DEBUG(10, ("acl_modify: cannot get descriptor\n"));
799                 return ret;
800         }
801         /* Theoretically we pass the check if the object has no sd */
802         if (!sd) {
803                 return LDB_SUCCESS;
804         }
805
806         guid = get_oc_guid_from_message(module,acl_res->msgs[0]);
807         if (!guid) {
808                 DEBUG(10, ("acl_modify: cannot get guid\n"));
809                 goto fail;
810         }
811
812         ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid);
813         if (ret != LDB_SUCCESS) {
814                 return LDB_ERR_OPERATIONS_ERROR;
815         }
816
817         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
818                                    &root, &new_node)) {
819                 DEBUG(10, ("acl_modify: cannot add to object tree\n"));
820                 goto fail;
821         }
822         for (i=0; i < req->op.mod.message->num_elements; i++){
823                 const struct dsdb_attribute *attr;
824                 /* clearTextPassword is not in schema */
825                 if (strcmp("clearTextPassword", req->op.mod.message->elements[i].name) == 0) {
826                         attr = dsdb_attribute_by_lDAPDisplayName(schema, "unicodePwd");
827                 } else {
828                         attr = dsdb_attribute_by_lDAPDisplayName(schema,
829                                                                  req->op.mod.message->elements[i].name);
830                 }
831                 if (strcmp("nTSecurityDescriptor", req->op.mod.message->elements[i].name) == 0) {
832                         modify_sd = true;
833                 } else {
834
835                         if (!attr) {
836                                 DEBUG(10, ("acl_modify: cannot find attribute %s\n",
837                                            req->op.mod.message->elements[i].name));
838                                 goto fail;
839                         }
840                         if (!insert_in_object_tree(tmp_ctx,
841                                                    &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP,
842                                                    &new_node, &new_node)) {
843                                 DEBUG(10, ("acl_modify: cannot add to object tree securityGUID\n"));
844                                 goto fail;
845                         }
846
847                         if (!insert_in_object_tree(tmp_ctx,
848                                                    &attr->schemaIDGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) {
849                                 DEBUG(10, ("acl_modify: cannot add to object tree attributeGUID\n"));
850                                 goto fail;
851                         }
852                 }
853         }
854
855         if (root->num_of_children > 0) {
856                 status = sec_access_check_ds(sd, acl_user_token(module),
857                                              SEC_ADS_WRITE_PROP,
858                                              &access_granted,
859                                              root,
860                                              sid);
861
862                 if (!NT_STATUS_IS_OK(status)) {
863                         DEBUG(10, ("Object %s nas no write property access\n",
864                                    ldb_dn_get_linearized(req->op.mod.message->dn)));
865                         acl_debug(sd,
866                                   acl_user_token(module),
867                                   req->op.mod.message->dn,
868                                   true,
869                                   10);
870                         talloc_free(tmp_ctx);
871                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
872                 }
873         }
874         if (modify_sd) {
875                 status = sec_access_check_ds(sd, acl_user_token(module),
876                                              SEC_STD_WRITE_DAC,
877                                              &access_granted,
878                                              NULL,
879                                              sid);
880
881                 if (!NT_STATUS_IS_OK(status)) {
882                         DEBUG(10, ("Object %s nas no write dacl access\n",
883                                    ldb_dn_get_linearized(req->op.mod.message->dn)));
884                         acl_debug(sd,
885                                   acl_user_token(module),
886                                   req->op.mod.message->dn,
887                                   true,
888                                   10);
889                         talloc_free(tmp_ctx);
890                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
891                 }
892         }
893
894         talloc_free(tmp_ctx);
895         return ldb_next_request(module, req);
896 fail:
897         talloc_free(tmp_ctx);
898         return LDB_ERR_OPERATIONS_ERROR;
899 }
900
901 /* similar to the modify for the time being.
902  * We need to concider the special delete tree case, though - TODO */
903 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
904 {
905         int ret;
906         struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.del.dn);
907         struct ldb_context *ldb;
908         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
909
910         if (as_system != NULL) {
911                 as_system->critical = 0;
912         }
913
914         DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
915         if (dsdb_module_am_system(module) || as_system) {
916                 return ldb_next_request(module, req);
917         }
918
919         if (ldb_dn_is_special(req->op.del.dn)) {
920                 return ldb_next_request(module, req);
921         }
922         ldb = ldb_module_get_ctx(module);
923         /* first check if we have delete object right */
924         ret = check_access_on_dn(module, req, req->op.del.dn, SEC_STD_DELETE, NULL);
925         if (ret == LDB_SUCCESS) {
926                 return ldb_next_request(module, req);
927         }
928
929         /* Nope, we don't have delete object. Lets check if we have delete child on the parent */
930         /* No parent, so check fails */
931         if ((ldb_dn_compare(req->op.del.dn, (ldb_get_schema_basedn(ldb))) == 0) ||
932             (ldb_dn_compare(req->op.del.dn, (ldb_get_config_basedn(ldb))) == 0) ||
933             (ldb_dn_compare(req->op.del.dn, (ldb_get_root_basedn(ldb))) == 0)) {
934                 DEBUG(10,("acl:deleting an NC\n"));
935                 return ldb_module_done(req, NULL, NULL, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS);
936         }
937
938         ret = check_access_on_dn(module, req, parent, SEC_ADS_DELETE_CHILD, NULL);
939         if (ret != LDB_SUCCESS) {
940                 return ret;
941         }
942         return ldb_next_request(module, req);
943 }
944
945 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
946 {
947         int ret;
948         struct ldb_dn *oldparent = ldb_dn_get_parent(req, req->op.rename.olddn);
949         struct ldb_dn *newparent = ldb_dn_get_parent(req, req->op.rename.newdn);
950         struct ldb_context *ldb;
951         struct security_descriptor *sd = NULL;
952         struct dom_sid *sid = NULL;
953         struct ldb_result *acl_res;
954         const struct GUID *guid;
955         struct object_tree *root = NULL;
956         struct object_tree *new_node = NULL;
957         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
958         TALLOC_CTX *tmp_ctx = talloc_new(req);
959         NTSTATUS status;
960         uint32_t access_granted;
961         const char *rdn_name;
962         static const char *acl_attrs[] = {
963                 "nTSecurityDescriptor",
964                 "objectClass",
965                 "objectSid",
966                 NULL
967         };
968
969         if (as_system != NULL) {
970                 as_system->critical = 0;
971         }
972
973         DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
974         if (dsdb_module_am_system(module) || as_system) {
975                 return ldb_next_request(module, req);
976         }
977         if (ldb_dn_is_special(req->op.rename.olddn)) {
978                 return ldb_next_request(module, req);
979         }
980         ldb = ldb_module_get_ctx(module);
981
982         /* TODO search to include deleted objects */
983         ret = ldb_search(ldb, req, &acl_res, req->op.rename.olddn,
984                          LDB_SCOPE_BASE, acl_attrs, NULL);
985         /* we sould be able to find the parent */
986         if (ret != LDB_SUCCESS) {
987                 DEBUG(10,("acl: failed to find object %s\n",
988                           ldb_dn_get_linearized(req->op.rename.olddn)));
989                 return ret;
990         }
991
992         guid = get_oc_guid_from_message(module,acl_res->msgs[0]);
993         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
994                                    &root, &new_node)) {
995                 return LDB_ERR_OPERATIONS_ERROR;
996         };
997
998         guid = attribute_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb),
999                                                           "name");
1000         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1001                                    &new_node, &new_node)) {
1002                 return LDB_ERR_OPERATIONS_ERROR;
1003         };
1004
1005         rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
1006         if (rdn_name == NULL) {
1007                 return LDB_ERR_OPERATIONS_ERROR;
1008         }
1009         guid = attribute_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb),
1010                                                           rdn_name);
1011         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1012                                    &new_node, &new_node)) {
1013                 return LDB_ERR_OPERATIONS_ERROR;
1014         };
1015
1016         ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd);
1017
1018         if (ret != LDB_SUCCESS) {
1019                 return LDB_ERR_OPERATIONS_ERROR;
1020         }
1021         /* Theoretically we pass the check if the object has no sd */
1022         if (!sd) {
1023                 return LDB_SUCCESS;
1024         }
1025         ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid);
1026         if (ret != LDB_SUCCESS) {
1027                 return LDB_ERR_OPERATIONS_ERROR;
1028         }
1029
1030         status = sec_access_check_ds(sd, acl_user_token(module),
1031                                      SEC_ADS_WRITE_PROP,
1032                                      &access_granted,
1033                                      root,
1034                                      sid);
1035
1036         if (!NT_STATUS_IS_OK(status)) {
1037                 DEBUG(10, ("Object %s nas no wp on name\n",
1038                            ldb_dn_get_linearized(req->op.rename.olddn)));
1039                 acl_debug(sd,
1040                           acl_user_token(module),
1041                           req->op.rename.olddn,
1042                           true,
1043                           10);
1044                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1045         }
1046
1047         if (ldb_dn_compare(oldparent, newparent) == 0) {
1048                 /* regular rename, not move, nothing more to do */
1049                 return ldb_next_request(module, req);
1050         }
1051
1052         /* What exactly to do in this case? It would fail anyway.. */
1053         if ((ldb_dn_compare(req->op.rename.newdn, (ldb_get_schema_basedn(ldb))) == 0) ||
1054             (ldb_dn_compare(req->op.rename.newdn, (ldb_get_config_basedn(ldb))) == 0) ||
1055             (ldb_dn_compare(req->op.rename.newdn, (ldb_get_root_basedn(ldb))) == 0)) {
1056                 DEBUG(10,("acl:moving as an NC\n"));
1057                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1058         }
1059         /* new parent should have create child */
1060         talloc_free(tmp_ctx);
1061         tmp_ctx = talloc_new(req);
1062         root = NULL;
1063         new_node = NULL;
1064         guid = get_oc_guid_from_message(module,acl_res->msgs[0]);
1065         if (!guid) {
1066                 DEBUG(10,("acl:renamed object has no object class\n"));
1067                 return ldb_module_done(req, NULL, NULL,  LDB_ERR_OPERATIONS_ERROR);
1068         }
1069         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_CREATE_CHILD,
1070                                    &root, &new_node)) {
1071                 return LDB_ERR_OPERATIONS_ERROR;
1072         }
1073         ret = check_access_on_dn(module, req, newparent, SEC_ADS_CREATE_CHILD, root);
1074         if (ret != LDB_SUCCESS) {
1075                 DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn)));
1076                 return ret;
1077         }
1078         /* do we have delete object on the object? */
1079
1080         status = sec_access_check_ds(sd, acl_user_token(module),
1081                                      SEC_STD_DELETE,
1082                                      &access_granted,
1083                                      NULL,
1084                                      sid);
1085
1086         if (NT_STATUS_IS_OK(status)) {
1087                 return ldb_next_request(module, req);
1088         }
1089         /* what about delete child on the current parent */
1090         ret = check_access_on_dn(module, req, oldparent, SEC_ADS_DELETE_CHILD, NULL);
1091         if (ret != LDB_SUCCESS) {
1092                 DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn)));
1093                 return ldb_module_done(req, NULL, NULL, ret);
1094         }
1095         return ldb_next_request(module, req);
1096 }
1097
1098 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1099 {
1100         struct ldb_context *ldb;
1101         struct acl_context *ac;
1102         struct acl_private *data;
1103         struct ldb_result *acl_res;
1104         static const char *acl_attrs[] = {
1105                 "objectClass",
1106                 "nTSecurityDescriptor",
1107                 "objectSid",
1108                 NULL
1109         };
1110         int ret, i;
1111
1112         ac = talloc_get_type(req->context, struct acl_context);
1113         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
1114         ldb = ldb_module_get_ctx(ac->module);
1115
1116         if (!ares) {
1117                 return ldb_module_done(ac->req, NULL, NULL,
1118                                        LDB_ERR_OPERATIONS_ERROR);
1119         }
1120         if (ares->error != LDB_SUCCESS) {
1121                 return ldb_module_done(ac->req, ares->controls,
1122                                        ares->response, ares->error);
1123         }
1124
1125         switch (ares->type) {
1126         case LDB_REPLY_ENTRY:
1127                 if (ac->allowedAttributes 
1128                     || ac->allowedChildClasses
1129                     || ac->allowedChildClassesEffective
1130                     || ac->allowedAttributesEffective
1131                     || ac->sDRightsEffective) {
1132                         ret = ldb_search(ldb, ac, &acl_res, ares->message->dn, LDB_SCOPE_BASE, acl_attrs, NULL);
1133                         if (ret != LDB_SUCCESS) {
1134                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1135                         }
1136                         if (ac->allowedAttributes || ac->allowedAttributesEffective) {
1137                                 ret = acl_allowedAttributes(ac->module, acl_res->msgs[0], ares->message, ac);
1138                                 if (ret != LDB_SUCCESS) {
1139                                         return ldb_module_done(ac->req, NULL, NULL, ret);
1140                                 }
1141                         }
1142                         if (ac->allowedChildClasses) {
1143                                 ret = acl_childClasses(ac->module, acl_res->msgs[0],
1144                                                        ares->message, "allowedChildClasses");
1145                                 if (ret != LDB_SUCCESS) {
1146                                         return ldb_module_done(ac->req, NULL, NULL, ret);
1147                                 }
1148                         }
1149                         if (ac->allowedChildClassesEffective) {
1150                                 ret = acl_childClassesEffective(ac->module,
1151                                                                 acl_res->msgs[0], ares->message, ac);
1152                                 if (ret != LDB_SUCCESS) {
1153                                         return ldb_module_done(ac->req, NULL, NULL, ret);
1154                                 }
1155                         }
1156                         if (ac->sDRightsEffective) {
1157                                 ret = acl_sDRightsEffective(ac->module,
1158                                                             acl_res->msgs[0], ares->message, ac);
1159                                 if (ret != LDB_SUCCESS) {
1160                                         return ldb_module_done(ac->req, NULL, NULL, ret);
1161                                 }
1162                         }
1163                 }
1164                 if (data && data->password_attrs) {
1165                         if (!ac->am_system) {
1166                                 for (i = 0; data->password_attrs[i]; i++) {
1167                                         ldb_msg_remove_attr(ares->message, data->password_attrs[i]);
1168                                 }
1169                         }
1170                 }
1171                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
1172
1173         case LDB_REPLY_REFERRAL:
1174                 return ldb_module_send_referral(ac->req, ares->referral);
1175
1176         case LDB_REPLY_DONE:
1177                 return ldb_module_done(ac->req, ares->controls,
1178                                        ares->response, LDB_SUCCESS);
1179
1180         }
1181         return LDB_SUCCESS;
1182 }
1183
1184 static int acl_search(struct ldb_module *module, struct ldb_request *req)
1185 {
1186         struct ldb_context *ldb;
1187         struct acl_context *ac;
1188         struct ldb_request *down_req;
1189         struct acl_private *data;
1190         int ret, i;
1191
1192         ldb = ldb_module_get_ctx(module);
1193
1194         ac = talloc_zero(req, struct acl_context);
1195         if (ac == NULL) {
1196                 ldb_oom(ldb);
1197                 return LDB_ERR_OPERATIONS_ERROR;
1198         }
1199         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
1200
1201         ac->module = module;
1202         ac->req = req;
1203         ac->am_system = dsdb_module_am_system(module);
1204         ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
1205         ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
1206         ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
1207         ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
1208         ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
1209
1210         /* replace any attributes in the parse tree that are private,
1211            so we don't allow a search for 'userPassword=penguin',
1212            just as we would not allow that attribute to be returned */
1213         if (ac->am_system) {
1214                 /* FIXME: We should copy the tree and keep the original unmodified. */
1215                 /* remove password attributes */
1216                 if (data && data->password_attrs) {
1217                         for (i = 0; data->password_attrs[i]; i++) {
1218                                 ldb_parse_tree_attr_replace(req->op.search.tree,
1219                                                             data->password_attrs[i],
1220                                                             "kludgeACLredactedattribute");
1221                         }
1222                 }
1223         }
1224         ret = ldb_build_search_req_ex(&down_req,
1225                                       ldb, ac,
1226                                       req->op.search.base,
1227                                       req->op.search.scope,
1228                                       req->op.search.tree,
1229                                       req->op.search.attrs,
1230                                       req->controls,
1231                                       ac, acl_search_callback,
1232                                       req);
1233         if (ret != LDB_SUCCESS) {
1234                 return ret;
1235         }
1236         /* perform the search */
1237         return ldb_next_request(module, down_req);
1238 }
1239
1240 _PUBLIC_ const struct ldb_module_ops ldb_acl_module_ops = {
1241         .name              = "acl",
1242         .search            = acl_search,
1243         .add               = acl_add,
1244         .modify            = acl_modify,
1245         .del               = acl_delete,
1246         .rename            = acl_rename,
1247         .init_context      = acl_module_init
1248 };