1*9663SMark.Logan@Sun.COM /**
2*9663SMark.Logan@Sun.COM  * security.c - Handling security/ACLs in NTFS.  Part of the Linux-NTFS project.
3*9663SMark.Logan@Sun.COM  *
4*9663SMark.Logan@Sun.COM  * Copyright (c) 2004 Anton Altaparmakov
5*9663SMark.Logan@Sun.COM  *
6*9663SMark.Logan@Sun.COM  * This program/include file is free software; you can redistribute it and/or
7*9663SMark.Logan@Sun.COM  * modify it under the terms of the GNU General Public License as published
8*9663SMark.Logan@Sun.COM  * by the Free Software Foundation; either version 2 of the License, or
9*9663SMark.Logan@Sun.COM  * (at your option) any later version.
10*9663SMark.Logan@Sun.COM  *
11*9663SMark.Logan@Sun.COM  * This program/include file is distributed in the hope that it will be
12*9663SMark.Logan@Sun.COM  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13*9663SMark.Logan@Sun.COM  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*9663SMark.Logan@Sun.COM  * GNU General Public License for more details.
15*9663SMark.Logan@Sun.COM  *
16*9663SMark.Logan@Sun.COM  * You should have received a copy of the GNU General Public License
17*9663SMark.Logan@Sun.COM  * along with this program (in the main directory of the Linux-NTFS
18*9663SMark.Logan@Sun.COM  * distribution in the file COPYING); if not, write to the Free Software
19*9663SMark.Logan@Sun.COM  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20*9663SMark.Logan@Sun.COM  */
21*9663SMark.Logan@Sun.COM 
22*9663SMark.Logan@Sun.COM #ifdef HAVE_CONFIG_H
23*9663SMark.Logan@Sun.COM #include "config.h"
24*9663SMark.Logan@Sun.COM #endif
25*9663SMark.Logan@Sun.COM 
26*9663SMark.Logan@Sun.COM #ifdef HAVE_STDIO_H
27*9663SMark.Logan@Sun.COM #include <stdio.h>
28*9663SMark.Logan@Sun.COM #endif
29*9663SMark.Logan@Sun.COM #ifdef HAVE_STDLIB_H
30*9663SMark.Logan@Sun.COM #include <stdlib.h>
31*9663SMark.Logan@Sun.COM #endif
32*9663SMark.Logan@Sun.COM #ifdef HAVE_STRING_H
33*9663SMark.Logan@Sun.COM #include <string.h>
34*9663SMark.Logan@Sun.COM #endif
35*9663SMark.Logan@Sun.COM #ifdef HAVE_ERRNO_H
36*9663SMark.Logan@Sun.COM #include <errno.h>
37*9663SMark.Logan@Sun.COM #endif
38*9663SMark.Logan@Sun.COM 
39*9663SMark.Logan@Sun.COM #include "types.h"
40*9663SMark.Logan@Sun.COM #include "layout.h"
41*9663SMark.Logan@Sun.COM #include "security.h"
42*9663SMark.Logan@Sun.COM 
43*9663SMark.Logan@Sun.COM /*
44*9663SMark.Logan@Sun.COM  * The zero GUID.
45*9663SMark.Logan@Sun.COM  */
46*9663SMark.Logan@Sun.COM static const GUID __zero_guid = { { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } };
47*9663SMark.Logan@Sun.COM const GUID *const zero_guid = &__zero_guid;
48*9663SMark.Logan@Sun.COM 
49*9663SMark.Logan@Sun.COM /**
50*9663SMark.Logan@Sun.COM  * ntfs_guid_is_zero - check if a GUID is zero
51*9663SMark.Logan@Sun.COM  * @guid:	[IN] guid to check
52*9663SMark.Logan@Sun.COM  *
53*9663SMark.Logan@Sun.COM  * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
54*9663SMark.Logan@Sun.COM  * and FALSE otherwise.
55*9663SMark.Logan@Sun.COM  */
56*9663SMark.Logan@Sun.COM BOOL ntfs_guid_is_zero(const GUID *guid)
57*9663SMark.Logan@Sun.COM {
58*9663SMark.Logan@Sun.COM 	return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
59*9663SMark.Logan@Sun.COM }
60*9663SMark.Logan@Sun.COM 
61*9663SMark.Logan@Sun.COM /**
62*9663SMark.Logan@Sun.COM  * ntfs_guid_to_mbs - convert a GUID to a multi byte string
63*9663SMark.Logan@Sun.COM  * @guid:	[IN]  guid to convert
64*9663SMark.Logan@Sun.COM  * @guid_str:	[OUT] string in which to return the GUID (optional)
65*9663SMark.Logan@Sun.COM  *
66*9663SMark.Logan@Sun.COM  * Convert the GUID pointed to by @guid to a multi byte string of the form
67*9663SMark.Logan@Sun.COM  * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".  Therefore, @guid_str (if not NULL)
68*9663SMark.Logan@Sun.COM  * needs to be able to store at least 37 bytes.
69*9663SMark.Logan@Sun.COM  *
70*9663SMark.Logan@Sun.COM  * If @guid_str is not NULL it will contain the converted GUID on return.  If
71*9663SMark.Logan@Sun.COM  * it is NULL a string will be allocated and this will be returned.  The caller
72*9663SMark.Logan@Sun.COM  * is responsible for free()ing the string in that case.
73*9663SMark.Logan@Sun.COM  *
74*9663SMark.Logan@Sun.COM  * On success return the converted string and on failure return NULL with errno
75*9663SMark.Logan@Sun.COM  * set to the error code.
76*9663SMark.Logan@Sun.COM  */
77*9663SMark.Logan@Sun.COM char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
78*9663SMark.Logan@Sun.COM {
79*9663SMark.Logan@Sun.COM 	char *_guid_str;
80*9663SMark.Logan@Sun.COM 	int res;
81*9663SMark.Logan@Sun.COM 
82*9663SMark.Logan@Sun.COM 	if (!guid) {
83*9663SMark.Logan@Sun.COM 		errno = EINVAL;
84*9663SMark.Logan@Sun.COM 		return NULL;
85*9663SMark.Logan@Sun.COM 	}
86*9663SMark.Logan@Sun.COM 	_guid_str = guid_str;
87*9663SMark.Logan@Sun.COM 	if (!_guid_str) {
88*9663SMark.Logan@Sun.COM 		_guid_str = ntfs_malloc(37);
89*9663SMark.Logan@Sun.COM 		if (!_guid_str)
90*9663SMark.Logan@Sun.COM 			return _guid_str;
91*9663SMark.Logan@Sun.COM 	}
92*9663SMark.Logan@Sun.COM 	res = snprintf(_guid_str, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
93*9663SMark.Logan@Sun.COM 			"%02x%02x-%02x%02x%02x%02x%02x%02x", guid->raw[0],
94*9663SMark.Logan@Sun.COM 			guid->raw[1], guid->raw[2], guid->raw[3], guid->raw[4],
95*9663SMark.Logan@Sun.COM 			guid->raw[5], guid->raw[6], guid->raw[7], guid->raw[8],
96*9663SMark.Logan@Sun.COM 			guid->raw[9], guid->raw[10], guid->raw[11],
97*9663SMark.Logan@Sun.COM 			guid->raw[12], guid->raw[13], guid->raw[14],
98*9663SMark.Logan@Sun.COM 			guid->raw[15]);
99*9663SMark.Logan@Sun.COM 	if (res == 36)
100*9663SMark.Logan@Sun.COM 		return _guid_str;
101*9663SMark.Logan@Sun.COM 	if (!guid_str)
102*9663SMark.Logan@Sun.COM 		free(_guid_str);
103*9663SMark.Logan@Sun.COM 	errno = EINVAL;
104*9663SMark.Logan@Sun.COM 	return NULL;
105*9663SMark.Logan@Sun.COM }
106*9663SMark.Logan@Sun.COM 
107*9663SMark.Logan@Sun.COM /**
108*9663SMark.Logan@Sun.COM  * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
109*9663SMark.Logan@Sun.COM  * @sid:	[IN]  SID for which to determine the maximum string size
110*9663SMark.Logan@Sun.COM  *
111*9663SMark.Logan@Sun.COM  * Determine the maximum multi byte string size in bytes which is needed to
112*9663SMark.Logan@Sun.COM  * store the standard textual representation of the SID pointed to by @sid.
113*9663SMark.Logan@Sun.COM  * See ntfs_sid_to_mbs(), below.
114*9663SMark.Logan@Sun.COM  *
115*9663SMark.Logan@Sun.COM  * On success return the maximum number of bytes needed to store the multi byte
116*9663SMark.Logan@Sun.COM  * string and on failure return -1 with errno set to the error code.
117*9663SMark.Logan@Sun.COM  */
118*9663SMark.Logan@Sun.COM int ntfs_sid_to_mbs_size(const SID *sid)
119*9663SMark.Logan@Sun.COM {
120*9663SMark.Logan@Sun.COM 	int size, i;
121*9663SMark.Logan@Sun.COM 
122*9663SMark.Logan@Sun.COM 	if (!ntfs_sid_is_valid(sid)) {
123*9663SMark.Logan@Sun.COM 		errno = EINVAL;
124*9663SMark.Logan@Sun.COM 		return -1;
125*9663SMark.Logan@Sun.COM 	}
126*9663SMark.Logan@Sun.COM 	/* Start with "S-". */
127*9663SMark.Logan@Sun.COM 	size = 2;
128*9663SMark.Logan@Sun.COM 	/*
129*9663SMark.Logan@Sun.COM 	 * Add the SID_REVISION.  Hopefully the compiler will optimize this
130*9663SMark.Logan@Sun.COM 	 * away as SID_REVISION is a constant.
131*9663SMark.Logan@Sun.COM 	 */
132*9663SMark.Logan@Sun.COM 	for (i = SID_REVISION; i > 0; i /= 10)
133*9663SMark.Logan@Sun.COM 		size++;
134*9663SMark.Logan@Sun.COM 	/* Add the "-". */
135*9663SMark.Logan@Sun.COM 	size++;
136*9663SMark.Logan@Sun.COM 	/*
137*9663SMark.Logan@Sun.COM 	 * Add the identifier authority.  If it needs to be in decimal, the
138*9663SMark.Logan@Sun.COM 	 * maximum is 2^32-1 = 4294967295 = 10 characters.  If it needs to be
139*9663SMark.Logan@Sun.COM 	 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
140*9663SMark.Logan@Sun.COM 	 */
141*9663SMark.Logan@Sun.COM 	if (!sid->identifier_authority.s.high_part)
142*9663SMark.Logan@Sun.COM 		size += 10;
143*9663SMark.Logan@Sun.COM 	else
144*9663SMark.Logan@Sun.COM 		size += 14;
145*9663SMark.Logan@Sun.COM 	/*
146*9663SMark.Logan@Sun.COM 	 * Finally, add the sub authorities.  For each we have a "-" followed
147*9663SMark.Logan@Sun.COM 	 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
148*9663SMark.Logan@Sun.COM 	 */
149*9663SMark.Logan@Sun.COM 	size += (1 + 10) * sid->sub_authority_count;
150*9663SMark.Logan@Sun.COM 	/* We need the zero byte at the end, too. */
151*9663SMark.Logan@Sun.COM 	size++;
152*9663SMark.Logan@Sun.COM 	return size * sizeof(char);
153*9663SMark.Logan@Sun.COM }
154*9663SMark.Logan@Sun.COM 
155*9663SMark.Logan@Sun.COM /**
156*9663SMark.Logan@Sun.COM  * ntfs_sid_to_mbs - convert a SID to a multi byte string
157*9663SMark.Logan@Sun.COM  * @sid:		[IN]  SID to convert
158*9663SMark.Logan@Sun.COM  * @sid_str:		[OUT] string in which to return the SID (optional)
159*9663SMark.Logan@Sun.COM  * @sid_str_size:	[IN]  size in bytes of @sid_str
160*9663SMark.Logan@Sun.COM  *
161*9663SMark.Logan@Sun.COM  * Convert the SID pointed to by @sid to its standard textual representation.
162*9663SMark.Logan@Sun.COM  * @sid_str (if not NULL) needs to be able to store at least
163*9663SMark.Logan@Sun.COM  * ntfs_sid_to_mbs_size() bytes.  @sid_str_size is the size in bytes of
164*9663SMark.Logan@Sun.COM  * @sid_str if @sid_str is not NULL.
165*9663SMark.Logan@Sun.COM  *
166*9663SMark.Logan@Sun.COM  * The standard textual representation of the SID is of the form:
167*9663SMark.Logan@Sun.COM  *	S-R-I-S-S...
168*9663SMark.Logan@Sun.COM  * Where:
169*9663SMark.Logan@Sun.COM  *    - The first "S" is the literal character 'S' identifying the following
170*9663SMark.Logan@Sun.COM  *	digits as a SID.
171*9663SMark.Logan@Sun.COM  *    - R is the revision level of the SID expressed as a sequence of digits
172*9663SMark.Logan@Sun.COM  *	in decimal.
173*9663SMark.Logan@Sun.COM  *    - I is the 48-bit identifier_authority, expressed as digits in decimal,
174*9663SMark.Logan@Sun.COM  *	if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
175*9663SMark.Logan@Sun.COM  *    - S... is one or more sub_authority values, expressed as digits in
176*9663SMark.Logan@Sun.COM  *	decimal.
177*9663SMark.Logan@Sun.COM  *
178*9663SMark.Logan@Sun.COM  * If @sid_str is not NULL it will contain the converted SUID on return.  If it
179*9663SMark.Logan@Sun.COM  * is NULL a string will be allocated and this will be returned.  The caller is
180*9663SMark.Logan@Sun.COM  * responsible for free()ing the string in that case.
181*9663SMark.Logan@Sun.COM  *
182*9663SMark.Logan@Sun.COM  * On success return the converted string and on failure return NULL with errno
183*9663SMark.Logan@Sun.COM  * set to the error code.
184*9663SMark.Logan@Sun.COM  */
185*9663SMark.Logan@Sun.COM char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
186*9663SMark.Logan@Sun.COM {
187*9663SMark.Logan@Sun.COM 	u64 u;
188*9663SMark.Logan@Sun.COM 	char *s;
189*9663SMark.Logan@Sun.COM 	int i, j, cnt;
190*9663SMark.Logan@Sun.COM 
191*9663SMark.Logan@Sun.COM 	/*
192*9663SMark.Logan@Sun.COM 	 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
193*9663SMark.Logan@Sun.COM 	 * check @sid, too.  8 is the minimum SID string size.
194*9663SMark.Logan@Sun.COM 	 */
195*9663SMark.Logan@Sun.COM 	if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
196*9663SMark.Logan@Sun.COM 		errno = EINVAL;
197*9663SMark.Logan@Sun.COM 		return NULL;
198*9663SMark.Logan@Sun.COM 	}
199*9663SMark.Logan@Sun.COM 	/* Allocate string if not provided. */
200*9663SMark.Logan@Sun.COM 	if (!sid_str) {
201*9663SMark.Logan@Sun.COM 		cnt = ntfs_sid_to_mbs_size(sid);
202*9663SMark.Logan@Sun.COM 		if (cnt < 0)
203*9663SMark.Logan@Sun.COM 			return NULL;
204*9663SMark.Logan@Sun.COM 		s = ntfs_malloc(cnt);
205*9663SMark.Logan@Sun.COM 		if (!s)
206*9663SMark.Logan@Sun.COM 			return s;
207*9663SMark.Logan@Sun.COM 		sid_str = s;
208*9663SMark.Logan@Sun.COM 		/* So we know we allocated it. */
209*9663SMark.Logan@Sun.COM 		sid_str_size = 0;
210*9663SMark.Logan@Sun.COM 	} else {
211*9663SMark.Logan@Sun.COM 		s = sid_str;
212*9663SMark.Logan@Sun.COM 		cnt = sid_str_size;
213*9663SMark.Logan@Sun.COM 	}
214*9663SMark.Logan@Sun.COM 	/* Start with "S-R-". */
215*9663SMark.Logan@Sun.COM 	i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
216*9663SMark.Logan@Sun.COM 	if (i < 0 || i >= cnt)
217*9663SMark.Logan@Sun.COM 		goto err_out;
218*9663SMark.Logan@Sun.COM 	s += i;
219*9663SMark.Logan@Sun.COM 	cnt -= i;
220*9663SMark.Logan@Sun.COM 	/* Add the identifier authority. */
221*9663SMark.Logan@Sun.COM 	for (u = i = 0, j = 40; i < 6; i++, j -= 8)
222*9663SMark.Logan@Sun.COM 		u += (u64)sid->identifier_authority.value[i] << j;
223*9663SMark.Logan@Sun.COM 	if (!sid->identifier_authority.s.high_part)
224*9663SMark.Logan@Sun.COM 		i = snprintf(s, cnt, "%lu", (unsigned long)u);
225*9663SMark.Logan@Sun.COM 	else
226*9663SMark.Logan@Sun.COM 		i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
227*9663SMark.Logan@Sun.COM 	if (i < 0 || i >= cnt)
228*9663SMark.Logan@Sun.COM 		goto err_out;
229*9663SMark.Logan@Sun.COM 	s += i;
230*9663SMark.Logan@Sun.COM 	cnt -= i;
231*9663SMark.Logan@Sun.COM 	/* Finally, add the sub authorities. */
232*9663SMark.Logan@Sun.COM 	for (j = 0; j < sid->sub_authority_count; j++) {
233*9663SMark.Logan@Sun.COM 		i = snprintf(s, cnt, "-%u", (unsigned int)
234*9663SMark.Logan@Sun.COM 				le32_to_cpu(sid->sub_authority[j]));
235*9663SMark.Logan@Sun.COM 		if (i < 0 || i >= cnt)
236*9663SMark.Logan@Sun.COM 			goto err_out;
237*9663SMark.Logan@Sun.COM 		s += i;
238*9663SMark.Logan@Sun.COM 		cnt -= i;
239*9663SMark.Logan@Sun.COM 	}
240*9663SMark.Logan@Sun.COM 	return sid_str;
241*9663SMark.Logan@Sun.COM err_out:
242*9663SMark.Logan@Sun.COM 	if (i >= cnt)
243*9663SMark.Logan@Sun.COM 		i = EMSGSIZE;
244*9663SMark.Logan@Sun.COM 	else
245*9663SMark.Logan@Sun.COM 		i = errno;
246*9663SMark.Logan@Sun.COM 	if (!sid_str_size)
247*9663SMark.Logan@Sun.COM 		free(sid_str);
248*9663SMark.Logan@Sun.COM 	errno = i;
249*9663SMark.Logan@Sun.COM 	return NULL;
250*9663SMark.Logan@Sun.COM }
251*9663SMark.Logan@Sun.COM 
252*9663SMark.Logan@Sun.COM /**
253*9663SMark.Logan@Sun.COM  * ntfs_generate_guid - generatates a random current guid.
254*9663SMark.Logan@Sun.COM  * @guid:	[OUT]   pointer to a GUID struct to hold the generated guid.
255*9663SMark.Logan@Sun.COM  *
256*9663SMark.Logan@Sun.COM  * perhaps not a very good random number generator though...
257*9663SMark.Logan@Sun.COM  */
258*9663SMark.Logan@Sun.COM void ntfs_generate_guid(GUID *guid)
259*9663SMark.Logan@Sun.COM {
260*9663SMark.Logan@Sun.COM 	unsigned int i;
261*9663SMark.Logan@Sun.COM 	u8 *p = (u8 *)guid;
262*9663SMark.Logan@Sun.COM 
263*9663SMark.Logan@Sun.COM 	for (i = 0; i < sizeof(GUID); i++) {
264*9663SMark.Logan@Sun.COM 		p[i] = (u8)(random() & 0xFF);
265*9663SMark.Logan@Sun.COM 		if (i == 7)
266*9663SMark.Logan@Sun.COM 			p[7] = (p[7] & 0x0F) | 0x40;
267*9663SMark.Logan@Sun.COM 		if (i == 8)
268*9663SMark.Logan@Sun.COM 			p[8] = (p[8] & 0x3F) | 0x80;
269*9663SMark.Logan@Sun.COM 	}
270*9663SMark.Logan@Sun.COM }
271*9663SMark.Logan@Sun.COM 
272