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 */ 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 */ 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 */ 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 */ 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 */ 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