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