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 47 /* 48 * The zero GUID. 49 */ 50 static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0), 51 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } }; 52 const GUID *const zero_guid = &__zero_guid; 53 54 /** 55 * ntfs_guid_is_zero - check if a GUID is zero 56 * @guid: [IN] guid to check 57 * 58 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID 59 * and FALSE otherwise. 60 */ 61 BOOL ntfs_guid_is_zero(const GUID *guid) 62 { 63 return (memcmp(guid, zero_guid, sizeof(*zero_guid))); 64 } 65 66 /** 67 * ntfs_guid_to_mbs - convert a GUID to a multi byte string 68 * @guid: [IN] guid to convert 69 * @guid_str: [OUT] string in which to return the GUID (optional) 70 * 71 * Convert the GUID pointed to by @guid to a multi byte string of the form 72 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL) 73 * needs to be able to store at least 37 bytes. 74 * 75 * If @guid_str is not NULL it will contain the converted GUID on return. If 76 * it is NULL a string will be allocated and this will be returned. The caller 77 * is responsible for free()ing the string in that case. 78 * 79 * On success return the converted string and on failure return NULL with errno 80 * set to the error code. 81 */ 82 char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str) 83 { 84 char *_guid_str; 85 int res; 86 87 if (!guid) { 88 errno = EINVAL; 89 return NULL; 90 } 91 _guid_str = guid_str; 92 if (!_guid_str) { 93 _guid_str = ntfs_malloc(37); 94 if (!_guid_str) 95 return _guid_str; 96 } 97 res = snprintf(_guid_str, 37, 98 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 99 (unsigned int)le32_to_cpu(guid->data1), 100 le16_to_cpu(guid->data2), le16_to_cpu(guid->data3), 101 guid->data4[0], guid->data4[1], 102 guid->data4[2], guid->data4[3], guid->data4[4], 103 guid->data4[5], guid->data4[6], guid->data4[7]); 104 if (res == 36) 105 return _guid_str; 106 if (!guid_str) 107 free(_guid_str); 108 errno = EINVAL; 109 return NULL; 110 } 111 112 /** 113 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID 114 * @sid: [IN] SID for which to determine the maximum string size 115 * 116 * Determine the maximum multi byte string size in bytes which is needed to 117 * store the standard textual representation of the SID pointed to by @sid. 118 * See ntfs_sid_to_mbs(), below. 119 * 120 * On success return the maximum number of bytes needed to store the multi byte 121 * string and on failure return -1 with errno set to the error code. 122 */ 123 int ntfs_sid_to_mbs_size(const SID *sid) 124 { 125 int size, i; 126 127 if (!ntfs_sid_is_valid(sid)) { 128 errno = EINVAL; 129 return -1; 130 } 131 /* Start with "S-". */ 132 size = 2; 133 /* 134 * Add the SID_REVISION. Hopefully the compiler will optimize this 135 * away as SID_REVISION is a constant. 136 */ 137 for (i = SID_REVISION; i > 0; i /= 10) 138 size++; 139 /* Add the "-". */ 140 size++; 141 /* 142 * Add the identifier authority. If it needs to be in decimal, the 143 * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be 144 * in hexadecimal, then maximum is 0x665544332211 = 14 characters. 145 */ 146 if (!sid->identifier_authority.high_part) 147 size += 10; 148 else 149 size += 14; 150 /* 151 * Finally, add the sub authorities. For each we have a "-" followed 152 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters. 153 */ 154 size += (1 + 10) * sid->sub_authority_count; 155 /* We need the zero byte at the end, too. */ 156 size++; 157 return size * sizeof(char); 158 } 159 160 /** 161 * ntfs_sid_to_mbs - convert a SID to a multi byte string 162 * @sid: [IN] SID to convert 163 * @sid_str: [OUT] string in which to return the SID (optional) 164 * @sid_str_size: [IN] size in bytes of @sid_str 165 * 166 * Convert the SID pointed to by @sid to its standard textual representation. 167 * @sid_str (if not NULL) needs to be able to store at least 168 * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of 169 * @sid_str if @sid_str is not NULL. 170 * 171 * The standard textual representation of the SID is of the form: 172 * S-R-I-S-S... 173 * Where: 174 * - The first "S" is the literal character 'S' identifying the following 175 * digits as a SID. 176 * - R is the revision level of the SID expressed as a sequence of digits 177 * in decimal. 178 * - I is the 48-bit identifier_authority, expressed as digits in decimal, 179 * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32. 180 * - S... is one or more sub_authority values, expressed as digits in 181 * decimal. 182 * 183 * If @sid_str is not NULL it will contain the converted SUID on return. If it 184 * is NULL a string will be allocated and this will be returned. The caller is 185 * responsible for free()ing the string in that case. 186 * 187 * On success return the converted string and on failure return NULL with errno 188 * set to the error code. 189 */ 190 char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size) 191 { 192 u64 u; 193 char *s; 194 int i, j, cnt; 195 196 /* 197 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will 198 * check @sid, too. 8 is the minimum SID string size. 199 */ 200 if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) { 201 errno = EINVAL; 202 return NULL; 203 } 204 /* Allocate string if not provided. */ 205 if (!sid_str) { 206 cnt = ntfs_sid_to_mbs_size(sid); 207 if (cnt < 0) 208 return NULL; 209 s = ntfs_malloc(cnt); 210 if (!s) 211 return s; 212 sid_str = s; 213 /* So we know we allocated it. */ 214 sid_str_size = 0; 215 } else { 216 s = sid_str; 217 cnt = sid_str_size; 218 } 219 /* Start with "S-R-". */ 220 i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision); 221 if (i < 0 || i >= cnt) 222 goto err_out; 223 s += i; 224 cnt -= i; 225 /* Add the identifier authority. */ 226 for (u = i = 0, j = 40; i < 6; i++, j -= 8) 227 u += (u64)sid->identifier_authority.value[i] << j; 228 if (!sid->identifier_authority.high_part) 229 i = snprintf(s, cnt, "%lu", (unsigned long)u); 230 else 231 i = snprintf(s, cnt, "0x%llx", (unsigned long long)u); 232 if (i < 0 || i >= cnt) 233 goto err_out; 234 s += i; 235 cnt -= i; 236 /* Finally, add the sub authorities. */ 237 for (j = 0; j < sid->sub_authority_count; j++) { 238 i = snprintf(s, cnt, "-%u", (unsigned int) 239 le32_to_cpu(sid->sub_authority[j])); 240 if (i < 0 || i >= cnt) 241 goto err_out; 242 s += i; 243 cnt -= i; 244 } 245 return sid_str; 246 err_out: 247 if (i >= cnt) 248 i = EMSGSIZE; 249 else 250 i = errno; 251 if (!sid_str_size) 252 free(sid_str); 253 errno = i; 254 return NULL; 255 } 256 257 /** 258 * ntfs_generate_guid - generatates a random current guid. 259 * @guid: [OUT] pointer to a GUID struct to hold the generated guid. 260 * 261 * perhaps not a very good random number generator though... 262 */ 263 void ntfs_generate_guid(GUID *guid) 264 { 265 unsigned int i; 266 u8 *p = (u8 *)guid; 267 268 for (i = 0; i < sizeof(GUID); i++) { 269 p[i] = (u8)(random() & 0xFF); 270 if (i == 7) 271 p[7] = (p[7] & 0x0F) | 0x40; 272 if (i == 8) 273 p[8] = (p[8] & 0x3F) | 0x80; 274 } 275 } 276 277 int ntfs_sd_add_everyone(ntfs_inode *ni) 278 { 279 SECURITY_DESCRIPTOR_ATTR *sd; 280 ACL *acl; 281 ACCESS_ALLOWED_ACE *ace; 282 SID *sid; 283 int ret, sd_len; 284 285 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */ 286 /* 287 * Calculate security descriptor length. We have 2 sub-authorities in 288 * owner and group SIDs, but structure SID contain only one, so add 289 * 4 bytes to every SID. 290 */ 291 sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) + 292 sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE); 293 sd = ntfs_calloc(sd_len); 294 if (!sd) 295 return -1; 296 297 sd->revision = 1; 298 sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE; 299 300 sid = (SID *)((u8 *)sd + sizeof(SECURITY_DESCRIPTOR_ATTR)); 301 sid->revision = 1; 302 sid->sub_authority_count = 2; 303 sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); 304 sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); 305 sid->identifier_authority.value[5] = 5; 306 sd->owner = cpu_to_le32((u8 *)sid - (u8 *)sd); 307 308 sid = (SID *)((u8 *)sid + sizeof(SID) + 4); 309 sid->revision = 1; 310 sid->sub_authority_count = 2; 311 sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); 312 sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); 313 sid->identifier_authority.value[5] = 5; 314 sd->group = cpu_to_le32((u8 *)sid - (u8 *)sd); 315 316 acl = (ACL *)((u8 *)sid + sizeof(SID) + 4); 317 acl->revision = 2; 318 acl->size = cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)); 319 acl->ace_count = cpu_to_le16(1); 320 sd->dacl = cpu_to_le32((u8 *)acl - (u8 *)sd); 321 322 ace = (ACCESS_ALLOWED_ACE *)((u8 *)acl + sizeof(ACL)); 323 ace->type = ACCESS_ALLOWED_ACE_TYPE; 324 ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; 325 ace->size = cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE)); 326 ace->mask = cpu_to_le32(0x1f01ff); /* FIXME */ 327 ace->sid.revision = 1; 328 ace->sid.sub_authority_count = 1; 329 ace->sid.sub_authority[0] = 0; 330 ace->sid.identifier_authority.value[5] = 1; 331 332 ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8 *)sd, 333 sd_len); 334 if (ret) 335 ntfs_log_perror("Failed to add SECURITY_DESCRIPTOR\n"); 336 337 free(sd); 338 return ret; 339 } 340 341