1/** 2 * security.c - Handling security/ACLs in NTFS. Originated from the Linux-NTFS project. 3 * 4 * Copyright (c) 2004 Anton Altaparmakov 5 * Copyright (c) 2005-2006 Szabolcs Szakacsits 6 * Copyright (c) 2006 Yura Pakhuchiy 7 * 8 * This program/include file is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as published 10 * by the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program/include file is distributed in the hope that it will be 14 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program (in the main directory of the NTFS-3G 20 * distribution in the file COPYING); if not, write to the Free Software 21 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include "config.h" 26#endif 27 28#ifdef HAVE_STDIO_H 29#include <stdio.h> 30#endif 31#ifdef HAVE_STDLIB_H 32#include <stdlib.h> 33#endif 34#ifdef HAVE_STRING_H 35#include <string.h> 36#endif 37#ifdef HAVE_ERRNO_H 38#include <errno.h> 39#endif 40 41#include "types.h" 42#include "layout.h" 43#include "attrib.h" 44#include "security.h" 45#include "misc.h" 46#include "bitmap.h" 47 48/* 49 * The zero GUID. 50 */ 51static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0), 52 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } }; 53const GUID *const zero_guid = &__zero_guid; 54 55/** 56 * ntfs_guid_is_zero - check if a GUID is zero 57 * @guid: [IN] guid to check 58 * 59 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID 60 * and FALSE otherwise. 61 */ 62BOOL ntfs_guid_is_zero(const GUID *guid) 63{ 64 return (memcmp(guid, zero_guid, sizeof(*zero_guid))); 65} 66 67/** 68 * ntfs_guid_to_mbs - convert a GUID to a multi byte string 69 * @guid: [IN] guid to convert 70 * @guid_str: [OUT] string in which to return the GUID (optional) 71 * 72 * Convert the GUID pointed to by @guid to a multi byte string of the form 73 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL) 74 * needs to be able to store at least 37 bytes. 75 * 76 * If @guid_str is not NULL it will contain the converted GUID on return. If 77 * it is NULL a string will be allocated and this will be returned. The caller 78 * is responsible for free()ing the string in that case. 79 * 80 * On success return the converted string and on failure return NULL with errno 81 * set to the error code. 82 */ 83char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str) 84{ 85 char *_guid_str; 86 int res; 87 88 if (!guid) { 89 errno = EINVAL; 90 return NULL; 91 } 92 _guid_str = guid_str; 93 if (!_guid_str) { 94 _guid_str = ntfs_malloc(37); 95 if (!_guid_str) 96 return _guid_str; 97 } 98 res = snprintf(_guid_str, 37, 99 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 100 (unsigned int)le32_to_cpu(guid->data1), 101 le16_to_cpu(guid->data2), le16_to_cpu(guid->data3), 102 guid->data4[0], guid->data4[1], 103 guid->data4[2], guid->data4[3], guid->data4[4], 104 guid->data4[5], guid->data4[6], guid->data4[7]); 105 if (res == 36) 106 return _guid_str; 107 if (!guid_str) 108 free(_guid_str); 109 errno = EINVAL; 110 return NULL; 111} 112 113/** 114 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID 115 * @sid: [IN] SID for which to determine the maximum string size 116 * 117 * Determine the maximum multi byte string size in bytes which is needed to 118 * store the standard textual representation of the SID pointed to by @sid. 119 * See ntfs_sid_to_mbs(), below. 120 * 121 * On success return the maximum number of bytes needed to store the multi byte 122 * string and on failure return -1 with errno set to the error code. 123 */ 124int ntfs_sid_to_mbs_size(const SID *sid) 125{ 126 int size, i; 127 128 if (!ntfs_sid_is_valid(sid)) { 129 errno = EINVAL; 130 return -1; 131 } 132 /* Start with "S-". */ 133 size = 2; 134 /* 135 * Add the SID_REVISION. Hopefully the compiler will optimize this 136 * away as SID_REVISION is a constant. 137 */ 138 for (i = SID_REVISION; i > 0; i /= 10) 139 size++; 140 /* Add the "-". */ 141 size++; 142 /* 143 * Add the identifier authority. If it needs to be in decimal, the 144 * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be 145 * in hexadecimal, then maximum is 0x665544332211 = 14 characters. 146 */ 147 if (!sid->identifier_authority.high_part) 148 size += 10; 149 else 150 size += 14; 151 /* 152 * Finally, add the sub authorities. For each we have a "-" followed 153 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters. 154 */ 155 size += (1 + 10) * sid->sub_authority_count; 156 /* We need the zero byte at the end, too. */ 157 size++; 158 return size * sizeof(char); 159} 160 161/** 162 * ntfs_sid_to_mbs - convert a SID to a multi byte string 163 * @sid: [IN] SID to convert 164 * @sid_str: [OUT] string in which to return the SID (optional) 165 * @sid_str_size: [IN] size in bytes of @sid_str 166 * 167 * Convert the SID pointed to by @sid to its standard textual representation. 168 * @sid_str (if not NULL) needs to be able to store at least 169 * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of 170 * @sid_str if @sid_str is not NULL. 171 * 172 * The standard textual representation of the SID is of the form: 173 * S-R-I-S-S... 174 * Where: 175 * - The first "S" is the literal character 'S' identifying the following 176 * digits as a SID. 177 * - R is the revision level of the SID expressed as a sequence of digits 178 * in decimal. 179 * - I is the 48-bit identifier_authority, expressed as digits in decimal, 180 * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32. 181 * - S... is one or more sub_authority values, expressed as digits in 182 * decimal. 183 * 184 * If @sid_str is not NULL it will contain the converted SUID on return. If it 185 * is NULL a string will be allocated and this will be returned. The caller is 186 * responsible for free()ing the string in that case. 187 * 188 * On success return the converted string and on failure return NULL with errno 189 * set to the error code. 190 */ 191char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size) 192{ 193 u64 u; 194 char *s; 195 int i, j, cnt; 196 197 /* 198 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will 199 * check @sid, too. 8 is the minimum SID string size. 200 */ 201 if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) { 202 errno = EINVAL; 203 return NULL; 204 } 205 /* Allocate string if not provided. */ 206 if (!sid_str) { 207 cnt = ntfs_sid_to_mbs_size(sid); 208 if (cnt < 0) 209 return NULL; 210 s = ntfs_malloc(cnt); 211 if (!s) 212 return s; 213 sid_str = s; 214 /* So we know we allocated it. */ 215 sid_str_size = 0; 216 } else { 217 s = sid_str; 218 cnt = sid_str_size; 219 } 220 /* Start with "S-R-". */ 221 i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision); 222 if (i < 0 || i >= cnt) 223 goto err_out; 224 s += i; 225 cnt -= i; 226 /* Add the identifier authority. */ 227 for (u = i = 0, j = 40; i < 6; i++, j -= 8) 228 u += (u64)sid->identifier_authority.value[i] << j; 229 if (!sid->identifier_authority.high_part) 230 i = snprintf(s, cnt, "%lu", (unsigned long)u); 231 else 232 i = snprintf(s, cnt, "0x%llx", (unsigned long long)u); 233 if (i < 0 || i >= cnt) 234 goto err_out; 235 s += i; 236 cnt -= i; 237 /* Finally, add the sub authorities. */ 238 for (j = 0; j < sid->sub_authority_count; j++) { 239 i = snprintf(s, cnt, "-%u", (unsigned int) 240 le32_to_cpu(sid->sub_authority[j])); 241 if (i < 0 || i >= cnt) 242 goto err_out; 243 s += i; 244 cnt -= i; 245 } 246 return sid_str; 247err_out: 248 if (i >= cnt) 249 i = EMSGSIZE; 250 else 251 i = errno; 252 if (!sid_str_size) 253 free(sid_str); 254 errno = i; 255 return NULL; 256} 257 258/** 259 * ntfs_generate_guid - generatates a random current guid. 260 * @guid: [OUT] pointer to a GUID struct to hold the generated guid. 261 * 262 * perhaps not a very good random number generator though... 263 */ 264void ntfs_generate_guid(GUID *guid) 265{ 266 unsigned int i; 267 u8 *p = (u8 *)guid; 268 269 for (i = 0; i < sizeof(GUID); i++) { 270 p[i] = (u8)(random() & 0xFF); 271 if (i == 7) 272 p[7] = (p[7] & 0x0F) | 0x40; 273 if (i == 8) 274 p[8] = (p[8] & 0x3F) | 0x80; 275 } 276} 277 278int ntfs_sd_add_everyone(ntfs_inode *ni) 279{ 280 SECURITY_DESCRIPTOR_ATTR *sd; 281 ACL *acl; 282 ACCESS_ALLOWED_ACE *ace; 283 SID *sid; 284 int ret, sd_len; 285 286 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */ 287 /* 288 * Calculate security descriptor length. We have 2 sub-authorities in 289 * owner and group SIDs, but structure SID contain only one, so add 290 * 4 bytes to every SID. 291 */ 292 sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) + 293 sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE); 294 sd = ntfs_calloc(sd_len); 295 if (!sd) 296 return -1; 297 298 sd->revision = 1; 299 sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE; 300 301 sid = (SID *)((u8 *)sd + sizeof(SECURITY_DESCRIPTOR_ATTR)); 302 sid->revision = 1; 303 sid->sub_authority_count = 2; 304 sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); 305 sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); 306 sid->identifier_authority.value[5] = 5; 307 sd->owner = cpu_to_le32((u8 *)sid - (u8 *)sd); 308 309 sid = (SID *)((u8 *)sid + sizeof(SID) + 4); 310 sid->revision = 1; 311 sid->sub_authority_count = 2; 312 sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); 313 sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); 314 sid->identifier_authority.value[5] = 5; 315 sd->group = cpu_to_le32((u8 *)sid - (u8 *)sd); 316 317 acl = (ACL *)((u8 *)sid + sizeof(SID) + 4); 318 acl->revision = 2; 319 acl->size = cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)); 320 acl->ace_count = cpu_to_le16(1); 321 sd->dacl = cpu_to_le32((u8 *)acl - (u8 *)sd); 322 323 ace = (ACCESS_ALLOWED_ACE *)((u8 *)acl + sizeof(ACL)); 324 ace->type = ACCESS_ALLOWED_ACE_TYPE; 325 ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; 326 ace->size = cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE)); 327 ace->mask = cpu_to_le32(0x1f01ff); /* FIXME */ 328 ace->sid.revision = 1; 329 ace->sid.sub_authority_count = 1; 330 ace->sid.sub_authority[0] = 0; 331 ace->sid.identifier_authority.value[5] = 1; 332 333 ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8 *)sd, 334 sd_len); 335 if (ret) 336 ntfs_log_perror("Failed to add SECURITY_DESCRIPTOR\n"); 337 338 free(sd); 339 return ret; 340} 341 342/** 343 * ntfs_security_hash - calculate the hash of a security descriptor 344 * @sd: self-relative security descriptor whose hash to calculate 345 * @length: size in bytes of the security descritor @sd 346 * 347 * Calculate the hash of the self-relative security descriptor @sd of length 348 * @length bytes. 349 * 350 * This hash is used in the $Secure system file as the primary key for the $SDH 351 * index and is also stored in the header of each security descriptor in the 352 * $SDS data stream as well as in the index data of both the $SII and $SDH 353 * indexes. In all three cases it forms part of the SDS_ENTRY_HEADER 354 * structure. 355 * 356 * Return the calculated security hash in little endian. 357 */ 358le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len) 359{ 360 const le32 *pos = (const le32 *)sd; 361 const le32 *end = pos + (len >> 2); 362 u32 hash = 0; 363 364 while (pos < end) { 365 hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3); 366 pos++; 367 } 368 return cpu_to_le32(hash); 369} 370 371