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