xref: /haiku/src/add-ons/kernel/file_systems/ntfs/libntfs/security.c (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
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 
47 /*
48  * The zero GUID.
49  */
50 static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
51 		const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
52 const GUID *const zero_guid = &__zero_guid;
53 
54 /**
55  * ntfs_guid_is_zero - check if a GUID is zero
56  * @guid:	[IN] guid to check
57  *
58  * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
59  * and FALSE otherwise.
60  */
61 BOOL ntfs_guid_is_zero(const GUID *guid)
62 {
63 	return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
64 }
65 
66 /**
67  * ntfs_guid_to_mbs - convert a GUID to a multi byte string
68  * @guid:	[IN]  guid to convert
69  * @guid_str:	[OUT] string in which to return the GUID (optional)
70  *
71  * Convert the GUID pointed to by @guid to a multi byte string of the form
72  * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".  Therefore, @guid_str (if not NULL)
73  * needs to be able to store at least 37 bytes.
74  *
75  * If @guid_str is not NULL it will contain the converted GUID on return.  If
76  * it is NULL a string will be allocated and this will be returned.  The caller
77  * is responsible for free()ing the string in that case.
78  *
79  * On success return the converted string and on failure return NULL with errno
80  * set to the error code.
81  */
82 char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
83 {
84 	char *_guid_str;
85 	int res;
86 
87 	if (!guid) {
88 		errno = EINVAL;
89 		return NULL;
90 	}
91 	_guid_str = guid_str;
92 	if (!_guid_str) {
93 		_guid_str = ntfs_malloc(37);
94 		if (!_guid_str)
95 			return _guid_str;
96 	}
97 	res = snprintf(_guid_str, 37,
98 			"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
99 			(unsigned int)le32_to_cpu(guid->data1),
100 			le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
101 			guid->data4[0], guid->data4[1],
102 			guid->data4[2], guid->data4[3], guid->data4[4],
103 			guid->data4[5], guid->data4[6], guid->data4[7]);
104 	if (res == 36)
105 		return _guid_str;
106 	if (!guid_str)
107 		free(_guid_str);
108 	errno = EINVAL;
109 	return NULL;
110 }
111 
112 /**
113  * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
114  * @sid:	[IN]  SID for which to determine the maximum string size
115  *
116  * Determine the maximum multi byte string size in bytes which is needed to
117  * store the standard textual representation of the SID pointed to by @sid.
118  * See ntfs_sid_to_mbs(), below.
119  *
120  * On success return the maximum number of bytes needed to store the multi byte
121  * string and on failure return -1 with errno set to the error code.
122  */
123 int ntfs_sid_to_mbs_size(const SID *sid)
124 {
125 	int size, i;
126 
127 	if (!ntfs_sid_is_valid(sid)) {
128 		errno = EINVAL;
129 		return -1;
130 	}
131 	/* Start with "S-". */
132 	size = 2;
133 	/*
134 	 * Add the SID_REVISION.  Hopefully the compiler will optimize this
135 	 * away as SID_REVISION is a constant.
136 	 */
137 	for (i = SID_REVISION; i > 0; i /= 10)
138 		size++;
139 	/* Add the "-". */
140 	size++;
141 	/*
142 	 * Add the identifier authority.  If it needs to be in decimal, the
143 	 * maximum is 2^32-1 = 4294967295 = 10 characters.  If it needs to be
144 	 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
145 	 */
146 	if (!sid->identifier_authority.high_part)
147 		size += 10;
148 	else
149 		size += 14;
150 	/*
151 	 * Finally, add the sub authorities.  For each we have a "-" followed
152 	 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
153 	 */
154 	size += (1 + 10) * sid->sub_authority_count;
155 	/* We need the zero byte at the end, too. */
156 	size++;
157 	return size * sizeof(char);
158 }
159 
160 /**
161  * ntfs_sid_to_mbs - convert a SID to a multi byte string
162  * @sid:		[IN]  SID to convert
163  * @sid_str:		[OUT] string in which to return the SID (optional)
164  * @sid_str_size:	[IN]  size in bytes of @sid_str
165  *
166  * Convert the SID pointed to by @sid to its standard textual representation.
167  * @sid_str (if not NULL) needs to be able to store at least
168  * ntfs_sid_to_mbs_size() bytes.  @sid_str_size is the size in bytes of
169  * @sid_str if @sid_str is not NULL.
170  *
171  * The standard textual representation of the SID is of the form:
172  *	S-R-I-S-S...
173  * Where:
174  *    - The first "S" is the literal character 'S' identifying the following
175  *	digits as a SID.
176  *    - R is the revision level of the SID expressed as a sequence of digits
177  *	in decimal.
178  *    - I is the 48-bit identifier_authority, expressed as digits in decimal,
179  *	if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
180  *    - S... is one or more sub_authority values, expressed as digits in
181  *	decimal.
182  *
183  * If @sid_str is not NULL it will contain the converted SUID on return.  If it
184  * is NULL a string will be allocated and this will be returned.  The caller is
185  * responsible for free()ing the string in that case.
186  *
187  * On success return the converted string and on failure return NULL with errno
188  * set to the error code.
189  */
190 char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
191 {
192 	u64 u;
193 	char *s;
194 	int i, j, cnt;
195 
196 	/*
197 	 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
198 	 * check @sid, too.  8 is the minimum SID string size.
199 	 */
200 	if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
201 		errno = EINVAL;
202 		return NULL;
203 	}
204 	/* Allocate string if not provided. */
205 	if (!sid_str) {
206 		cnt = ntfs_sid_to_mbs_size(sid);
207 		if (cnt < 0)
208 			return NULL;
209 		s = ntfs_malloc(cnt);
210 		if (!s)
211 			return s;
212 		sid_str = s;
213 		/* So we know we allocated it. */
214 		sid_str_size = 0;
215 	} else {
216 		s = sid_str;
217 		cnt = sid_str_size;
218 	}
219 	/* Start with "S-R-". */
220 	i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
221 	if (i < 0 || i >= cnt)
222 		goto err_out;
223 	s += i;
224 	cnt -= i;
225 	/* Add the identifier authority. */
226 	for (u = i = 0, j = 40; i < 6; i++, j -= 8)
227 		u += (u64)sid->identifier_authority.value[i] << j;
228 	if (!sid->identifier_authority.high_part)
229 		i = snprintf(s, cnt, "%lu", (unsigned long)u);
230 	else
231 		i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
232 	if (i < 0 || i >= cnt)
233 		goto err_out;
234 	s += i;
235 	cnt -= i;
236 	/* Finally, add the sub authorities. */
237 	for (j = 0; j < sid->sub_authority_count; j++) {
238 		i = snprintf(s, cnt, "-%u", (unsigned int)
239 				le32_to_cpu(sid->sub_authority[j]));
240 		if (i < 0 || i >= cnt)
241 			goto err_out;
242 		s += i;
243 		cnt -= i;
244 	}
245 	return sid_str;
246 err_out:
247 	if (i >= cnt)
248 		i = EMSGSIZE;
249 	else
250 		i = errno;
251 	if (!sid_str_size)
252 		free(sid_str);
253 	errno = i;
254 	return NULL;
255 }
256 
257 /**
258  * ntfs_generate_guid - generatates a random current guid.
259  * @guid:	[OUT]   pointer to a GUID struct to hold the generated guid.
260  *
261  * perhaps not a very good random number generator though...
262  */
263 void ntfs_generate_guid(GUID *guid)
264 {
265 	unsigned int i;
266 	u8 *p = (u8 *)guid;
267 
268 	for (i = 0; i < sizeof(GUID); i++) {
269 		p[i] = (u8)(random() & 0xFF);
270 		if (i == 7)
271 			p[7] = (p[7] & 0x0F) | 0x40;
272 		if (i == 8)
273 			p[8] = (p[8] & 0x3F) | 0x80;
274 	}
275 }
276 
277 int ntfs_sd_add_everyone(ntfs_inode *ni)
278 {
279 	SECURITY_DESCRIPTOR_ATTR *sd;
280 	ACL *acl;
281 	ACCESS_ALLOWED_ACE *ace;
282 	SID *sid;
283 	int ret, sd_len;
284 
285 	/* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
286 	/*
287 	 * Calculate security descriptor length. We have 2 sub-authorities in
288 	 * owner and group SIDs, but structure SID contain only one, so add
289 	 * 4 bytes to every SID.
290 	 */
291 	sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
292 		sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
293 	sd = ntfs_calloc(sd_len);
294 	if (!sd)
295 		return -1;
296 
297 	sd->revision = 1;
298 	sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
299 
300 	sid = (SID *)((u8 *)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
301 	sid->revision = 1;
302 	sid->sub_authority_count = 2;
303 	sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
304 	sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
305 	sid->identifier_authority.value[5] = 5;
306 	sd->owner = cpu_to_le32((u8 *)sid - (u8 *)sd);
307 
308 	sid = (SID *)((u8 *)sid + sizeof(SID) + 4);
309 	sid->revision = 1;
310 	sid->sub_authority_count = 2;
311 	sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
312 	sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
313 	sid->identifier_authority.value[5] = 5;
314 	sd->group = cpu_to_le32((u8 *)sid - (u8 *)sd);
315 
316 	acl = (ACL *)((u8 *)sid + sizeof(SID) + 4);
317 	acl->revision = 2;
318 	acl->size = cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
319 	acl->ace_count = cpu_to_le16(1);
320 	sd->dacl = cpu_to_le32((u8 *)acl - (u8 *)sd);
321 
322 	ace = (ACCESS_ALLOWED_ACE *)((u8 *)acl + sizeof(ACL));
323 	ace->type = ACCESS_ALLOWED_ACE_TYPE;
324 	ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
325 	ace->size = cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
326 	ace->mask = cpu_to_le32(0x1f01ff); /* FIXME */
327 	ace->sid.revision = 1;
328 	ace->sid.sub_authority_count = 1;
329 	ace->sid.sub_authority[0] = 0;
330 	ace->sid.identifier_authority.value[5] = 1;
331 
332 	ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8 *)sd,
333 			    sd_len);
334 	if (ret)
335 		ntfs_log_perror("Failed to add SECURITY_DESCRIPTOR\n");
336 
337 	free(sd);
338 	return ret;
339 }
340 
341