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