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