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