1/**
2 * security.c - Handling security/ACLs in NTFS.  Originated from the Linux-NTFS project.
3 *
4 * Copyright (c) 2004 Anton Altaparmakov
5 * Copyright (c) 2005-2006 Szabolcs Szakacsits
6 * Copyright (c) 2006 Yura Pakhuchiy
7 *
8 * This program/include file is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program/include file is distributed in the hope that it will be
14 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15 * of 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 (in the main directory of the NTFS-3G
20 * distribution in the file COPYING); if not, write to the Free Software
21 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#ifdef HAVE_STDIO_H
29#include <stdio.h>
30#endif
31#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
34#ifdef HAVE_STRING_H
35#include <string.h>
36#endif
37#ifdef HAVE_ERRNO_H
38#include <errno.h>
39#endif
40
41#include "types.h"
42#include "layout.h"
43#include "attrib.h"
44#include "security.h"
45#include "misc.h"
46#include "bitmap.h"
47
48/*
49 * The zero GUID.
50 */
51static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
52		const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
53const GUID *const zero_guid = &__zero_guid;
54
55/**
56 * ntfs_guid_is_zero - check if a GUID is zero
57 * @guid:	[IN] guid to check
58 *
59 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
60 * and FALSE otherwise.
61 */
62BOOL ntfs_guid_is_zero(const GUID *guid)
63{
64	return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
65}
66
67/**
68 * ntfs_guid_to_mbs - convert a GUID to a multi byte string
69 * @guid:	[IN]  guid to convert
70 * @guid_str:	[OUT] string in which to return the GUID (optional)
71 *
72 * Convert the GUID pointed to by @guid to a multi byte string of the form
73 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".  Therefore, @guid_str (if not NULL)
74 * needs to be able to store at least 37 bytes.
75 *
76 * If @guid_str is not NULL it will contain the converted GUID on return.  If
77 * it is NULL a string will be allocated and this will be returned.  The caller
78 * is responsible for free()ing the string in that case.
79 *
80 * On success return the converted string and on failure return NULL with errno
81 * set to the error code.
82 */
83char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
84{
85	char *_guid_str;
86	int res;
87
88	if (!guid) {
89		errno = EINVAL;
90		return NULL;
91	}
92	_guid_str = guid_str;
93	if (!_guid_str) {
94		_guid_str = ntfs_malloc(37);
95		if (!_guid_str)
96			return _guid_str;
97	}
98	res = snprintf(_guid_str, 37,
99			"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
100			(unsigned int)le32_to_cpu(guid->data1),
101			le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
102			guid->data4[0], guid->data4[1],
103			guid->data4[2], guid->data4[3], guid->data4[4],
104			guid->data4[5], guid->data4[6], guid->data4[7]);
105	if (res == 36)
106		return _guid_str;
107	if (!guid_str)
108		free(_guid_str);
109	errno = EINVAL;
110	return NULL;
111}
112
113/**
114 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
115 * @sid:	[IN]  SID for which to determine the maximum string size
116 *
117 * Determine the maximum multi byte string size in bytes which is needed to
118 * store the standard textual representation of the SID pointed to by @sid.
119 * See ntfs_sid_to_mbs(), below.
120 *
121 * On success return the maximum number of bytes needed to store the multi byte
122 * string and on failure return -1 with errno set to the error code.
123 */
124int ntfs_sid_to_mbs_size(const SID *sid)
125{
126	int size, i;
127
128	if (!ntfs_sid_is_valid(sid)) {
129		errno = EINVAL;
130		return -1;
131	}
132	/* Start with "S-". */
133	size = 2;
134	/*
135	 * Add the SID_REVISION.  Hopefully the compiler will optimize this
136	 * away as SID_REVISION is a constant.
137	 */
138	for (i = SID_REVISION; i > 0; i /= 10)
139		size++;
140	/* Add the "-". */
141	size++;
142	/*
143	 * Add the identifier authority.  If it needs to be in decimal, the
144	 * maximum is 2^32-1 = 4294967295 = 10 characters.  If it needs to be
145	 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
146	 */
147	if (!sid->identifier_authority.high_part)
148		size += 10;
149	else
150		size += 14;
151	/*
152	 * Finally, add the sub authorities.  For each we have a "-" followed
153	 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
154	 */
155	size += (1 + 10) * sid->sub_authority_count;
156	/* We need the zero byte at the end, too. */
157	size++;
158	return size * sizeof(char);
159}
160
161/**
162 * ntfs_sid_to_mbs - convert a SID to a multi byte string
163 * @sid:		[IN]  SID to convert
164 * @sid_str:		[OUT] string in which to return the SID (optional)
165 * @sid_str_size:	[IN]  size in bytes of @sid_str
166 *
167 * Convert the SID pointed to by @sid to its standard textual representation.
168 * @sid_str (if not NULL) needs to be able to store at least
169 * ntfs_sid_to_mbs_size() bytes.  @sid_str_size is the size in bytes of
170 * @sid_str if @sid_str is not NULL.
171 *
172 * The standard textual representation of the SID is of the form:
173 *	S-R-I-S-S...
174 * Where:
175 *    - The first "S" is the literal character 'S' identifying the following
176 *	digits as a SID.
177 *    - R is the revision level of the SID expressed as a sequence of digits
178 *	in decimal.
179 *    - I is the 48-bit identifier_authority, expressed as digits in decimal,
180 *	if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
181 *    - S... is one or more sub_authority values, expressed as digits in
182 *	decimal.
183 *
184 * If @sid_str is not NULL it will contain the converted SUID on return.  If it
185 * is NULL a string will be allocated and this will be returned.  The caller is
186 * responsible for free()ing the string in that case.
187 *
188 * On success return the converted string and on failure return NULL with errno
189 * set to the error code.
190 */
191char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
192{
193	u64 u;
194	char *s;
195	int i, j, cnt;
196
197	/*
198	 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
199	 * check @sid, too.  8 is the minimum SID string size.
200	 */
201	if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
202		errno = EINVAL;
203		return NULL;
204	}
205	/* Allocate string if not provided. */
206	if (!sid_str) {
207		cnt = ntfs_sid_to_mbs_size(sid);
208		if (cnt < 0)
209			return NULL;
210		s = ntfs_malloc(cnt);
211		if (!s)
212			return s;
213		sid_str = s;
214		/* So we know we allocated it. */
215		sid_str_size = 0;
216	} else {
217		s = sid_str;
218		cnt = sid_str_size;
219	}
220	/* Start with "S-R-". */
221	i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
222	if (i < 0 || i >= cnt)
223		goto err_out;
224	s += i;
225	cnt -= i;
226	/* Add the identifier authority. */
227	for (u = i = 0, j = 40; i < 6; i++, j -= 8)
228		u += (u64)sid->identifier_authority.value[i] << j;
229	if (!sid->identifier_authority.high_part)
230		i = snprintf(s, cnt, "%lu", (unsigned long)u);
231	else
232		i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
233	if (i < 0 || i >= cnt)
234		goto err_out;
235	s += i;
236	cnt -= i;
237	/* Finally, add the sub authorities. */
238	for (j = 0; j < sid->sub_authority_count; j++) {
239		i = snprintf(s, cnt, "-%u", (unsigned int)
240				le32_to_cpu(sid->sub_authority[j]));
241		if (i < 0 || i >= cnt)
242			goto err_out;
243		s += i;
244		cnt -= i;
245	}
246	return sid_str;
247err_out:
248	if (i >= cnt)
249		i = EMSGSIZE;
250	else
251		i = errno;
252	if (!sid_str_size)
253		free(sid_str);
254	errno = i;
255	return NULL;
256}
257
258/**
259 * ntfs_generate_guid - generatates a random current guid.
260 * @guid:	[OUT]   pointer to a GUID struct to hold the generated guid.
261 *
262 * perhaps not a very good random number generator though...
263 */
264void ntfs_generate_guid(GUID *guid)
265{
266	unsigned int i;
267	u8 *p = (u8 *)guid;
268
269	for (i = 0; i < sizeof(GUID); i++) {
270		p[i] = (u8)(random() & 0xFF);
271		if (i == 7)
272			p[7] = (p[7] & 0x0F) | 0x40;
273		if (i == 8)
274			p[8] = (p[8] & 0x3F) | 0x80;
275	}
276}
277
278int ntfs_sd_add_everyone(ntfs_inode *ni)
279{
280	SECURITY_DESCRIPTOR_ATTR *sd;
281	ACL *acl;
282	ACCESS_ALLOWED_ACE *ace;
283	SID *sid;
284	int ret, sd_len;
285
286	/* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
287	/*
288	 * Calculate security descriptor length. We have 2 sub-authorities in
289	 * owner and group SIDs, but structure SID contain only one, so add
290	 * 4 bytes to every SID.
291	 */
292	sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
293		sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
294	sd = ntfs_calloc(sd_len);
295	if (!sd)
296		return -1;
297
298	sd->revision = 1;
299	sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
300
301	sid = (SID *)((u8 *)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
302	sid->revision = 1;
303	sid->sub_authority_count = 2;
304	sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
305	sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
306	sid->identifier_authority.value[5] = 5;
307	sd->owner = cpu_to_le32((u8 *)sid - (u8 *)sd);
308
309	sid = (SID *)((u8 *)sid + sizeof(SID) + 4);
310	sid->revision = 1;
311	sid->sub_authority_count = 2;
312	sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
313	sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
314	sid->identifier_authority.value[5] = 5;
315	sd->group = cpu_to_le32((u8 *)sid - (u8 *)sd);
316
317	acl = (ACL *)((u8 *)sid + sizeof(SID) + 4);
318	acl->revision = 2;
319	acl->size = cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
320	acl->ace_count = cpu_to_le16(1);
321	sd->dacl = cpu_to_le32((u8 *)acl - (u8 *)sd);
322
323	ace = (ACCESS_ALLOWED_ACE *)((u8 *)acl + sizeof(ACL));
324	ace->type = ACCESS_ALLOWED_ACE_TYPE;
325	ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
326	ace->size = cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
327	ace->mask = cpu_to_le32(0x1f01ff); /* FIXME */
328	ace->sid.revision = 1;
329	ace->sid.sub_authority_count = 1;
330	ace->sid.sub_authority[0] = 0;
331	ace->sid.identifier_authority.value[5] = 1;
332
333	ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8 *)sd,
334			    sd_len);
335	if (ret)
336		ntfs_log_perror("Failed to add SECURITY_DESCRIPTOR\n");
337
338	free(sd);
339	return ret;
340}
341
342/**
343 * ntfs_security_hash - calculate the hash of a security descriptor
344 * @sd:         self-relative security descriptor whose hash to calculate
345 * @length:     size in bytes of the security descritor @sd
346 *
347 * Calculate the hash of the self-relative security descriptor @sd of length
348 * @length bytes.
349 *
350 * This hash is used in the $Secure system file as the primary key for the $SDH
351 * index and is also stored in the header of each security descriptor in the
352 * $SDS data stream as well as in the index data of both the $SII and $SDH
353 * indexes.  In all three cases it forms part of the SDS_ENTRY_HEADER
354 * structure.
355 *
356 * Return the calculated security hash in little endian.
357 */
358le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len)
359{
360        const le32 *pos = (const le32 *)sd;
361        const le32 *end = pos + (len >> 2);
362        u32 hash = 0;
363
364        while (pos < end) {
365                hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3);
366		pos++;
367	}
368        return cpu_to_le32(hash);
369}
370
371