1b02abcb8e21a74a84385841a116bf5a73d9908d
[ira/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 "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 /* acl_search helper */
44 struct acl_context {
45
46         struct ldb_module *module;
47         struct ldb_request *req;
48         struct ldb_request *down_req;
49
50         /*needed if we have to identify if this is SYSTEM_USER*/
51         enum security_user_level user_type;
52
53         uint32_t access_needed;
54         struct ldb_dn * dn_to_check;
55
56         /* set to true when we need to process the request as a SYSTEM_USER, regardless
57          * of the user's actual rights - for example when we need to retrieve the
58          * ntSecurityDescriptor */
59         bool ignore_security;
60         struct security_token *token;
61         /*needed to identify if we have requested these attributes*/
62         bool nTSecurityDescriptor;
63         bool objectClass;
64         int sec_result;
65 };
66
67 struct extended_access_check_attribute {
68         const char *oa_name;
69         const uint32_t requires_rights;
70 };
71
72 struct acl_private{
73         bool perform_check;
74 };
75
76 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares);
77
78 /*FIXME: Perhaps this should go in the .idl file*/
79 #define SEC_GENERIC_ACCESS_NEVER_GRANTED ( 0xFFFFFFFF )
80
81 /*Contains a part of the attributes - the ones that have predefined required rights*/
82 static const struct extended_access_check_attribute extended_access_checks_table[] =
83 {
84         {
85                 .oa_name = "nTSecurityDescriptor",
86                 .requires_rights = SEC_FLAG_SYSTEM_SECURITY & SEC_STD_READ_CONTROL,
87         },
88         {
89                 .oa_name = "pekList",
90                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
91         },
92         {
93                 .oa_name = "currentValue",
94                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
95         },
96         {
97                 .oa_name = "dBCSPwd",
98                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
99         },
100         {
101                 .oa_name = "unicodePwd",
102                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
103         },
104         {
105                 .oa_name = "ntPwdHistory",
106                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
107         },
108         {
109                 .oa_name = "priorValue",
110                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
111         },
112         {
113                 .oa_name = "supplementalCredentials",
114                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
115         },
116         {
117                 .oa_name = "trustAuthIncoming",
118                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
119         },
120         {
121                 .oa_name = "trustAuthOutgoing",
122                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
123         },
124         {
125                 .oa_name = "ImPwdHistory",
126                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
127         },
128         {
129                 .oa_name = "initialAuthIncoming",
130                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
131         },
132         {
133                 .oa_name = "initialAuthOutgoing",
134                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
135         },
136         {
137                 .oa_name = "msDS-ExecuteScriptPassword",
138                 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
139         },
140 };
141
142 static NTSTATUS extended_access_check(const char *attribute_name, const int access_rights, uint32_t searchFlags)
143 {
144         int i = 0;
145         if (access_rights == SEC_GENERIC_ACCESS_NEVER_GRANTED) {
146                 return NT_STATUS_ACCESS_DENIED;
147         }
148
149         /*Check if the attribute is in the table first*/
150         for ( i = 0; extended_access_checks_table[i].oa_name; i++ ) {
151                 if (ldb_attr_cmp(extended_access_checks_table[i].oa_name, attribute_name) == 0) {
152                         if ((access_rights & extended_access_checks_table[i].requires_rights) == access_rights) {
153                                 return NT_STATUS_OK;
154                         } else {
155                                 return NT_STATUS_ACCESS_DENIED;
156                         }
157                 }
158         }
159
160         /*Check for attribute whose attributeSchema has 0x80 set in searchFlags*/
161         if ((searchFlags & SEARCH_FLAG_CONFIDENTIAL) == SEARCH_FLAG_CONFIDENTIAL) {
162                 if (((SEC_ADS_READ_PROP & SEC_ADS_CONTROL_ACCESS) & access_rights) == access_rights) {
163                         return NT_STATUS_OK;
164                 } else {
165                         return NT_STATUS_ACCESS_DENIED;
166                 }
167         }
168
169         /*Check attributes with *special* behaviour*/
170         if (ldb_attr_cmp("msDS-QuotaEffective", attribute_name) == 0 || ldb_attr_cmp("msDS-QuotaUsed", attribute_name) == 0){
171                 /*Rights required:
172                  *
173                  *(RIGHT_DS_READ_PROPERTY on the Quotas container or
174                  *((the client is querying the quota for the security principal it is authenticated as) and
175                  *(DS-Query-Self-Quota control access right on the Quotas container))
176                  */
177         }
178
179         if (ldb_attr_cmp("userPassword", attribute_name) == 0) {
180                 /*When the dSHeuristics.fUserPwdSupport flag is false, the requester must be granted RIGHT_DS_READ_PROPERTY.
181                  *When the dSHeuristics.fUserPwdSupport flag is true, access is never granted.
182                  */
183         }
184
185         if (ldb_attr_cmp("sDRightsEffective", attribute_name) == 0) {
186                 /*FIXME:3.1.1.4.5.4 in MS-ADTS*/
187         }
188
189         if (ldb_attr_cmp("allowedChildClassesEffective", attribute_name) == 0) {
190                 /*FIXME:3.1.1.4.5.5 in MS-ADTS*/
191         }
192
193         if (ldb_attr_cmp("allowedAttributesEffective", attribute_name) == 0) {
194                 /*FIXME:3.1.1.4.5.7 in MS-ADTS*/
195         }
196
197         if (ldb_attr_cmp("msDS-Approx-Immed-Subordinates", attribute_name) == 0) {
198                 /*FIXME:3.1.1.4.5.15 in MS-ADTS*/
199         }
200
201         if (ldb_attr_cmp("msDS-QuotaEffective", attribute_name) == 0) {
202                 /*FIXME:3.1.1.4.5.22 in MS-ADTS*/
203         }
204
205         if (ldb_attr_cmp("msDS-ReplAttributeMetaData", attribute_name) == 0 || ldb_attr_cmp("msDS-ReplAttributeMetaData", attribute_name) == 0) {
206                 /*The security context of the requester must be granted the following rights on the replPropertyMetaData attribute:
207                  *(RIGHT_DS_READ_PROPERTY)or (DS-Replication-Manage-Topology by ON!nTSecurityDescriptor)
208                  */
209         }
210
211         if (ldb_attr_cmp("msDS-NCReplInboundNeighbors", attribute_name) == 0) {
212                 /*The security context of the requester must be granted the following rights on repsFrom:
213                  *(RIGHT_DS_READ_PROPERTY) or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
214                  */
215         }
216
217         if (ldb_attr_cmp("msDS-NCReplOutboundNeighbors", attribute_name) == 0) {
218                 /*The security context of the requester must be granted the following rights on repsTo:
219                  *(RIGHT_DS_READ_PROPERTY) or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
220                  */
221         }
222
223         if (ldb_attr_cmp("msDS-NCReplCursors", attribute_name) == 0) {
224                 /*The security context of the requester must be granted the following rights on replUpToDateVector: (RIGHT_DS_READ_PROPERTY)
225                  *or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
226                  */
227         }
228
229         if (ldb_attr_cmp("msDS-IsUserCachableAtRodc", attribute_name) == 0) {
230                 /*The security context of the requester must be granted
231                  *the DS-Replication-Secrets-Synchronize control access right on the root of the default NC.
232                  */
233         }
234
235         return NT_STATUS_OK;
236 }
237
238 /* Builds an object tree for object specific access checks */
239 static struct object_tree * build_object_tree_form_attr_list(TALLOC_CTX *mem_ctx,   /* Todo this context or separate? */
240                                                              struct ldb_context *ldb,
241                                                              const char ** attr_names,
242                                                              int num_attrs,
243                                                              const char * object_class,
244                                                              uint32_t init_access)
245 {
246         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
247         const struct GUID *oc_guid = class_schemaid_guid_by_lDAPDisplayName(schema, object_class);
248         struct object_tree *tree;
249         int i;
250
251         if (!oc_guid)
252                 return NULL;
253
254         tree = insert_in_object_tree(mem_ctx, oc_guid, NULL, init_access, NULL);
255         if (attr_names){
256                 for (i=0; i < num_attrs; i++){
257                         const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema,attr_names[i]);
258                         if (attribute)
259                                 insert_in_object_tree(mem_ctx,
260                                                       &attribute->schemaIDGUID,
261                                                       &attribute->attributeSecurityGUID,
262                                                       init_access,
263                                                       tree);
264                 }
265         }
266         return tree;
267 }
268
269 bool is_root_base_dn(struct ldb_context *ldb, struct ldb_dn *dn_to_check)
270 {
271         int result;
272         struct ldb_dn *root_base_dn = ldb_get_root_basedn(ldb);
273         result = ldb_dn_compare(root_base_dn,dn_to_check);
274         return (result==0);
275 }
276
277 static int acl_op_callback(struct ldb_request *req, struct ldb_reply *ares)
278 {
279         struct acl_context *ac;
280
281         ac = talloc_get_type(req->context, struct acl_context);
282
283         if (!ares) {
284                 return ldb_module_done(ac->req, NULL, NULL,
285                                         LDB_ERR_OPERATIONS_ERROR);
286         }
287         if (ares->error != LDB_SUCCESS) {
288                 return ldb_module_done(ac->req, ares->controls,
289                                         ares->response, ares->error);
290         }
291
292         if (ares->type != LDB_REPLY_DONE) {
293                 talloc_free(ares);
294                 return ldb_module_done(ac->req, NULL, NULL,
295                                         LDB_ERR_OPERATIONS_ERROR);
296         }
297
298         return ldb_module_done(ac->req, ares->controls,
299                                 ares->response, ares->error);
300 }
301
302
303 static int acl_access_check_add(struct ldb_reply *ares,
304                                 struct acl_context *ac,
305                                 struct security_descriptor *sd)
306 {
307         uint32_t access_granted = 0;
308         NTSTATUS status;
309         struct ldb_dn *parent;
310         struct ldb_dn *grandparent;
311         struct object_tree *tree = NULL;
312
313         parent = ldb_dn_get_parent(ac->req, ac->req->op.add.message->dn);
314         grandparent = ldb_dn_get_parent(ac->req, parent);
315         if (ldb_dn_compare(ares->message->dn, grandparent) == 0)
316                 status = sec_access_check_ds(sd, ac->token,
317                                              SEC_ADS_LIST,
318                                              &access_granted,
319                                              NULL);
320         else if (ldb_dn_compare(ares->message->dn, parent) == 0){
321                 struct ldb_message_element *oc_el;
322                 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
323                 const struct dsdb_schema *schema = dsdb_get_schema(ldb);
324                 int i;
325
326                 oc_el = ldb_msg_find_element(ares->message, "objectClass");
327                 if (!oc_el || oc_el->num_values == 0)
328                         return LDB_SUCCESS;
329                 for (i = 0; i < oc_el->num_values; i++){
330                         const struct GUID *guid = class_schemaid_guid_by_lDAPDisplayName(schema,
331                                                                                           oc_el->values[i].data);
332                         ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
333                         tree = insert_in_object_tree(ac->req, guid, NULL, SEC_ADS_CREATE_CHILD,
334                                                      tree);
335                         status = sec_access_check_ds(sd, ac->token, SEC_ADS_CREATE_CHILD,&access_granted, tree);
336                         if (NT_STATUS_IS_OK(status))
337                                 ac->sec_result = LDB_SUCCESS;
338                 }
339         }
340         else
341                 return LDB_SUCCESS;
342
343         return ac->sec_result;
344 }
345
346 static int acl_access_check_modify(struct ldb_reply *ares, struct acl_context *ac,
347                                    struct security_descriptor *sd)
348 {
349         uint32_t access_granted = 0;
350         NTSTATUS status;
351         struct ldb_dn *parent;
352         struct object_tree *tree = NULL;
353
354         parent = ldb_dn_get_parent(ac->req, ac->req->op.add.message->dn);
355         if (ldb_dn_compare(ares->message->dn, parent) == 0)
356                 status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
357         else if (ldb_dn_compare(ares->message->dn, ac->req->op.add.message->dn) == 0){
358                 struct ldb_message_element *oc_el;
359                 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
360                 const struct dsdb_schema *schema = dsdb_get_schema(ldb);
361                 int i;
362                 struct GUID *guid;
363                 oc_el = ldb_msg_find_element(ares->message, "objectClass");
364                 if (!oc_el || oc_el->num_values == 0)
365                         return LDB_SUCCESS;
366
367                 guid = class_schemaid_guid_by_lDAPDisplayName(schema,
368                                                               oc_el->values[oc_el->num_values-1].data);
369                 tree = insert_in_object_tree(ac->req, guid, NULL, SEC_ADS_WRITE_PROP,
370                                                      tree);
371                 for (i=0; i < ac->req->op.mod.message->num_elements; i++){
372                         const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
373                                                                                               ac->req->op.mod.message->elements[i].name);
374                         if (!attr)
375                                 return LDB_ERR_OPERATIONS_ERROR; /* What should we actually return here? */
376                         insert_in_object_tree(ac, &attr->schemaIDGUID,
377                                               &attr->attributeSecurityGUID, ac->access_needed, tree);
378                 }
379                 status = sec_access_check_ds(sd, ac->token, SEC_ADS_WRITE_PROP ,&access_granted, tree);
380                 if (!NT_STATUS_IS_OK(status))
381                         ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
382         }
383         else
384                 return LDB_SUCCESS;
385         return ac->sec_result;
386 }
387 /*TODO*/
388 static int acl_access_check_rename(struct ldb_reply *ares, struct acl_context *ac,
389                                    struct security_descriptor *sd)
390 {
391         return ac->sec_result;
392 }
393
394 static int acl_access_check_delete(struct ldb_reply *ares, struct acl_context *ac,
395                                    struct security_descriptor *sd)
396 {
397         uint32_t access_granted = 0;
398         NTSTATUS status;
399         struct ldb_dn *parent;
400         struct object_tree *tree = NULL;
401
402         parent = ldb_dn_get_parent(ac->req, ac->req->op.del.dn);
403         if (ldb_dn_compare(ares->message->dn, parent) == 0){
404                 status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
405                 if (!NT_STATUS_IS_OK(status)){
406                         ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
407                         return ac->sec_result;
408                 }
409                 status = sec_access_check_ds(sd, ac->token, SEC_ADS_DELETE_CHILD,&access_granted, NULL);
410                 if (NT_STATUS_IS_OK(status)){
411                         ac->sec_result = LDB_SUCCESS;
412                         return ac->sec_result;
413                 }
414         }
415         else if (ldb_dn_compare(ares->message->dn, ac->req->op.del.dn) == 0){
416                 status = sec_access_check_ds(sd, ac->token, SEC_STD_DELETE, &access_granted, NULL);
417                 if (!NT_STATUS_IS_OK(status))
418                         ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
419         }
420         return ac->sec_result;
421 }
422
423 static int acl_access_check_search(struct ldb_reply *ares, struct acl_context *ac,
424                                    struct security_descriptor *sd)
425 {
426         uint32_t access_granted;
427         NTSTATUS status;
428         struct ldb_dn *parent;
429
430         if (ac->user_type == SECURITY_SYSTEM || ac->user_type == SECURITY_ANONYMOUS) {
431                 return LDB_SUCCESS;/*FIXME: we have anonymous access*/
432         }
433
434         parent = ldb_dn_get_parent(ac->req, ac->dn_to_check);
435         ac->sec_result = LDB_SUCCESS;
436         if (ldb_dn_compare(ares->message->dn, parent) == 0) {
437                 status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
438                 if (!NT_STATUS_IS_OK(status)) {
439                         ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
440                 }
441         }
442
443         return ac->sec_result;
444 }
445
446 static int acl_perform_access_check(struct ldb_request *req, struct ldb_reply *ares,
447                                     struct acl_context *ac)
448 {
449         struct ldb_message_element *oc_el;
450         struct security_descriptor *sd;
451         enum ndr_err_code ndr_err;
452
453         oc_el = ldb_msg_find_element(ares->message, "ntSecurityDescriptor");
454         if (!oc_el || oc_el->num_values == 0)
455                 return LDB_SUCCESS;
456
457         sd = talloc(ac, struct security_descriptor);
458         if(!sd) {
459                 return ldb_module_done(ac->req, ares->controls,
460                                        ares->response, LDB_ERR_OPERATIONS_ERROR);
461         }
462         ndr_err = ndr_pull_struct_blob(&oc_el->values[0], sd, NULL, sd,
463                                        (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
464
465         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err))
466                 return ldb_module_done(ac->req, ares->controls,
467                                        ares->response, LDB_ERR_OPERATIONS_ERROR);
468         switch (ac->req->operation) {
469         case LDB_SEARCH:
470                 return acl_access_check_search(ares, ac, sd);
471         case LDB_ADD:
472                 return acl_access_check_add(ares, ac, sd);
473         case LDB_MODIFY:
474                 return acl_access_check_modify(ares, ac, sd);
475         case LDB_DELETE:
476                 return acl_access_check_delete(ares, ac, sd);
477         case LDB_RENAME:
478                 return acl_access_check_rename(ares, ac, sd);
479         default:
480                 return ldb_module_done(ac->req, ares->controls,
481                                        ares->response, LDB_ERR_OPERATIONS_ERROR);
482         }
483         return LDB_SUCCESS;
484 }
485
486 static int acl_forward_add(struct ldb_reply *ares,
487                            struct acl_context *ac)
488 {
489   struct ldb_request *newreq;
490         struct ldb_context *ldb;
491         int ret;
492
493         ldb = ldb_module_get_ctx(ac->module);
494         ret = ldb_build_add_req(&newreq,ldb,
495                                 ac,
496                                 ac->req->op.add.message,
497                                 ac->req->controls,
498                                 ac,
499                                 acl_op_callback,
500                                 ac->req);
501         if (ret != LDB_SUCCESS)
502                 return ldb_module_done(ac->req, ares->controls,
503                                        ares->response, LDB_ERR_OPERATIONS_ERROR);
504         return ldb_next_request(ac->module, newreq);
505 }
506
507 static int acl_forward_modify(struct ldb_reply *ares,
508                               struct acl_context *ac)
509 {
510   struct ldb_request *newreq;
511         struct ldb_context *ldb;
512         int ret;
513
514         ldb = ldb_module_get_ctx(ac->module);
515         ret = ldb_build_mod_req(&newreq,ldb,
516                                     ac,
517                                     ac->req->op.mod.message,
518                                     ac->req->controls,
519                                     ac,
520                                     acl_op_callback,
521                                     ac->req);
522         if (ret != LDB_SUCCESS)
523                 return ldb_module_done(ac->req, ares->controls,
524                                        ares->response, LDB_ERR_OPERATIONS_ERROR);
525         return ldb_next_request(ac->module, newreq);
526 }
527
528 static int acl_forward_delete(struct ldb_reply *ares,
529                               struct acl_context *ac)
530 {
531         struct ldb_request *newreq;
532         struct ldb_context *ldb;
533         int ret;
534
535         ldb = ldb_module_get_ctx(ac->module);
536         ret = ldb_build_del_req(&newreq, ldb,
537                                     ac,
538                                     ac->req->op.del.dn,
539                                     ac->req->controls,
540                                     ac,
541                                     acl_op_callback,
542                                     ac->req);
543         if (ret != LDB_SUCCESS)
544                 return ldb_module_done(ac->req, ares->controls,
545                                        ares->response, LDB_ERR_OPERATIONS_ERROR);
546         return ldb_next_request(ac->module, newreq);
547 }
548
549 static int acl_forward_rename(struct ldb_reply *ares,
550                               struct acl_context *ac)
551 {
552         return LDB_SUCCESS;
553 }
554
555 static int acl_forward_search(struct acl_context *ac)
556 {
557         int ret;
558         const char * const *attrs;
559         struct ldb_control *sd_control;
560         struct ldb_control **sd_saved_controls;
561         struct ldb_context *ldb;
562         struct ldb_request *newreq;
563
564         ldb = ldb_module_get_ctx(ac->module);
565         attrs = ac->req->op.search.attrs;
566         if (attrs) {
567                 ac->nTSecurityDescriptor = false;
568                 ac->objectClass = false;
569                 if (!ldb_attr_in_list(ac->req->op.search.attrs, "nTSecurityDescriptor")) {
570                         attrs = ldb_attr_list_copy_add(ac, attrs, "nTSecurityDescriptor");
571                         ac->nTSecurityDescriptor = true;
572                 }
573                 if (!ldb_attr_in_list(ac->req->op.search.attrs, "objectClass")) {
574                         attrs = ldb_attr_list_copy_add(ac, attrs, "objectClass");
575                         ac->objectClass = true;
576                 }
577         }
578         ret = ldb_build_search_req_ex(&newreq,ldb,
579                                       ac,
580                                       ac->req->op.search.base,
581                                       ac->req->op.search.scope,
582                                       ac->req->op.search.tree,
583                                       attrs,
584                                       ac->req->controls,
585                                       ac, acl_search_callback,
586                                       ac->req);
587         if (ret != LDB_SUCCESS) {
588                 return LDB_ERR_OPERATIONS_ERROR;
589         }
590         /* check if there's an SD_FLAGS control */
591         sd_control = ldb_request_get_control(newreq, LDB_CONTROL_SD_FLAGS_OID);
592         if (sd_control) {
593                 /* save it locally and remove it from the list */
594                 /* we do not need to replace them later as we
595                  * are keeping the original req intact */
596                 if (!save_controls(sd_control, newreq, &sd_saved_controls)) {
597                         return LDB_ERR_OPERATIONS_ERROR;
598                 }
599         }
600         return ldb_next_request(ac->module, newreq);
601 }
602
603 static int acl_forward_request(struct ldb_reply *ares,
604                                struct acl_context *ac)
605 {
606         switch (ac->req->operation) {
607         case LDB_SEARCH:
608                 return acl_forward_search(ac);
609         case LDB_ADD:
610                 return acl_forward_add(ares,ac);
611         case LDB_MODIFY:
612                 return acl_forward_modify(ares,ac);
613         case LDB_DELETE:
614                 return acl_forward_delete(ares,ac);
615         case LDB_RENAME:
616                 return acl_forward_rename(ares,ac);
617         default:
618                 return ldb_module_done(ac->req, ares->controls,
619                                        ares->response, LDB_ERR_OPERATIONS_ERROR);
620         }
621         return LDB_SUCCESS;
622 }
623
624 static int acl_visible_callback(struct ldb_request *req, struct ldb_reply *ares)
625 {
626         struct acl_context *ac;
627
628         ac = talloc_get_type(req->context, struct acl_context);
629
630         if (!ares) {
631                 return ldb_module_done(ac->req, NULL, NULL,
632                                         LDB_ERR_OPERATIONS_ERROR);
633         }
634
635         if (ares->error != LDB_SUCCESS) {
636                 return ldb_module_done(ac->req, ares->controls,
637                                         ares->response, ares->error);
638         }
639
640         switch (ares->type) {
641         case LDB_REPLY_ENTRY:
642                 return acl_perform_access_check(req, ares, ac);
643         case LDB_REPLY_REFERRAL:
644                 return ldb_module_send_referral(ac->req, ares->referral); /* what to do here actually? */
645         case LDB_REPLY_DONE:
646                 if (ac->sec_result != LDB_SUCCESS) {
647                         return ldb_module_done(ac->req, ares->controls,
648                                                ares->response, ac->sec_result);
649                 }
650                 return acl_forward_request(ares,ac);
651         default:
652                 break;
653         }
654         return LDB_SUCCESS;
655 }
656
657 static enum security_user_level what_is_user(struct ldb_module *module)
658 {
659         struct ldb_context *ldb = ldb_module_get_ctx(module);
660         struct auth_session_info *session_info
661                 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
662         return security_session_user_level(session_info);
663 }
664
665 static struct security_token * user_token(struct ldb_module *module)
666 {
667         struct ldb_context *ldb = ldb_module_get_ctx(module);
668         struct auth_session_info *session_info
669                 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
670         if(!session_info) {
671                 return NULL;
672         }
673         return session_info->security_token;
674 }
675
676
677 static int make_req_access_check(struct ldb_module *module, struct ldb_request *req,
678                                  struct acl_context *ac, const char *filter)
679 {
680         struct ldb_context *ldb;
681         int ret;
682         const char **attrs = talloc_array(ac, const char *, 3);
683         struct ldb_parse_tree *tree = ldb_parse_tree(req, filter);
684
685         attrs[0] = talloc_strdup(attrs, "ntSecurityDescriptor");
686         attrs[1] = talloc_strdup(attrs, "objectClass");
687         attrs[2] = NULL;
688
689         ldb = ldb_module_get_ctx(module);
690         ret = ldb_build_search_req_ex(&ac->down_req,
691                                       ldb, ac,
692                                       ac->dn_to_check,
693                                       LDB_SCOPE_SUBTREE,
694                                       tree,
695                                       attrs,
696                                       NULL,
697                                       ac, acl_visible_callback,
698                                       req);
699         return ret;
700 }
701
702 static const char *user_name(TALLOC_CTX *mem_ctx, struct ldb_module *module)
703 {
704         struct ldb_context *ldb = ldb_module_get_ctx(module);
705         struct auth_session_info *session_info
706                 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
707         if (!session_info) {
708                 return "UNKNOWN (NULL)";
709         }
710
711         return talloc_asprintf(mem_ctx, "%s\\%s",
712                                session_info->server_info->domain_name,
713                                session_info->server_info->account_name);
714 }
715
716 static int acl_module_init(struct ldb_module *module)
717 {
718         struct ldb_context *ldb;
719         struct acl_private *data;
720         int ret;
721
722         ldb = ldb_module_get_ctx(module);
723
724         ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
725         if (ret != LDB_SUCCESS) {
726                 ldb_debug(ldb, LDB_DEBUG_ERROR,
727                           "acl_module_init: Unable to register control with rootdse!\n");
728                 return LDB_ERR_OPERATIONS_ERROR;
729         }
730
731         data = talloc(module, struct acl_private);
732         data->perform_check = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
733                                   NULL, "acl", "perform", false);
734         ldb_module_set_private(module, data);
735
736         return ldb_next_init(module);
737 }
738
739 static int acl_add(struct ldb_module *module, struct ldb_request *req)
740 {
741         int ret;
742         struct acl_context *ac;
743         struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.add.message->dn);
744         char * filter;
745         struct ldb_context *ldb;
746         struct acl_private *data;
747
748         ldb = ldb_module_get_ctx(module);
749         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
750
751         if (!data->perform_check)
752                 return ldb_next_request(module, req);
753
754         ac = talloc(req, struct acl_context);
755         if (ac == NULL) {
756                 return LDB_ERR_OPERATIONS_ERROR;
757         }
758
759         if (what_is_user(module) == SECURITY_SYSTEM)
760                 return ldb_next_request(module, req);
761
762         ac->module = module;
763         ac->req = req;
764         ac->ignore_security = true;
765         ac->dn_to_check = ldb_dn_get_parent(req, parent);
766         ac->token = user_token(module);
767         ac->user_type = what_is_user(module);
768         ac->sec_result = LDB_SUCCESS;
769         if (!is_root_base_dn(ldb, req->op.add.message->dn) && parent && !is_root_base_dn(ldb, parent)){
770                 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
771                                          ldb_dn_get_component_name(parent,0),
772                                          ldb_dn_get_component_val(parent,0)->data,
773                                          ldb_dn_get_component_name(ac->dn_to_check,0),
774                                          ldb_dn_get_component_val(ac->dn_to_check,0)->data);
775
776                 ret = make_req_access_check(module, req, ac, filter);
777                 if (ret != LDB_SUCCESS){
778                         return ret;
779                 }
780                 return ldb_next_request(module, ac->down_req);
781         }
782         return ldb_next_request(module, req);
783 }
784
785 static int acl_modify(struct ldb_module *module, struct ldb_request *req)
786 {
787         int ret;
788         struct acl_context *ac;
789         struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.mod.message->dn);
790         char * filter;
791         struct ldb_context *ldb;
792         struct acl_private *data;
793
794         ldb = ldb_module_get_ctx(module);
795         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
796
797         if (!data->perform_check)
798                 return ldb_next_request(module, req);
799
800         ac = talloc(req, struct acl_context);
801         if (ac == NULL) {
802                 return LDB_ERR_OPERATIONS_ERROR;
803         }
804
805 /*      if (what_is_user(module) == SECURITY_SYSTEM) */
806                 return ldb_next_request(module, req);
807
808         ac->module = module;
809         ac->req = req;
810         ac->ignore_security = true;
811         ac->dn_to_check = req->op.mod.message->dn;
812         ac->token = user_token(module);
813         ac->user_type = what_is_user(module);
814         ac->sec_result = LDB_SUCCESS;
815         if (!is_root_base_dn(ldb, req->op.mod.message->dn) && parent && !is_root_base_dn(ldb, parent)){
816           filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
817                                    ldb_dn_get_component_name(parent,0),
818                                    ldb_dn_get_component_val(parent,0)->data,
819                                    ldb_dn_get_component_name(req->op.mod.message->dn,0),
820                                    ldb_dn_get_component_val(req->op.mod.message->dn,0)->data);
821
822                 ret = make_req_access_check(module, req, ac, filter);
823                 if (ret != LDB_SUCCESS){
824                         return ret;
825                 }
826                 return ldb_next_request(module, ac->down_req);
827         }
828         return ldb_next_request(module, req);
829 }
830
831 /* similar to the modify for the time being.
832  * We need to concider the special delete tree case, though - TODO */
833 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
834 {
835         int ret;
836         struct acl_context *ac;
837         struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.del.dn);
838         char * filter;
839         struct ldb_context *ldb;
840         struct acl_private *data;
841
842         ldb = ldb_module_get_ctx(module);
843         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
844
845         if (!data->perform_check)
846                 return ldb_next_request(module, req);
847
848         ac = talloc(req, struct acl_context);
849         if (ac == NULL) {
850                 return LDB_ERR_OPERATIONS_ERROR;
851         }
852
853         if (ac->user_type == SECURITY_SYSTEM)
854                 return ldb_next_request(module, req);
855
856         ac->module = module;
857         ac->req = req;
858         ac->ignore_security = true;
859         ac->dn_to_check = req->op.del.dn;
860         ac->token = user_token(module);
861         ac->user_type = what_is_user(module);
862         ac->sec_result = LDB_SUCCESS;
863         if (parent) {
864                 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
865                                          ldb_dn_get_component_name(parent,0),
866                                          ldb_dn_get_component_val(parent,0)->data,
867                                          ldb_dn_get_component_name(req->op.del.dn,0),
868                                          ldb_dn_get_component_val(req->op.del.dn,0)->data);
869                 ret = make_req_access_check(module, req, ac, filter);
870
871                 if (ret != LDB_SUCCESS){
872                         return ret;
873                 }
874                 return ldb_next_request(module, ac->down_req);
875         }
876
877         return ldb_next_request(module, req);
878 }
879
880 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
881 {
882         struct ldb_dn *source_parent;
883         struct ldb_dn *dest_parent;
884         int ret;
885         struct acl_context *ac;
886         char * filter;
887         struct ldb_context *ldb;
888         struct acl_private *data;
889
890         ldb = ldb_module_get_ctx(module);
891         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
892
893         if (!data->perform_check)
894                 return ldb_next_request(module, req);
895
896         ac = talloc(req, struct acl_context);
897         if (ac == NULL) {
898                 return LDB_ERR_OPERATIONS_ERROR;
899         }
900
901         if (ac->user_type == SECURITY_SYSTEM)
902                 return ldb_next_request(module, req);
903
904         ac->module = module;
905         ac->req = req;
906         ac->ignore_security = true;
907         ac->token = user_token(module);
908         ac->user_type = what_is_user(module);
909         ac->sec_result = LDB_SUCCESS;
910
911         /* We need to know if it is a simple rename or a move operation */
912         source_parent = ldb_dn_get_parent(req, req->op.rename.olddn);
913         dest_parent = ldb_dn_get_parent(req, req->op.rename.newdn);
914
915         if (ldb_dn_compare(source_parent, dest_parent) == 0){
916                 /*Not a move, just rename*/
917                 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
918                                          ldb_dn_get_component_name(dest_parent,0),
919                                          ldb_dn_get_component_val(dest_parent,0)->data,
920                                          ldb_dn_get_component_name(req->op.rename.olddn,0),
921                                          ldb_dn_get_component_val(req->op.rename.olddn,0)->data);
922         }
923         else{
924                 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
925                                          ldb_dn_get_component_name(dest_parent,0),
926                                          ldb_dn_get_component_val(dest_parent,0)->data,
927                                          ldb_dn_get_component_name(source_parent,0),
928                                          ldb_dn_get_component_val(source_parent,0)->data);
929         }
930
931         ret = make_req_access_check(module, req, ac, filter);
932
933         if (ret != LDB_SUCCESS){
934                 return ret;
935                 }
936         return ldb_next_request(module, ac->down_req);
937 }
938
939 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
940 {
941         struct ldb_context *ldb;
942         struct acl_context *ac;
943         struct security_descriptor *sd;
944         uint32_t searchFlags;
945         uint32_t access_mask;
946         struct object_tree *ot;
947         int i, ret;
948         NTSTATUS status;
949         struct ldb_message_element *element_security_descriptor;
950         struct ldb_message_element *element_object_class;
951         const struct dsdb_attribute *attr;
952         const struct dsdb_schema *schema;
953         struct GUID *oc_guid;
954
955         ac = talloc_get_type(req->context, struct acl_context);
956         ldb = ldb_module_get_ctx(ac->module);
957         schema = dsdb_get_schema(ldb);
958         if (!ares) {
959                 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
960         }
961         if (ares->error != LDB_SUCCESS) {
962                 return ldb_module_done(ac->req, ares->controls, ares->response, ares->error);
963         }
964
965         switch (ares->type) {
966         case LDB_REPLY_ENTRY:
967                 switch (ac->user_type) {
968                 case SECURITY_SYSTEM:
969                 case SECURITY_ANONYMOUS:/*FIXME: should we let anonymous have system access*/
970                         break;
971                 default:
972                         /* Access checks
973                          *
974                          * 0. If we do not have nTSecurityDescriptor, we do not have an object in the response,
975                          *    so check the parent dn.
976                          * 1. Call sec_access_check on empty tree
977                          * 2. For each attribute call extended_access_check
978                          * 3. For each attribute call build_object_tree_form_attr_list and then check with sec_access_check
979                          *
980                          */
981                         element_security_descriptor = ldb_msg_find_element(ares->message, "nTSecurityDescriptor");
982                         element_object_class = ldb_msg_find_element(ares->message, "objectClass");
983                         if (!element_security_descriptor || !element_object_class)
984                                 break;
985
986                         sd = talloc(ldb, struct security_descriptor);
987                         if(!sd) {
988                           return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
989                         }
990                         if(!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&element_security_descriptor->values[0],
991                                                                          ldb,
992                                                                          NULL,
993                                                                          sd,
994                                                                          (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
995                                 DEBUG(0, ("acl_search_callback: Error parsing security descriptor\n"));
996                                 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
997                         }
998
999                         oc_guid = class_schemaid_guid_by_lDAPDisplayName(schema, element_object_class->values[0].data);
1000                         for (i=0; i<ares->message->num_elements; i++) {
1001                                 attr = dsdb_attribute_by_lDAPDisplayName(schema, ares->message->elements[i].name);
1002                                 if (attr) {
1003                                         searchFlags = attr->searchFlags;
1004                                 } else {
1005                                         searchFlags = 0x0;
1006                                 }
1007
1008                                 /*status = extended_access_check(ares->message->elements[i].name, access_mask, searchFlags); */ /* Todo FIXME */
1009                                 ac->access_needed = SEC_ADS_READ_PROP;
1010                                 if (NT_STATUS_IS_OK(status)) {
1011                                         ot = insert_in_object_tree(req, oc_guid, NULL, ac->access_needed, NULL);
1012
1013                                         insert_in_object_tree(req,
1014                                                               &attr->schemaIDGUID,
1015                                                               &attr->attributeSecurityGUID,
1016                                                               ac->access_needed,
1017                                                               ot);
1018
1019                                         status = sec_access_check_ds(sd,
1020                                                                      ac->token,
1021                                                                      ac->access_needed,
1022                                                                      &access_mask,
1023                                                                      ot);
1024
1025                                         if (NT_STATUS_IS_OK(status)) {
1026                                                 continue;
1027                                         }
1028                                 }
1029                                 ldb_msg_remove_attr(ares->message, ares->message->elements[i].name);
1030                         }
1031                         break;
1032                 }
1033                 if (ac->nTSecurityDescriptor) {
1034                         ldb_msg_remove_attr(ares->message, "nTSecurityDescriptor");
1035                 } else if (ac->objectClass) {
1036                         ldb_msg_remove_attr(ares->message, "objectClass");
1037                 }
1038
1039                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
1040         case LDB_REPLY_REFERRAL:
1041                 return ldb_module_send_referral(ac->req, ares->referral);
1042
1043         case LDB_REPLY_DONE:
1044                 return ldb_module_done(ac->req, ares->controls,ares->response, LDB_SUCCESS);
1045         }
1046
1047         return LDB_SUCCESS;
1048 }
1049
1050 static int acl_search(struct ldb_module *module, struct ldb_request *req)
1051 {
1052         int ret;
1053         struct ldb_context *ldb;
1054         struct acl_context *ac;
1055         const char **attrs;
1056         struct ldb_control *sd_control;
1057         struct ldb_control **sd_saved_controls;
1058         struct ldb_dn * parent;
1059         struct acl_private *data;
1060
1061         ldb = ldb_module_get_ctx(module);
1062         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
1063
1064         if (!data || !data->perform_check)
1065                 return ldb_next_request(module, req);
1066
1067         if (what_is_user(module) == SECURITY_SYSTEM)
1068                 return ldb_next_request(module, req);
1069
1070         ac = talloc_get_type(req->context, struct acl_context);
1071         if ( ac == NULL ) {
1072                 ac = talloc(req, struct acl_context);
1073                 if (ac == NULL) {
1074                         ldb_oom(ldb);
1075                         return LDB_ERR_OPERATIONS_ERROR;
1076                 }
1077                 ac->module = module;
1078                 ac->req = req;
1079                 ac->ignore_security = false;
1080                 ac->user_type = what_is_user(module);
1081                 ac->token = user_token(module);
1082                 ac->dn_to_check = req->op.search.base;
1083                 ac->sec_result = LDB_SUCCESS;
1084
1085                 attrs = talloc_array(ac, const char*, 2);
1086                 attrs[0] = talloc_strdup(attrs, "nTSecurityDescriptor");
1087                 attrs[1] = NULL;
1088                 parent = ldb_dn_get_parent(req, ac->dn_to_check);
1089                 if (!is_root_base_dn(ldb, req->op.search.base) && parent && !is_root_base_dn(ldb, parent)) {
1090                         /*we have parent so check for visibility*/
1091                         ret = ldb_build_search_req(&ac->down_req,
1092                                                    ldb, ac,
1093                                                    parent,
1094                                                    LDB_SCOPE_BASE,
1095                                                    "(objectClass=*)",
1096                                                    attrs,
1097                                                    req->controls,
1098                                                    ac, acl_visible_callback,
1099                                                    req);
1100                         if (ret != LDB_SUCCESS) {
1101                                 return ret;
1102                         }
1103                         return ldb_next_request(module, ac->down_req);
1104                 } else {
1105                         return acl_forward_search(ac);
1106                 }
1107         }
1108
1109         return ldb_next_request(module, req);
1110 }
1111
1112 static int acl_extended(struct ldb_module *module, struct ldb_request *req)
1113 {
1114         struct ldb_context *ldb = ldb_module_get_ctx(module);
1115         enum security_user_level user_type;
1116         struct acl_private *data;
1117
1118         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
1119
1120         if (!data->perform_check)
1121                 return ldb_next_request(module, req);
1122
1123         /* allow everybody to read the sequence number */
1124         if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
1125                 return ldb_next_request(module, req);
1126         }
1127
1128         user_type = what_is_user(module);
1129         switch (user_type) {
1130         case SECURITY_SYSTEM:
1131         case SECURITY_ADMINISTRATOR:
1132                 return ldb_next_request(module, req);
1133         default:
1134                 ldb_asprintf_errstring(ldb,
1135                                        "acl_extended: attempted database modify not permitted."
1136                                        "User %s is not SYSTEM or an Administrator",
1137                                        user_name(req, module));
1138                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1139         }
1140 }
1141
1142 _PUBLIC_ const struct ldb_module_ops ldb_acl_module_ops = {
1143         .name              = "acl",
1144         .search            = acl_search,
1145         .add               = acl_add,
1146         .modify            = acl_modify,
1147         .del               = acl_delete,
1148         .rename            = acl_rename,
1149         .extended          = acl_extended,
1150         .init_context      = acl_module_init
1151 };