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