• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/dsdb/samdb/ldb_modules/
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 */
44struct 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
67struct extended_access_check_attribute {
68	const char *oa_name;
69	const uint32_t requires_rights;
70};
71
72struct acl_private{
73	bool perform_check;
74};
75
76static 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*/
82static 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
142static 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 */
239static 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
269bool 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
277static 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
303static 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
346static 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*/
388static 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
394static 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
423static 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
446static 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
486static 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
507static 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
528static 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
549static int acl_forward_rename(struct ldb_reply *ares,
550			      struct acl_context *ac)
551{
552	return LDB_SUCCESS;
553}
554
555static 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
603static 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
624static 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
657static 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
665static 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
677static 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
702static 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
716static 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
739static 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
785static 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 */
833static 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
880static 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
939static 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
1050static 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
1112static 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};
1152