1/*
2 *  Unix SMB/Netbios implementation.
3 *  SEC_DESC handling functions
4 *  Copyright (C) Andrew Tridgell              1992-1998,
5 *  Copyright (C) Jeremy R. Allison            1995-2003.
6 *  Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
7 *  Copyright (C) Paul Ashton                  1997-1998.
8 *
9 *  This program is free software; you can redistribute it and/or modify
10 *  it under the terms of the GNU General Public License as published by
11 *  the Free Software Foundation; either version 2 of the License, or
12 *  (at your option) any later version.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include "includes.h"
25
26/* Map generic permissions to file object specific permissions */
27
28struct generic_mapping file_generic_mapping = {
29	FILE_GENERIC_READ,
30	FILE_GENERIC_WRITE,
31	FILE_GENERIC_EXECUTE,
32	FILE_GENERIC_ALL
33};
34
35/*******************************************************************
36 Works out the linearization size of a SEC_DESC.
37********************************************************************/
38
39size_t sec_desc_size(SEC_DESC *psd)
40{
41	size_t offset;
42
43	if (!psd) return 0;
44
45	offset = SEC_DESC_HEADER_SIZE;
46
47	/* don't align */
48
49	if (psd->owner_sid != NULL)
50		offset += sid_size(psd->owner_sid);
51
52	if (psd->group_sid != NULL)
53		offset += sid_size(psd->group_sid);
54
55	if (psd->sacl != NULL)
56		offset += psd->sacl->size;
57
58	if (psd->dacl != NULL)
59		offset += psd->dacl->size;
60
61	return offset;
62}
63
64/*******************************************************************
65 Compares two SEC_DESC structures
66********************************************************************/
67
68BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
69{
70	/* Trivial case */
71
72	if (!s1 && !s2) {
73		goto done;
74	}
75
76	if (!s1 || !s2) {
77		return False;
78	}
79
80	/* Check top level stuff */
81
82	if (s1->revision != s2->revision) {
83		DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
84			   s1->revision, s2->revision));
85		return False;
86	}
87
88	if (s1->type!= s2->type) {
89		DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
90			   s1->type, s2->type));
91		return False;
92	}
93
94	/* Check owner and group */
95
96	if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
97		fstring str1, str2;
98
99		sid_to_string(str1, s1->owner_sid);
100		sid_to_string(str2, s2->owner_sid);
101
102		DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
103			   str1, str2));
104		return False;
105	}
106
107	if (!sid_equal(s1->group_sid, s2->group_sid)) {
108		fstring str1, str2;
109
110		sid_to_string(str1, s1->group_sid);
111		sid_to_string(str2, s2->group_sid);
112
113		DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
114			   str1, str2));
115		return False;
116	}
117
118	/* Check ACLs present in one but not the other */
119
120	if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
121	    (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
122		DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
123		return False;
124	}
125
126	/* Sigh - we have to do it the hard way by iterating over all
127	   the ACEs in the ACLs */
128
129	if (!sec_acl_equal(s1->dacl, s2->dacl) ||
130	    !sec_acl_equal(s1->sacl, s2->sacl)) {
131		DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
132		return False;
133	}
134
135 done:
136	DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
137	return True;
138}
139
140/*******************************************************************
141 Merge part of security descriptor old_sec in to the empty sections of
142 security descriptor new_sec.
143********************************************************************/
144
145SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
146{
147	DOM_SID *owner_sid, *group_sid;
148	SEC_DESC_BUF *return_sdb;
149	SEC_ACL *dacl, *sacl;
150	SEC_DESC *psd = NULL;
151	uint16 secdesc_type;
152	size_t secdesc_size;
153
154	/* Copy over owner and group sids.  There seems to be no flag for
155	   this so just check the pointer values. */
156
157	owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
158		old_sdb->sec->owner_sid;
159
160	group_sid = new_sdb->sec->group_sid ? new_sdb->sec->group_sid :
161		old_sdb->sec->group_sid;
162
163	secdesc_type = new_sdb->sec->type;
164
165	/* Ignore changes to the system ACL.  This has the effect of making
166	   changes through the security tab audit button not sticking.
167	   Perhaps in future Samba could implement these settings somehow. */
168
169	sacl = NULL;
170	secdesc_type &= ~SEC_DESC_SACL_PRESENT;
171
172	/* Copy across discretionary ACL */
173
174	if (secdesc_type & SEC_DESC_DACL_PRESENT) {
175		dacl = new_sdb->sec->dacl;
176	} else {
177		dacl = old_sdb->sec->dacl;
178	}
179
180	/* Create new security descriptor from bits */
181
182	psd = make_sec_desc(ctx, new_sdb->sec->revision, secdesc_type,
183			    owner_sid, group_sid, sacl, dacl, &secdesc_size);
184
185	return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
186
187	return(return_sdb);
188}
189
190/*******************************************************************
191 Creates a SEC_DESC structure
192********************************************************************/
193
194SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision, uint16 type,
195			const DOM_SID *owner_sid, const DOM_SID *group_sid,
196			SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
197{
198	SEC_DESC *dst;
199	uint32 offset     = 0;
200
201	*sd_size = 0;
202
203	if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
204		return NULL;
205
206	dst->revision = revision;
207	dst->type = type;
208
209	if (sacl)
210		dst->type |= SEC_DESC_SACL_PRESENT;
211	if (dacl)
212		dst->type |= SEC_DESC_DACL_PRESENT;
213
214	dst->off_owner_sid = 0;
215	dst->off_grp_sid   = 0;
216	dst->off_sacl      = 0;
217	dst->off_dacl      = 0;
218
219	if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL))
220		goto error_exit;
221
222	if(group_sid && ((dst->group_sid = sid_dup_talloc(ctx,group_sid)) == NULL))
223		goto error_exit;
224
225	if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL))
226		goto error_exit;
227
228	if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL))
229		goto error_exit;
230
231	offset = SEC_DESC_HEADER_SIZE;
232
233	/*
234	 * Work out the linearization sizes.
235	 */
236
237	if (dst->sacl != NULL) {
238		dst->off_sacl = offset;
239		offset += dst->sacl->size;
240	}
241	if (dst->dacl != NULL) {
242		dst->off_dacl = offset;
243		offset += dst->dacl->size;
244	}
245
246	if (dst->owner_sid != NULL) {
247		dst->off_owner_sid = offset;
248		offset += sid_size(dst->owner_sid);
249	}
250
251	if (dst->group_sid != NULL) {
252		dst->off_grp_sid = offset;
253		offset += sid_size(dst->group_sid);
254	}
255
256	*sd_size = (size_t)offset;
257	return dst;
258
259error_exit:
260
261	*sd_size = 0;
262	return NULL;
263}
264
265/*******************************************************************
266 Duplicate a SEC_DESC structure.
267********************************************************************/
268
269SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
270{
271	size_t dummy;
272
273	if(src == NULL)
274		return NULL;
275
276	return make_sec_desc( ctx, src->revision, src->type,
277				src->owner_sid, src->group_sid, src->sacl,
278				src->dacl, &dummy);
279}
280
281/*******************************************************************
282 Creates a SEC_DESC structure with typical defaults.
283********************************************************************/
284
285SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *group_sid,
286				 SEC_ACL *dacl, size_t *sd_size)
287{
288	return make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
289			     owner_sid, group_sid, NULL, dacl, sd_size);
290}
291
292/*******************************************************************
293 Creates a SEC_DESC_BUF structure.
294********************************************************************/
295
296SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
297{
298	SEC_DESC_BUF *dst;
299
300	if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
301		return NULL;
302
303	/* max buffer size (allocated size) */
304	dst->max_len = (uint32)len;
305	dst->len = (uint32)len;
306
307	if(sec_desc && ((dst->sec = dup_sec_desc(ctx, sec_desc)) == NULL)) {
308		return NULL;
309	}
310
311	dst->ptr = 0x1;
312
313	return dst;
314}
315
316/*******************************************************************
317 Duplicates a SEC_DESC_BUF structure.
318********************************************************************/
319
320SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
321{
322	if(src == NULL)
323		return NULL;
324
325	return make_sec_desc_buf( ctx, src->len, src->sec);
326}
327
328/*******************************************************************
329 Add a new SID with its permissions to SEC_DESC.
330********************************************************************/
331
332NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
333{
334	SEC_DESC *sd   = 0;
335	SEC_ACL  *dacl = 0;
336	SEC_ACE  *ace  = 0;
337	NTSTATUS  status;
338
339	if (!ctx || !psd || !sid || !sd_size)
340		return NT_STATUS_INVALID_PARAMETER;
341
342	*sd_size = 0;
343
344	status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
345
346	if (!NT_STATUS_IS_OK(status))
347		return status;
348
349	if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
350		return NT_STATUS_UNSUCCESSFUL;
351
352	if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
353		psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
354		return NT_STATUS_UNSUCCESSFUL;
355
356	*psd = sd;
357	 sd  = 0;
358	return NT_STATUS_OK;
359}
360
361/*******************************************************************
362 Modify a SID's permissions in a SEC_DESC.
363********************************************************************/
364
365NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
366{
367	NTSTATUS status;
368
369	if (!sd || !sid)
370		return NT_STATUS_INVALID_PARAMETER;
371
372	status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
373
374	if (!NT_STATUS_IS_OK(status))
375		return status;
376
377	return NT_STATUS_OK;
378}
379
380/*******************************************************************
381 Delete a SID from a SEC_DESC.
382********************************************************************/
383
384NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
385{
386	SEC_DESC *sd   = 0;
387	SEC_ACL  *dacl = 0;
388	SEC_ACE  *ace  = 0;
389	NTSTATUS  status;
390
391	if (!ctx || !psd[0] || !sid || !sd_size)
392		return NT_STATUS_INVALID_PARAMETER;
393
394	*sd_size = 0;
395
396	status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
397
398	if (!NT_STATUS_IS_OK(status))
399		return status;
400
401	if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
402		return NT_STATUS_UNSUCCESSFUL;
403
404	if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
405		psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
406		return NT_STATUS_UNSUCCESSFUL;
407
408	*psd = sd;
409	 sd  = 0;
410	return NT_STATUS_OK;
411}
412
413/* Create a child security descriptor using another security descriptor as
414   the parent container.  This child object can either be a container or
415   non-container object. */
416
417SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
418				      BOOL child_container)
419{
420	SEC_DESC_BUF *sdb;
421	SEC_DESC *sd;
422	SEC_ACL *new_dacl, *the_acl;
423	SEC_ACE *new_ace_list = NULL;
424	unsigned int new_ace_list_ndx = 0, i;
425	size_t size;
426
427	/* Currently we only process the dacl when creating the child.  The
428	   sacl should also be processed but this is left out as sacls are
429	   not implemented in Samba at the moment.*/
430
431	the_acl = parent_ctr->dacl;
432
433	if (the_acl->num_aces) {
434		if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE, the_acl->num_aces)))
435			return NULL;
436	} else {
437		new_ace_list = NULL;
438	}
439
440	for (i = 0; i < the_acl->num_aces; i++) {
441		SEC_ACE *ace = &the_acl->aces[i];
442		SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
443		uint8 new_flags = 0;
444		BOOL inherit = False;
445		fstring sid_str;
446
447		/* The OBJECT_INHERIT_ACE flag causes the ACE to be
448		   inherited by non-container children objects.  Container
449		   children objects will inherit it as an INHERIT_ONLY
450		   ACE. */
451
452		if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
453
454			if (!child_container) {
455				new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
456			} else {
457				new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
458			}
459
460			inherit = True;
461		}
462
463		/* The CONAINER_INHERIT_ACE flag means all child container
464		   objects will inherit and use the ACE. */
465
466		if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
467			if (!child_container) {
468				inherit = False;
469			} else {
470				new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
471			}
472		}
473
474		/* The INHERIT_ONLY_ACE is not used by the se_access_check()
475		   function for the parent container, but is inherited by
476		   all child objects as a normal ACE. */
477
478		if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
479			/* Move along, nothing to see here */
480		}
481
482		/* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
483		   is inherited by child objects but not grandchildren
484		   objects.  We clear the object inherit and container
485		   inherit flags in the inherited ACE. */
486
487		if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
488			new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
489				       SEC_ACE_FLAG_CONTAINER_INHERIT);
490		}
491
492		/* Add ACE to ACE list */
493
494		if (!inherit)
495			continue;
496
497		init_sec_access(&new_ace->access_mask, ace->access_mask);
498		init_sec_ace(new_ace, &ace->trustee, ace->type,
499			     new_ace->access_mask, new_flags);
500
501		sid_to_string(sid_str, &ace->trustee);
502
503		DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
504			  " inherited as %s:%d/0x%02x/0x%08x\n", sid_str,
505			  ace->type, ace->flags, ace->access_mask,
506			  sid_str, new_ace->type, new_ace->flags,
507			  new_ace->access_mask));
508
509		new_ace_list_ndx++;
510	}
511
512	/* Create child security descriptor to return */
513
514	new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
515
516	/* Use the existing user and group sids.  I don't think this is
517	   correct.  Perhaps the user and group should be passed in as
518	   parameters by the caller? */
519
520	sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
521			   parent_ctr->owner_sid,
522			   parent_ctr->group_sid,
523			   parent_ctr->sacl,
524			   new_dacl, &size);
525
526	sdb = make_sec_desc_buf(ctx, size, sd);
527
528	return sdb;
529}
530
531/*******************************************************************
532 Sets up a SEC_ACCESS structure.
533********************************************************************/
534
535void init_sec_access(SEC_ACCESS *t, uint32 mask)
536{
537	*t = mask;
538}
539