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 * Copyright (c) 2007-2012 Jean-Pierre Andre 8 * 9 * This program/include file is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as published 11 * by the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program/include file is distributed in the hope that it will be 15 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program (in the main directory of the NTFS-3G 21 * distribution in the file COPYING); if not, write to the Free Software 22 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24 25 #ifdef HAVE_CONFIG_H 26 #include "config.h" 27 #endif 28 29 #ifdef HAVE_STDIO_H 30 #include <stdio.h> 31 #endif 32 #ifdef HAVE_STDLIB_H 33 #include <stdlib.h> 34 #endif 35 #ifdef HAVE_STRING_H 36 #include <string.h> 37 #endif 38 #ifdef HAVE_ERRNO_H 39 #include <errno.h> 40 #endif 41 #ifdef HAVE_FCNTL_H 42 #include <fcntl.h> 43 #endif 44 #ifdef HAVE_SETXATTR 45 #include <sys/xattr.h> 46 #endif 47 #ifdef HAVE_SYS_STAT_H 48 #include <sys/stat.h> 49 #endif 50 51 #include <unistd.h> 52 #include <pwd.h> 53 #include <grp.h> 54 55 #include "compat.h" 56 #include "param.h" 57 #include "types.h" 58 #include "layout.h" 59 #include "attrib.h" 60 #include "index.h" 61 #include "dir.h" 62 #include "bitmap.h" 63 #include "security.h" 64 #include "acls.h" 65 #include "cache.h" 66 #include "misc.h" 67 68 #ifdef __HAIKU__ 69 #define getgrgid(a) NULL 70 #define getpwuid(a) NULL 71 #endif 72 73 74 /* 75 * JPA NTFS constants or structs 76 * should be moved to layout.h 77 */ 78 79 #define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */ 80 #define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */ 81 #define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */ 82 #define FIRST_SECURITY_ID 0x100 /* Lowest security id */ 83 84 /* Mask for attributes which can be forced */ 85 #define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY \ 86 | FILE_ATTR_HIDDEN \ 87 | FILE_ATTR_SYSTEM \ 88 | FILE_ATTR_ARCHIVE \ 89 | FILE_ATTR_TEMPORARY \ 90 | FILE_ATTR_OFFLINE \ 91 | FILE_ATTR_NOT_CONTENT_INDEXED ) 92 93 struct SII { /* this is an image of an $SII index entry */ 94 le16 offs; 95 le16 size; 96 le32 fill1; 97 le16 indexsz; 98 le16 indexksz; 99 le16 flags; 100 le16 fill2; 101 le32 keysecurid; 102 103 /* did not find official description for the following */ 104 le32 hash; 105 le32 securid; 106 le32 dataoffsl; /* documented as badly aligned */ 107 le32 dataoffsh; 108 le32 datasize; 109 } ; 110 111 struct SDH { /* this is an image of an $SDH index entry */ 112 le16 offs; 113 le16 size; 114 le32 fill1; 115 le16 indexsz; 116 le16 indexksz; 117 le16 flags; 118 le16 fill2; 119 le32 keyhash; 120 le32 keysecurid; 121 122 /* did not find official description for the following */ 123 le32 hash; 124 le32 securid; 125 le32 dataoffsl; 126 le32 dataoffsh; 127 le32 datasize; 128 le32 fill3; 129 } ; 130 131 /* 132 * A few useful constants 133 */ 134 135 static ntfschar sii_stream[] = { const_cpu_to_le16('$'), 136 const_cpu_to_le16('S'), 137 const_cpu_to_le16('I'), 138 const_cpu_to_le16('I'), 139 const_cpu_to_le16(0) }; 140 static ntfschar sdh_stream[] = { const_cpu_to_le16('$'), 141 const_cpu_to_le16('S'), 142 const_cpu_to_le16('D'), 143 const_cpu_to_le16('H'), 144 const_cpu_to_le16(0) }; 145 146 /* 147 * null SID (S-1-0-0) 148 */ 149 150 extern const SID *nullsid; 151 152 /* 153 * The zero GUID. 154 */ 155 156 static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0), 157 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } }; 158 static const GUID *const zero_guid = &__zero_guid; 159 160 /** 161 * ntfs_guid_is_zero - check if a GUID is zero 162 * @guid: [IN] guid to check 163 * 164 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID 165 * and FALSE otherwise. 166 */ 167 BOOL ntfs_guid_is_zero(const GUID *guid) 168 { 169 return (memcmp(guid, zero_guid, sizeof(*zero_guid))); 170 } 171 172 /** 173 * ntfs_guid_to_mbs - convert a GUID to a multi byte string 174 * @guid: [IN] guid to convert 175 * @guid_str: [OUT] string in which to return the GUID (optional) 176 * 177 * Convert the GUID pointed to by @guid to a multi byte string of the form 178 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL) 179 * needs to be able to store at least 37 bytes. 180 * 181 * If @guid_str is not NULL it will contain the converted GUID on return. If 182 * it is NULL a string will be allocated and this will be returned. The caller 183 * is responsible for free()ing the string in that case. 184 * 185 * On success return the converted string and on failure return NULL with errno 186 * set to the error code. 187 */ 188 char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str) 189 { 190 char *_guid_str; 191 int res; 192 193 if (!guid) { 194 errno = EINVAL; 195 return NULL; 196 } 197 _guid_str = guid_str; 198 if (!_guid_str) { 199 _guid_str = (char*)ntfs_malloc(37); 200 if (!_guid_str) 201 return _guid_str; 202 } 203 res = snprintf(_guid_str, 37, 204 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 205 (unsigned int)le32_to_cpu(guid->data1), 206 le16_to_cpu(guid->data2), le16_to_cpu(guid->data3), 207 guid->data4[0], guid->data4[1], 208 guid->data4[2], guid->data4[3], guid->data4[4], 209 guid->data4[5], guid->data4[6], guid->data4[7]); 210 if (res == 36) 211 return _guid_str; 212 if (!guid_str) 213 free(_guid_str); 214 errno = EINVAL; 215 return NULL; 216 } 217 218 /** 219 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID 220 * @sid: [IN] SID for which to determine the maximum string size 221 * 222 * Determine the maximum multi byte string size in bytes which is needed to 223 * store the standard textual representation of the SID pointed to by @sid. 224 * See ntfs_sid_to_mbs(), below. 225 * 226 * On success return the maximum number of bytes needed to store the multi byte 227 * string and on failure return -1 with errno set to the error code. 228 */ 229 int ntfs_sid_to_mbs_size(const SID *sid) 230 { 231 int size, i; 232 233 if (!ntfs_sid_is_valid(sid)) { 234 errno = EINVAL; 235 return -1; 236 } 237 /* Start with "S-". */ 238 size = 2; 239 /* 240 * Add the SID_REVISION. Hopefully the compiler will optimize this 241 * away as SID_REVISION is a constant. 242 */ 243 for (i = SID_REVISION; i > 0; i /= 10) 244 size++; 245 /* Add the "-". */ 246 size++; 247 /* 248 * Add the identifier authority. If it needs to be in decimal, the 249 * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be 250 * in hexadecimal, then maximum is 0x665544332211 = 14 characters. 251 */ 252 if (!sid->identifier_authority.high_part) 253 size += 10; 254 else 255 size += 14; 256 /* 257 * Finally, add the sub authorities. For each we have a "-" followed 258 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters. 259 */ 260 size += (1 + 10) * sid->sub_authority_count; 261 /* We need the zero byte at the end, too. */ 262 size++; 263 return size * sizeof(char); 264 } 265 266 /** 267 * ntfs_sid_to_mbs - convert a SID to a multi byte string 268 * @sid: [IN] SID to convert 269 * @sid_str: [OUT] string in which to return the SID (optional) 270 * @sid_str_size: [IN] size in bytes of @sid_str 271 * 272 * Convert the SID pointed to by @sid to its standard textual representation. 273 * @sid_str (if not NULL) needs to be able to store at least 274 * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of 275 * @sid_str if @sid_str is not NULL. 276 * 277 * The standard textual representation of the SID is of the form: 278 * S-R-I-S-S... 279 * Where: 280 * - The first "S" is the literal character 'S' identifying the following 281 * digits as a SID. 282 * - R is the revision level of the SID expressed as a sequence of digits 283 * in decimal. 284 * - I is the 48-bit identifier_authority, expressed as digits in decimal, 285 * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32. 286 * - S... is one or more sub_authority values, expressed as digits in 287 * decimal. 288 * 289 * If @sid_str is not NULL it will contain the converted SUID on return. If it 290 * is NULL a string will be allocated and this will be returned. The caller is 291 * responsible for free()ing the string in that case. 292 * 293 * On success return the converted string and on failure return NULL with errno 294 * set to the error code. 295 */ 296 char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size) 297 { 298 u64 u; 299 le32 leauth; 300 char *s; 301 int i, j, cnt; 302 303 /* 304 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will 305 * check @sid, too. 8 is the minimum SID string size. 306 */ 307 if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) { 308 errno = EINVAL; 309 return NULL; 310 } 311 /* Allocate string if not provided. */ 312 if (!sid_str) { 313 cnt = ntfs_sid_to_mbs_size(sid); 314 if (cnt < 0) 315 return NULL; 316 s = (char*)ntfs_malloc(cnt); 317 if (!s) 318 return s; 319 sid_str = s; 320 /* So we know we allocated it. */ 321 sid_str_size = 0; 322 } else { 323 s = sid_str; 324 cnt = sid_str_size; 325 } 326 /* Start with "S-R-". */ 327 i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision); 328 if (i < 0 || i >= cnt) 329 goto err_out; 330 s += i; 331 cnt -= i; 332 /* Add the identifier authority. */ 333 for (u = i = 0, j = 40; i < 6; i++, j -= 8) 334 u += (u64)sid->identifier_authority.value[i] << j; 335 if (!sid->identifier_authority.high_part) 336 i = snprintf(s, cnt, "%lu", (unsigned long)u); 337 else 338 i = snprintf(s, cnt, "0x%llx", (unsigned long long)u); 339 if (i < 0 || i >= cnt) 340 goto err_out; 341 s += i; 342 cnt -= i; 343 /* Finally, add the sub authorities. */ 344 for (j = 0; j < sid->sub_authority_count; j++) { 345 leauth = sid->sub_authority[j]; 346 i = snprintf(s, cnt, "-%u", (unsigned int) 347 le32_to_cpu(leauth)); 348 if (i < 0 || i >= cnt) 349 goto err_out; 350 s += i; 351 cnt -= i; 352 } 353 return sid_str; 354 err_out: 355 if (i >= cnt) 356 i = EMSGSIZE; 357 else 358 i = errno; 359 if (!sid_str_size) 360 free(sid_str); 361 errno = i; 362 return NULL; 363 } 364 365 /** 366 * ntfs_generate_guid - generatates a random current guid. 367 * @guid: [OUT] pointer to a GUID struct to hold the generated guid. 368 * 369 * perhaps not a very good random number generator though... 370 */ 371 void ntfs_generate_guid(GUID *guid) 372 { 373 unsigned int i; 374 u8 *p = (u8 *)guid; 375 376 /* this is called at most once from mkntfs */ 377 srandom(time((time_t*)NULL) ^ (getpid() << 16)); 378 for (i = 0; i < sizeof(GUID); i++) { 379 p[i] = (u8)(random() & 0xFF); 380 if (i == 7) 381 p[7] = (p[7] & 0x0F) | 0x40; 382 if (i == 8) 383 p[8] = (p[8] & 0x3F) | 0x80; 384 } 385 } 386 387 /** 388 * ntfs_security_hash - calculate the hash of a security descriptor 389 * @sd: self-relative security descriptor whose hash to calculate 390 * @length: size in bytes of the security descritor @sd 391 * 392 * Calculate the hash of the self-relative security descriptor @sd of length 393 * @length bytes. 394 * 395 * This hash is used in the $Secure system file as the primary key for the $SDH 396 * index and is also stored in the header of each security descriptor in the 397 * $SDS data stream as well as in the index data of both the $SII and $SDH 398 * indexes. In all three cases it forms part of the SDS_ENTRY_HEADER 399 * structure. 400 * 401 * Return the calculated security hash in little endian. 402 */ 403 le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len) 404 { 405 const le32 *pos = (const le32*)sd; 406 const le32 *end = pos + (len >> 2); 407 u32 hash = 0; 408 409 while (pos < end) { 410 hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3); 411 pos++; 412 } 413 return cpu_to_le32(hash); 414 } 415 416 /* 417 * Get the first entry of current index block 418 * cut and pasted form ntfs_ie_get_first() in index.c 419 */ 420 421 static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih) 422 { 423 return (INDEX_ENTRY*)((u8*)ih + le32_to_cpu(ih->entries_offset)); 424 } 425 426 /* 427 * Stuff a 256KB block into $SDS before writing descriptors 428 * into the block. 429 * 430 * This prevents $SDS from being automatically declared as sparse 431 * when the second copy of the first security descriptor is written 432 * 256KB further ahead. 433 * 434 * Having $SDS declared as a sparse file is not wrong by itself 435 * and chkdsk leaves it as a sparse file. It does however complain 436 * and add a sparse flag (0x0200) into field file_attributes of 437 * STANDARD_INFORMATION of $Secure. This probably means that a 438 * sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse 439 * files (FILE_ATTR_SPARSE_FILE). 440 * 441 * Windows normally does not convert to sparse attribute or sparse 442 * file. Stuffing is just a way to get to the same result. 443 */ 444 445 static int entersecurity_stuff(ntfs_volume *vol, off_t offs) 446 { 447 int res; 448 int written; 449 unsigned long total; 450 char *stuff; 451 452 res = 0; 453 total = 0; 454 stuff = (char*)ntfs_malloc(STUFFSZ); 455 if (stuff) { 456 memset(stuff, 0, STUFFSZ); 457 do { 458 written = ntfs_attr_data_write(vol->secure_ni, 459 STREAM_SDS, 4, stuff, STUFFSZ, offs); 460 if (written == STUFFSZ) { 461 total += STUFFSZ; 462 offs += STUFFSZ; 463 } else { 464 errno = ENOSPC; 465 res = -1; 466 } 467 } while (!res && (total < ALIGN_SDS_BLOCK)); 468 free(stuff); 469 } else { 470 errno = ENOMEM; 471 res = -1; 472 } 473 return (res); 474 } 475 476 /* 477 * Enter a new security descriptor into $Secure (data only) 478 * it has to be written twice with an offset of 256KB 479 * 480 * Should only be called by entersecurityattr() to ensure consistency 481 * 482 * Returns zero if sucessful 483 */ 484 485 static int entersecurity_data(ntfs_volume *vol, 486 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz, 487 le32 hash, le32 keyid, off_t offs, int gap) 488 { 489 int res; 490 int written1; 491 int written2; 492 char *fullattr; 493 int fullsz; 494 SECURITY_DESCRIPTOR_HEADER *phsds; 495 496 res = -1; 497 fullsz = attrsz + gap + sizeof(SECURITY_DESCRIPTOR_HEADER); 498 fullattr = (char*)ntfs_malloc(fullsz); 499 if (fullattr) { 500 /* 501 * Clear the gap from previous descriptor 502 * this could be useful for appending the second 503 * copy to the end of file. When creating a new 504 * 256K block, the gap is cleared while writing 505 * the first copy 506 */ 507 if (gap) 508 memset(fullattr,0,gap); 509 memcpy(&fullattr[gap + sizeof(SECURITY_DESCRIPTOR_HEADER)], 510 attr,attrsz); 511 phsds = (SECURITY_DESCRIPTOR_HEADER*)&fullattr[gap]; 512 phsds->hash = hash; 513 phsds->security_id = keyid; 514 phsds->offset = cpu_to_le64(offs); 515 phsds->length = cpu_to_le32(fullsz - gap); 516 written1 = ntfs_attr_data_write(vol->secure_ni, 517 STREAM_SDS, 4, fullattr, fullsz, 518 offs - gap); 519 written2 = ntfs_attr_data_write(vol->secure_ni, 520 STREAM_SDS, 4, fullattr, fullsz, 521 offs - gap + ALIGN_SDS_BLOCK); 522 if ((written1 == fullsz) 523 && (written2 == written1)) 524 res = 0; 525 else 526 errno = ENOSPC; 527 free(fullattr); 528 } else 529 errno = ENOMEM; 530 return (res); 531 } 532 533 /* 534 * Enter a new security descriptor in $Secure (indexes only) 535 * 536 * Should only be called by entersecurityattr() to ensure consistency 537 * 538 * Returns zero if sucessful 539 */ 540 541 static int entersecurity_indexes(ntfs_volume *vol, s64 attrsz, 542 le32 hash, le32 keyid, off_t offs) 543 { 544 union { 545 struct { 546 le32 dataoffsl; 547 le32 dataoffsh; 548 } parts; 549 le64 all; 550 } realign; 551 int res; 552 ntfs_index_context *xsii; 553 ntfs_index_context *xsdh; 554 struct SII newsii; 555 struct SDH newsdh; 556 557 res = -1; 558 /* enter a new $SII record */ 559 560 xsii = vol->secure_xsii; 561 ntfs_index_ctx_reinit(xsii); 562 newsii.offs = const_cpu_to_le16(20); 563 newsii.size = const_cpu_to_le16(sizeof(struct SII) - 20); 564 newsii.fill1 = const_cpu_to_le32(0); 565 newsii.indexsz = const_cpu_to_le16(sizeof(struct SII)); 566 newsii.indexksz = const_cpu_to_le16(sizeof(SII_INDEX_KEY)); 567 newsii.flags = const_cpu_to_le16(0); 568 newsii.fill2 = const_cpu_to_le16(0); 569 newsii.keysecurid = keyid; 570 newsii.hash = hash; 571 newsii.securid = keyid; 572 realign.all = cpu_to_le64(offs); 573 newsii.dataoffsh = realign.parts.dataoffsh; 574 newsii.dataoffsl = realign.parts.dataoffsl; 575 newsii.datasize = cpu_to_le32(attrsz 576 + sizeof(SECURITY_DESCRIPTOR_HEADER)); 577 if (!ntfs_ie_add(xsii,(INDEX_ENTRY*)&newsii)) { 578 579 /* enter a new $SDH record */ 580 581 xsdh = vol->secure_xsdh; 582 ntfs_index_ctx_reinit(xsdh); 583 newsdh.offs = const_cpu_to_le16(24); 584 newsdh.size = const_cpu_to_le16( 585 sizeof(SECURITY_DESCRIPTOR_HEADER)); 586 newsdh.fill1 = const_cpu_to_le32(0); 587 newsdh.indexsz = const_cpu_to_le16( 588 sizeof(struct SDH)); 589 newsdh.indexksz = const_cpu_to_le16( 590 sizeof(SDH_INDEX_KEY)); 591 newsdh.flags = const_cpu_to_le16(0); 592 newsdh.fill2 = const_cpu_to_le16(0); 593 newsdh.keyhash = hash; 594 newsdh.keysecurid = keyid; 595 newsdh.hash = hash; 596 newsdh.securid = keyid; 597 newsdh.dataoffsh = realign.parts.dataoffsh; 598 newsdh.dataoffsl = realign.parts.dataoffsl; 599 newsdh.datasize = cpu_to_le32(attrsz 600 + sizeof(SECURITY_DESCRIPTOR_HEADER)); 601 /* special filler value, Windows generally */ 602 /* fills with 0x00490049, sometimes with zero */ 603 newsdh.fill3 = const_cpu_to_le32(0x00490049); 604 if (!ntfs_ie_add(xsdh,(INDEX_ENTRY*)&newsdh)) 605 res = 0; 606 } 607 return (res); 608 } 609 610 /* 611 * Enter a new security descriptor in $Secure (data and indexes) 612 * Returns id of entry, or zero if there is a problem. 613 * (should not be called for NTFS version < 3.0) 614 * 615 * important : calls have to be serialized, however no locking is 616 * needed while fuse is not multithreaded 617 */ 618 619 static le32 entersecurityattr(ntfs_volume *vol, 620 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz, 621 le32 hash) 622 { 623 union { 624 struct { 625 le32 dataoffsl; 626 le32 dataoffsh; 627 } parts; 628 le64 all; 629 } realign; 630 le32 securid; 631 le32 keyid; 632 u32 newkey; 633 off_t offs; 634 int gap; 635 int size; 636 BOOL found; 637 struct SII *psii; 638 INDEX_ENTRY *entry; 639 INDEX_ENTRY *next; 640 ntfs_index_context *xsii; 641 int retries; 642 ntfs_attr *na; 643 int olderrno; 644 645 /* find the first available securid beyond the last key */ 646 /* in $Secure:$SII. This also determines the first */ 647 /* available location in $Secure:$SDS, as this stream */ 648 /* is always appended to and the id's are allocated */ 649 /* in sequence */ 650 651 securid = const_cpu_to_le32(0); 652 xsii = vol->secure_xsii; 653 ntfs_index_ctx_reinit(xsii); 654 offs = size = 0; 655 keyid = const_cpu_to_le32(-1); 656 olderrno = errno; 657 found = !ntfs_index_lookup((char*)&keyid, 658 sizeof(SII_INDEX_KEY), xsii); 659 if (!found && (errno != ENOENT)) { 660 ntfs_log_perror("Inconsistency in index $SII"); 661 psii = (struct SII*)NULL; 662 } else { 663 /* restore errno to avoid misinterpretation */ 664 errno = olderrno; 665 entry = xsii->entry; 666 psii = (struct SII*)xsii->entry; 667 } 668 if (psii) { 669 /* 670 * Get last entry in block, but must get first one 671 * one first, as we should already be beyond the 672 * last one. For some reason the search for the last 673 * entry sometimes does not return the last block... 674 * we assume this can only happen in root block 675 */ 676 if (xsii->is_in_root) 677 entry = ntfs_ie_get_first 678 ((INDEX_HEADER*)&xsii->ir->index); 679 else 680 entry = ntfs_ie_get_first 681 ((INDEX_HEADER*)&xsii->ib->index); 682 /* 683 * All index blocks should be at least half full 684 * so there always is a last entry but one, 685 * except when creating the first entry in index root. 686 * This was however found not to be true : chkdsk 687 * sometimes deletes all the (unused) keys in the last 688 * index block without rebalancing the tree. 689 * When this happens, a new search is restarted from 690 * the smallest key. 691 */ 692 keyid = const_cpu_to_le32(0); 693 retries = 0; 694 while (entry) { 695 next = ntfs_index_next(entry,xsii); 696 if (next) { 697 psii = (struct SII*)next; 698 /* save last key and */ 699 /* available position */ 700 keyid = psii->keysecurid; 701 realign.parts.dataoffsh 702 = psii->dataoffsh; 703 realign.parts.dataoffsl 704 = psii->dataoffsl; 705 offs = le64_to_cpu(realign.all); 706 size = le32_to_cpu(psii->datasize); 707 } 708 entry = next; 709 if (!entry && !keyid && !retries) { 710 /* search failed, retry from smallest key */ 711 ntfs_index_ctx_reinit(xsii); 712 found = !ntfs_index_lookup((char*)&keyid, 713 sizeof(SII_INDEX_KEY), xsii); 714 if (!found && (errno != ENOENT)) { 715 ntfs_log_perror("Index $SII is broken"); 716 } else { 717 /* restore errno */ 718 errno = olderrno; 719 entry = xsii->entry; 720 } 721 retries++; 722 } 723 } 724 } 725 if (!keyid) { 726 /* 727 * could not find any entry, before creating the first 728 * entry, make a double check by making sure size of $SII 729 * is less than needed for one entry 730 */ 731 securid = const_cpu_to_le32(0); 732 na = ntfs_attr_open(vol->secure_ni,AT_INDEX_ROOT,sii_stream,4); 733 if (na) { 734 if ((size_t)na->data_size < sizeof(struct SII)) { 735 ntfs_log_error("Creating the first security_id\n"); 736 securid = const_cpu_to_le32(FIRST_SECURITY_ID); 737 } 738 ntfs_attr_close(na); 739 } 740 if (!securid) { 741 ntfs_log_error("Error creating a security_id\n"); 742 errno = EIO; 743 } 744 } else { 745 newkey = le32_to_cpu(keyid) + 1; 746 securid = cpu_to_le32(newkey); 747 } 748 /* 749 * The security attr has to be written twice 256KB 750 * apart. This implies that offsets like 751 * 0x40000*odd_integer must be left available for 752 * the second copy. So align to next block when 753 * the last byte overflows on a wrong block. 754 */ 755 756 if (securid) { 757 gap = (-size) & (ALIGN_SDS_ENTRY - 1); 758 offs += gap + size; 759 if ((offs + attrsz + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1) 760 & ALIGN_SDS_BLOCK) { 761 offs = ((offs + attrsz 762 + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1) 763 | (ALIGN_SDS_BLOCK - 1)) + 1; 764 } 765 if (!(offs & (ALIGN_SDS_BLOCK - 1))) 766 entersecurity_stuff(vol, offs); 767 /* 768 * now write the security attr to storage : 769 * first data, then SII, then SDH 770 * If failure occurs while writing SDS, data will never 771 * be accessed through indexes, and will be overwritten 772 * by the next allocated descriptor 773 * If failure occurs while writing SII, the id has not 774 * recorded and will be reallocated later 775 * If failure occurs while writing SDH, the space allocated 776 * in SDS or SII will not be reused, an inconsistency 777 * will persist with no significant consequence 778 */ 779 if (entersecurity_data(vol, attr, attrsz, hash, securid, offs, gap) 780 || entersecurity_indexes(vol, attrsz, hash, securid, offs)) 781 securid = const_cpu_to_le32(0); 782 } 783 /* inode now is dirty, synchronize it all */ 784 ntfs_index_entry_mark_dirty(vol->secure_xsii); 785 ntfs_index_ctx_reinit(vol->secure_xsii); 786 ntfs_index_entry_mark_dirty(vol->secure_xsdh); 787 ntfs_index_ctx_reinit(vol->secure_xsdh); 788 NInoSetDirty(vol->secure_ni); 789 if (ntfs_inode_sync(vol->secure_ni)) 790 ntfs_log_perror("Could not sync $Secure\n"); 791 return (securid); 792 } 793 794 /* 795 * Find a matching security descriptor in $Secure, 796 * if none, allocate a new id and write the descriptor to storage 797 * Returns id of entry, or zero if there is a problem. 798 * 799 * important : calls have to be serialized, however no locking is 800 * needed while fuse is not multithreaded 801 */ 802 803 static le32 setsecurityattr(ntfs_volume *vol, 804 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz) 805 { 806 struct SDH *psdh; /* this is an image of index (le) */ 807 union { 808 struct { 809 le32 dataoffsl; 810 le32 dataoffsh; 811 } parts; 812 le64 all; 813 } realign; 814 BOOL found; 815 BOOL collision; 816 size_t size; 817 size_t rdsize; 818 s64 offs; 819 int res; 820 ntfs_index_context *xsdh; 821 char *oldattr; 822 SDH_INDEX_KEY key; 823 INDEX_ENTRY *entry; 824 le32 securid; 825 le32 hash; 826 int olderrno; 827 828 hash = ntfs_security_hash(attr,attrsz); 829 oldattr = (char*)NULL; 830 securid = const_cpu_to_le32(0); 831 res = 0; 832 xsdh = vol->secure_xsdh; 833 if (vol->secure_ni && xsdh && !vol->secure_reentry++) { 834 ntfs_index_ctx_reinit(xsdh); 835 /* 836 * find the nearest key as (hash,0) 837 * (do not search for partial key : in case of collision, 838 * it could return a key which is not the first one which 839 * collides) 840 */ 841 key.hash = hash; 842 key.security_id = const_cpu_to_le32(0); 843 olderrno = errno; 844 found = !ntfs_index_lookup((char*)&key, 845 sizeof(SDH_INDEX_KEY), xsdh); 846 if (!found && (errno != ENOENT)) 847 ntfs_log_perror("Inconsistency in index $SDH"); 848 else { 849 /* restore errno to avoid misinterpretation */ 850 errno = olderrno; 851 entry = xsdh->entry; 852 found = FALSE; 853 /* 854 * lookup() may return a node with no data, 855 * if so get next 856 */ 857 if (entry->ie_flags & INDEX_ENTRY_END) 858 entry = ntfs_index_next(entry,xsdh); 859 do { 860 collision = FALSE; 861 psdh = (struct SDH*)entry; 862 if (psdh) 863 size = (size_t) le32_to_cpu(psdh->datasize) 864 - sizeof(SECURITY_DESCRIPTOR_HEADER); 865 else size = 0; 866 /* if hash is not the same, the key is not present */ 867 if (psdh && (size > 0) 868 && (psdh->keyhash == hash)) { 869 /* if hash is the same */ 870 /* check the whole record */ 871 realign.parts.dataoffsh = psdh->dataoffsh; 872 realign.parts.dataoffsl = psdh->dataoffsl; 873 offs = le64_to_cpu(realign.all) 874 + sizeof(SECURITY_DESCRIPTOR_HEADER); 875 oldattr = (char*)ntfs_malloc(size); 876 if (oldattr) { 877 rdsize = ntfs_attr_data_read( 878 vol->secure_ni, 879 STREAM_SDS, 4, 880 oldattr, size, offs); 881 found = (rdsize == size) 882 && !memcmp(oldattr,attr,size); 883 free(oldattr); 884 /* if the records do not compare */ 885 /* (hash collision), try next one */ 886 if (!found) { 887 entry = ntfs_index_next( 888 entry,xsdh); 889 collision = TRUE; 890 } 891 } else 892 res = ENOMEM; 893 } 894 } while (collision && entry); 895 if (found) 896 securid = psdh->keysecurid; 897 else { 898 if (res) { 899 errno = res; 900 securid = const_cpu_to_le32(0); 901 } else { 902 /* 903 * no matching key : 904 * have to build a new one 905 */ 906 securid = entersecurityattr(vol, 907 attr, attrsz, hash); 908 } 909 } 910 } 911 } 912 if (--vol->secure_reentry) 913 ntfs_log_perror("Reentry error, check no multithreading\n"); 914 return (securid); 915 } 916 917 918 /* 919 * Update the security descriptor of a file 920 * Either as an attribute (complying with pre v3.x NTFS version) 921 * or, when possible, as an entry in $Secure (for NTFS v3.x) 922 * 923 * returns 0 if success 924 */ 925 926 static int update_secur_descr(ntfs_volume *vol, 927 char *newattr, ntfs_inode *ni) 928 { 929 int newattrsz; 930 int written; 931 int res; 932 ntfs_attr *na; 933 934 newattrsz = ntfs_attr_size(newattr); 935 936 #if !FORCE_FORMAT_v1x 937 if ((vol->major_ver < 3) || !vol->secure_ni) { 938 #endif 939 940 /* update for NTFS format v1.x */ 941 942 /* update the old security attribute */ 943 na = ntfs_attr_open(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0); 944 if (na) { 945 /* resize attribute */ 946 res = ntfs_attr_truncate(na, (s64) newattrsz); 947 /* overwrite value */ 948 if (!res) { 949 written = (int)ntfs_attr_pwrite(na, (s64) 0, 950 (s64) newattrsz, newattr); 951 if (written != newattrsz) { 952 ntfs_log_error("Failed to update " 953 "a v1.x security descriptor\n"); 954 errno = EIO; 955 res = -1; 956 } 957 } 958 959 ntfs_attr_close(na); 960 /* if old security attribute was found, also */ 961 /* truncate standard information attribute to v1.x */ 962 /* this is needed when security data is wanted */ 963 /* as v1.x though volume is formatted for v3.x */ 964 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION, 965 AT_UNNAMED, 0); 966 if (na) { 967 clear_nino_flag(ni, v3_Extensions); 968 /* 969 * Truncating the record does not sweep extensions 970 * from copy in memory. Clear security_id to be safe 971 */ 972 ni->security_id = const_cpu_to_le32(0); 973 res = ntfs_attr_truncate(na, (s64)48); 974 ntfs_attr_close(na); 975 clear_nino_flag(ni, v3_Extensions); 976 } 977 } else { 978 /* 979 * insert the new security attribute if there 980 * were none 981 */ 982 res = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, 983 AT_UNNAMED, 0, (u8*)newattr, 984 (s64) newattrsz); 985 } 986 #if !FORCE_FORMAT_v1x 987 } else { 988 989 /* update for NTFS format v3.x */ 990 991 le32 securid; 992 993 securid = setsecurityattr(vol, 994 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr, 995 (s64)newattrsz); 996 if (securid) { 997 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION, 998 AT_UNNAMED, 0); 999 if (na) { 1000 res = 0; 1001 if (!test_nino_flag(ni, v3_Extensions)) { 1002 /* expand standard information attribute to v3.x */ 1003 res = ntfs_attr_truncate(na, 1004 (s64)sizeof(STANDARD_INFORMATION)); 1005 ni->owner_id = const_cpu_to_le32(0); 1006 ni->quota_charged = const_cpu_to_le64(0); 1007 ni->usn = const_cpu_to_le64(0); 1008 ntfs_attr_remove(ni, 1009 AT_SECURITY_DESCRIPTOR, 1010 AT_UNNAMED, 0); 1011 } 1012 set_nino_flag(ni, v3_Extensions); 1013 ni->security_id = securid; 1014 ntfs_attr_close(na); 1015 } else { 1016 ntfs_log_error("Failed to update " 1017 "standard informations\n"); 1018 errno = EIO; 1019 res = -1; 1020 } 1021 } else 1022 res = -1; 1023 } 1024 #endif 1025 1026 /* mark node as dirty */ 1027 NInoSetDirty(ni); 1028 return (res); 1029 } 1030 1031 /* 1032 * Upgrade the security descriptor of a file 1033 * This is intended to allow graceful upgrades for files which 1034 * were created in previous versions, with a security attributes 1035 * and no security id. 1036 * 1037 * It will allocate a security id and replace the individual 1038 * security attribute by a reference to the global one 1039 * 1040 * Special files are not upgraded (currently / and files in 1041 * directories /$*) 1042 * 1043 * Though most code is similar to update_secur_desc() it has 1044 * been kept apart to facilitate the further processing of 1045 * special cases or even to remove it if found dangerous. 1046 * 1047 * returns 0 if success, 1048 * 1 if not upgradable. This is not an error. 1049 * -1 if there is a problem 1050 */ 1051 1052 static int upgrade_secur_desc(ntfs_volume *vol, 1053 const char *attr, ntfs_inode *ni) 1054 { 1055 int attrsz; 1056 int res; 1057 le32 securid; 1058 ntfs_attr *na; 1059 1060 /* 1061 * upgrade requires NTFS format v3.x 1062 * also refuse upgrading for special files 1063 * whose number is less than FILE_first_user 1064 */ 1065 1066 if ((vol->major_ver >= 3) 1067 && (ni->mft_no >= FILE_first_user)) { 1068 attrsz = ntfs_attr_size(attr); 1069 securid = setsecurityattr(vol, 1070 (const SECURITY_DESCRIPTOR_RELATIVE*)attr, 1071 (s64)attrsz); 1072 if (securid) { 1073 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION, 1074 AT_UNNAMED, 0); 1075 if (na) { 1076 /* expand standard information attribute to v3.x */ 1077 res = ntfs_attr_truncate(na, 1078 (s64)sizeof(STANDARD_INFORMATION)); 1079 ni->owner_id = const_cpu_to_le32(0); 1080 ni->quota_charged = const_cpu_to_le64(0); 1081 ni->usn = const_cpu_to_le64(0); 1082 ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR, 1083 AT_UNNAMED, 0); 1084 set_nino_flag(ni, v3_Extensions); 1085 ni->security_id = securid; 1086 ntfs_attr_close(na); 1087 } else { 1088 ntfs_log_error("Failed to upgrade " 1089 "standard informations\n"); 1090 errno = EIO; 1091 res = -1; 1092 } 1093 } else 1094 res = -1; 1095 /* mark node as dirty */ 1096 NInoSetDirty(ni); 1097 } else 1098 res = 1; 1099 1100 return (res); 1101 } 1102 1103 /* 1104 * Optional simplified checking of group membership 1105 * 1106 * This only takes into account the groups defined in 1107 * /etc/group at initialization time. 1108 * It does not take into account the groups dynamically set by 1109 * setgroups() nor the changes in /etc/group since initialization 1110 * 1111 * This optional method could be useful if standard checking 1112 * leads to a performance concern. 1113 * 1114 * Should not be called for user root, however the group may be root 1115 * 1116 */ 1117 #ifndef __HAIKU__ 1118 static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid) 1119 { 1120 BOOL ingroup; 1121 int grcnt; 1122 gid_t *groups; 1123 struct MAPPING *user; 1124 1125 ingroup = FALSE; 1126 if (uid) { 1127 user = scx->mapping[MAPUSERS]; 1128 while (user && ((uid_t)user->xid != uid)) 1129 user = user->next; 1130 if (user) { 1131 groups = user->groups; 1132 grcnt = user->grcnt; 1133 while ((--grcnt >= 0) && (groups[grcnt] != gid)) { } 1134 ingroup = (grcnt >= 0); 1135 } 1136 } 1137 return (ingroup); 1138 } 1139 #endif //__HAIKU__ 1140 1141 #if defined(__sun) && defined (__SVR4) 1142 1143 /* 1144 * Check whether current thread owner is member of file group 1145 * Solaris/OpenIndiana version 1146 * Should not be called for user root, however the group may be root 1147 * 1148 * The group list is available in "/proc/$PID/cred" 1149 * 1150 */ 1151 1152 static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid) 1153 { 1154 typedef struct prcred { 1155 uid_t pr_euid; /* effective user id */ 1156 uid_t pr_ruid; /* real user id */ 1157 uid_t pr_suid; /* saved user id (from exec) */ 1158 gid_t pr_egid; /* effective group id */ 1159 gid_t pr_rgid; /* real group id */ 1160 gid_t pr_sgid; /* saved group id (from exec) */ 1161 int pr_ngroups; /* number of supplementary groups */ 1162 gid_t pr_groups[1]; /* array of supplementary groups */ 1163 } prcred_t; 1164 enum { readset = 16 }; 1165 1166 prcred_t basecreds; 1167 gid_t groups[readset]; 1168 char filename[64]; 1169 int fd; 1170 int k; 1171 int cnt; 1172 gid_t *p; 1173 BOOL ismember; 1174 int got; 1175 pid_t tid; 1176 1177 if (scx->vol->secure_flags & (1 << SECURITY_STATICGRPS)) 1178 ismember = staticgroupmember(scx, uid, gid); 1179 else { 1180 ismember = FALSE; /* default return */ 1181 tid = scx->tid; 1182 sprintf(filename,"/proc/%u/cred",tid); 1183 fd = open(filename,O_RDONLY); 1184 if (fd >= 0) { 1185 got = read(fd, &basecreds, sizeof(prcred_t)); 1186 if (got == sizeof(prcred_t)) { 1187 if (basecreds.pr_egid == gid) 1188 ismember = TRUE; 1189 p = basecreds.pr_groups; 1190 cnt = 1; 1191 k = 0; 1192 while (!ismember 1193 && (k < basecreds.pr_ngroups) 1194 && (cnt > 0) 1195 && (*p != gid)) { 1196 k++; 1197 cnt--; 1198 p++; 1199 if (cnt <= 0) { 1200 got = read(fd, groups, 1201 readset*sizeof(gid_t)); 1202 cnt = got/sizeof(gid_t); 1203 p = groups; 1204 } 1205 } 1206 if ((cnt > 0) 1207 && (k < basecreds.pr_ngroups)) 1208 ismember = TRUE; 1209 } 1210 close(fd); 1211 } 1212 } 1213 return (ismember); 1214 } 1215 1216 #elif defined(__HAIKU__) 1217 1218 static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid) 1219 { 1220 return TRUE; 1221 } 1222 1223 #else /* defined(__sun) && defined (__SVR4) */ 1224 1225 /* 1226 * Check whether current thread owner is member of file group 1227 * Linux version 1228 * Should not be called for user root, however the group may be root 1229 * 1230 * As indicated by Miklos Szeredi : 1231 * 1232 * The group list is available in 1233 * 1234 * /proc/$PID/task/$TID/status 1235 * 1236 * and fuse supplies TID in get_fuse_context()->pid. The only problem is 1237 * finding out PID, for which I have no good solution, except to iterate 1238 * through all processes. This is rather slow, but may be speeded up 1239 * with caching and heuristics (for single threaded programs PID = TID). 1240 * 1241 * The following implementation gets the group list from 1242 * /proc/$TID/task/$TID/status which apparently exists and 1243 * contains the same data. 1244 */ 1245 1246 static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid) 1247 { 1248 static char key[] = "\nGroups:"; 1249 char buf[BUFSZ+1]; 1250 char filename[64]; 1251 enum { INKEY, INSEP, INNUM, INEND } state; 1252 int fd; 1253 char c; 1254 int matched; 1255 BOOL ismember; 1256 int got; 1257 char *p; 1258 gid_t grp; 1259 pid_t tid; 1260 1261 if (scx->vol->secure_flags & (1 << SECURITY_STATICGRPS)) 1262 ismember = staticgroupmember(scx, uid, gid); 1263 else { 1264 ismember = FALSE; /* default return */ 1265 tid = scx->tid; 1266 sprintf(filename,"/proc/%u/task/%u/status",tid,tid); 1267 fd = open(filename,O_RDONLY); 1268 if (fd >= 0) { 1269 got = read(fd, buf, BUFSZ); 1270 buf[got] = 0; 1271 state = INKEY; 1272 matched = 0; 1273 p = buf; 1274 grp = 0; 1275 /* 1276 * A simple automaton to process lines like 1277 * Groups: 14 500 513 1278 */ 1279 do { 1280 c = *p++; 1281 if (!c) { 1282 /* refill buffer */ 1283 got = read(fd, buf, BUFSZ); 1284 buf[got] = 0; 1285 p = buf; 1286 c = *p++; /* 0 at end of file */ 1287 } 1288 switch (state) { 1289 case INKEY : 1290 if (key[matched] == c) { 1291 if (!key[++matched]) 1292 state = INSEP; 1293 } else 1294 if (key[0] == c) 1295 matched = 1; 1296 else 1297 matched = 0; 1298 break; 1299 case INSEP : 1300 if ((c >= '0') && (c <= '9')) { 1301 grp = c - '0'; 1302 state = INNUM; 1303 } else 1304 if ((c != ' ') && (c != '\t')) 1305 state = INEND; 1306 break; 1307 case INNUM : 1308 if ((c >= '0') && (c <= '9')) 1309 grp = grp*10 + c - '0'; 1310 else { 1311 ismember = (grp == gid); 1312 if ((c != ' ') && (c != '\t')) 1313 state = INEND; 1314 else 1315 state = INSEP; 1316 } 1317 default : 1318 break; 1319 } 1320 } while (!ismember && c && (state != INEND)); 1321 close(fd); 1322 if (!c) 1323 ntfs_log_error("No group record found in %s\n",filename); 1324 } else 1325 ntfs_log_error("Could not open %s\n",filename); 1326 } 1327 return (ismember); 1328 } 1329 1330 #endif /* defined(__sun) && defined (__SVR4) */ 1331 1332 /* 1333 * Cacheing is done two-way : 1334 * - from uid, gid and perm to securid (CACHED_SECURID) 1335 * - from a securid to uid, gid and perm (CACHED_PERMISSIONS) 1336 * 1337 * CACHED_SECURID data is kept in a most-recent-first list 1338 * which should not be too long to be efficient. Its optimal 1339 * size is depends on usage and is hard to determine. 1340 * 1341 * CACHED_PERMISSIONS data is kept in a two-level indexed array. It 1342 * is optimal at the expense of storage. Use of a most-recent-first 1343 * list would save memory and provide similar performances for 1344 * standard usage, but not for file servers with too many file 1345 * owners 1346 * 1347 * CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS 1348 * for legacy directories which were not allocated a security_id 1349 * it is organized in a most-recent-first list. 1350 * 1351 * In main caches, data is never invalidated, as the meaning of 1352 * a security_id only changes when user mapping is changed, which 1353 * current implies remounting. However returned entries may be 1354 * overwritten at next update, so data has to be copied elsewhere 1355 * before another cache update is made. 1356 * In legacy cache, data has to be invalidated when protection is 1357 * changed. 1358 * 1359 * Though the same data may be found in both list, they 1360 * must be kept separately : the interpretation of ACL 1361 * in both direction are approximations which could be non 1362 * reciprocal for some configuration of the user mapping data 1363 * 1364 * During the process of recompiling ntfs-3g from a tgz archive, 1365 * security processing added 7.6% to the cpu time used by ntfs-3g 1366 * and 30% if the cache is disabled. 1367 */ 1368 1369 static struct PERMISSIONS_CACHE *create_caches(struct SECURITY_CONTEXT *scx, 1370 u32 securindex) 1371 { 1372 struct PERMISSIONS_CACHE *cache; 1373 unsigned int index1; 1374 unsigned int i; 1375 1376 cache = (struct PERMISSIONS_CACHE*)NULL; 1377 /* create the first permissions blocks */ 1378 index1 = securindex >> CACHE_PERMISSIONS_BITS; 1379 cache = (struct PERMISSIONS_CACHE*) 1380 ntfs_malloc(sizeof(struct PERMISSIONS_CACHE) 1381 + index1*sizeof(struct CACHED_PERMISSIONS*)); 1382 if (cache) { 1383 cache->head.last = index1; 1384 cache->head.p_reads = 0; 1385 cache->head.p_hits = 0; 1386 cache->head.p_writes = 0; 1387 *scx->pseccache = cache; 1388 for (i=0; i<=index1; i++) 1389 cache->cachetable[i] 1390 = (struct CACHED_PERMISSIONS*)NULL; 1391 } 1392 return (cache); 1393 } 1394 1395 /* 1396 * Free memory used by caches 1397 * The only purpose is to facilitate the detection of memory leaks 1398 */ 1399 1400 static void free_caches(struct SECURITY_CONTEXT *scx) 1401 { 1402 unsigned int index1; 1403 struct PERMISSIONS_CACHE *pseccache; 1404 1405 pseccache = *scx->pseccache; 1406 if (pseccache) { 1407 for (index1=0; index1<=pseccache->head.last; index1++) 1408 if (pseccache->cachetable[index1]) { 1409 #if POSIXACLS 1410 struct CACHED_PERMISSIONS *cacheentry; 1411 unsigned int index2; 1412 1413 for (index2=0; index2<(1<< CACHE_PERMISSIONS_BITS); index2++) { 1414 cacheentry = &pseccache->cachetable[index1][index2]; 1415 if (cacheentry->valid 1416 && cacheentry->pxdesc) 1417 free(cacheentry->pxdesc); 1418 } 1419 #endif 1420 free(pseccache->cachetable[index1]); 1421 } 1422 free(pseccache); 1423 } 1424 } 1425 1426 static int compare(const struct CACHED_SECURID *cached, 1427 const struct CACHED_SECURID *item) 1428 { 1429 #if POSIXACLS 1430 size_t csize; 1431 size_t isize; 1432 1433 /* only compare data and sizes */ 1434 csize = (cached->variable ? 1435 sizeof(struct POSIX_ACL) 1436 + (((struct POSIX_SECURITY*)cached->variable)->acccnt 1437 + ((struct POSIX_SECURITY*)cached->variable)->defcnt) 1438 *sizeof(struct POSIX_ACE) : 1439 0); 1440 isize = (item->variable ? 1441 sizeof(struct POSIX_ACL) 1442 + (((struct POSIX_SECURITY*)item->variable)->acccnt 1443 + ((struct POSIX_SECURITY*)item->variable)->defcnt) 1444 *sizeof(struct POSIX_ACE) : 1445 0); 1446 return ((cached->uid != item->uid) 1447 || (cached->gid != item->gid) 1448 || (cached->dmode != item->dmode) 1449 || (csize != isize) 1450 || (csize 1451 && isize 1452 && memcmp(&((struct POSIX_SECURITY*)cached->variable)->acl, 1453 &((struct POSIX_SECURITY*)item->variable)->acl, csize))); 1454 #else 1455 return ((cached->uid != item->uid) 1456 || (cached->gid != item->gid) 1457 || (cached->dmode != item->dmode)); 1458 #endif 1459 } 1460 1461 static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached, 1462 const struct CACHED_PERMISSIONS_LEGACY *item) 1463 { 1464 return (cached->mft_no != item->mft_no); 1465 } 1466 1467 /* 1468 * Resize permission cache table 1469 * do not call unless resizing is needed 1470 * 1471 * If allocation fails, the cache size is not updated 1472 * Lack of memory is not considered as an error, the cache is left 1473 * consistent and errno is not set. 1474 */ 1475 1476 static void resize_cache(struct SECURITY_CONTEXT *scx, 1477 u32 securindex) 1478 { 1479 struct PERMISSIONS_CACHE *oldcache; 1480 struct PERMISSIONS_CACHE *newcache; 1481 int newcnt; 1482 int oldcnt; 1483 unsigned int index1; 1484 unsigned int i; 1485 1486 oldcache = *scx->pseccache; 1487 index1 = securindex >> CACHE_PERMISSIONS_BITS; 1488 newcnt = index1 + 1; 1489 if (newcnt <= ((CACHE_PERMISSIONS_SIZE 1490 + (1 << CACHE_PERMISSIONS_BITS) 1491 - 1) >> CACHE_PERMISSIONS_BITS)) { 1492 /* expand cache beyond current end, do not use realloc() */ 1493 /* to avoid losing data when there is no more memory */ 1494 oldcnt = oldcache->head.last + 1; 1495 newcache = (struct PERMISSIONS_CACHE*) 1496 ntfs_malloc( 1497 sizeof(struct PERMISSIONS_CACHE) 1498 + (newcnt - 1)*sizeof(struct CACHED_PERMISSIONS*)); 1499 if (newcache) { 1500 memcpy(newcache,oldcache, 1501 sizeof(struct PERMISSIONS_CACHE) 1502 + (oldcnt - 1)*sizeof(struct CACHED_PERMISSIONS*)); 1503 free(oldcache); 1504 /* mark new entries as not valid */ 1505 for (i=newcache->head.last+1; i<=index1; i++) 1506 newcache->cachetable[i] 1507 = (struct CACHED_PERMISSIONS*)NULL; 1508 newcache->head.last = index1; 1509 *scx->pseccache = newcache; 1510 } 1511 } 1512 } 1513 1514 /* 1515 * Enter uid, gid and mode into cache, if possible 1516 * 1517 * returns the updated or created cache entry, 1518 * or NULL if not possible (typically if there is no 1519 * security id associated) 1520 */ 1521 1522 #if POSIXACLS 1523 static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx, 1524 ntfs_inode *ni, uid_t uid, gid_t gid, 1525 struct POSIX_SECURITY *pxdesc) 1526 #else 1527 static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx, 1528 ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode) 1529 #endif 1530 { 1531 struct CACHED_PERMISSIONS *cacheentry; 1532 struct CACHED_PERMISSIONS *cacheblock; 1533 struct PERMISSIONS_CACHE *pcache; 1534 u32 securindex; 1535 #if POSIXACLS 1536 int pxsize; 1537 struct POSIX_SECURITY *pxcached; 1538 #endif 1539 unsigned int index1; 1540 unsigned int index2; 1541 int i; 1542 1543 /* cacheing is only possible if a security_id has been defined */ 1544 if (test_nino_flag(ni, v3_Extensions) 1545 && ni->security_id) { 1546 /* 1547 * Immediately test the most frequent situation 1548 * where the entry exists 1549 */ 1550 securindex = le32_to_cpu(ni->security_id); 1551 index1 = securindex >> CACHE_PERMISSIONS_BITS; 1552 index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1); 1553 pcache = *scx->pseccache; 1554 if (pcache 1555 && (pcache->head.last >= index1) 1556 && pcache->cachetable[index1]) { 1557 cacheentry = &pcache->cachetable[index1][index2]; 1558 cacheentry->uid = uid; 1559 cacheentry->gid = gid; 1560 #if POSIXACLS 1561 if (cacheentry->valid && cacheentry->pxdesc) 1562 free(cacheentry->pxdesc); 1563 if (pxdesc) { 1564 pxsize = sizeof(struct POSIX_SECURITY) 1565 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); 1566 pxcached = (struct POSIX_SECURITY*)malloc(pxsize); 1567 if (pxcached) { 1568 memcpy(pxcached, pxdesc, pxsize); 1569 cacheentry->pxdesc = pxcached; 1570 } else { 1571 cacheentry->valid = 0; 1572 cacheentry = (struct CACHED_PERMISSIONS*)NULL; 1573 } 1574 cacheentry->mode = pxdesc->mode & 07777; 1575 } else 1576 cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL; 1577 #else 1578 cacheentry->mode = mode & 07777; 1579 #endif 1580 cacheentry->inh_fileid = const_cpu_to_le32(0); 1581 cacheentry->inh_dirid = const_cpu_to_le32(0); 1582 cacheentry->valid = 1; 1583 pcache->head.p_writes++; 1584 } else { 1585 if (!pcache) { 1586 /* create the first cache block */ 1587 pcache = create_caches(scx, securindex); 1588 } else { 1589 if (index1 > pcache->head.last) { 1590 resize_cache(scx, securindex); 1591 pcache = *scx->pseccache; 1592 } 1593 } 1594 /* allocate block, if cache table was allocated */ 1595 if (pcache && (index1 <= pcache->head.last)) { 1596 cacheblock = (struct CACHED_PERMISSIONS*) 1597 malloc(sizeof(struct CACHED_PERMISSIONS) 1598 << CACHE_PERMISSIONS_BITS); 1599 pcache->cachetable[index1] = cacheblock; 1600 for (i=0; i<(1 << CACHE_PERMISSIONS_BITS); i++) 1601 cacheblock[i].valid = 0; 1602 cacheentry = &cacheblock[index2]; 1603 if (cacheentry) { 1604 cacheentry->uid = uid; 1605 cacheentry->gid = gid; 1606 #if POSIXACLS 1607 if (pxdesc) { 1608 pxsize = sizeof(struct POSIX_SECURITY) 1609 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); 1610 pxcached = (struct POSIX_SECURITY*)malloc(pxsize); 1611 if (pxcached) { 1612 memcpy(pxcached, pxdesc, pxsize); 1613 cacheentry->pxdesc = pxcached; 1614 } else { 1615 cacheentry->valid = 0; 1616 cacheentry = (struct CACHED_PERMISSIONS*)NULL; 1617 } 1618 cacheentry->mode = pxdesc->mode & 07777; 1619 } else 1620 cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL; 1621 #else 1622 cacheentry->mode = mode & 07777; 1623 #endif 1624 cacheentry->inh_fileid = const_cpu_to_le32(0); 1625 cacheentry->inh_dirid = const_cpu_to_le32(0); 1626 cacheentry->valid = 1; 1627 pcache->head.p_writes++; 1628 } 1629 } else 1630 cacheentry = (struct CACHED_PERMISSIONS*)NULL; 1631 } 1632 } else { 1633 cacheentry = (struct CACHED_PERMISSIONS*)NULL; 1634 #if CACHE_LEGACY_SIZE 1635 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { 1636 struct CACHED_PERMISSIONS_LEGACY wanted; 1637 struct CACHED_PERMISSIONS_LEGACY *legacy; 1638 1639 wanted.perm.uid = uid; 1640 wanted.perm.gid = gid; 1641 #if POSIXACLS 1642 wanted.perm.mode = pxdesc->mode & 07777; 1643 wanted.perm.inh_fileid = const_cpu_to_le32(0); 1644 wanted.perm.inh_dirid = const_cpu_to_le32(0); 1645 wanted.mft_no = ni->mft_no; 1646 wanted.variable = (void*)pxdesc; 1647 wanted.varsize = sizeof(struct POSIX_SECURITY) 1648 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); 1649 #else 1650 wanted.perm.mode = mode & 07777; 1651 wanted.perm.inh_fileid = const_cpu_to_le32(0); 1652 wanted.perm.inh_dirid = const_cpu_to_le32(0); 1653 wanted.mft_no = ni->mft_no; 1654 wanted.variable = (void*)NULL; 1655 wanted.varsize = 0; 1656 #endif 1657 legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_enter_cache( 1658 scx->vol->legacy_cache, GENERIC(&wanted), 1659 (cache_compare)leg_compare); 1660 if (legacy) { 1661 cacheentry = &legacy->perm; 1662 #if POSIXACLS 1663 /* 1664 * give direct access to the cached pxdesc 1665 * in the permissions structure 1666 */ 1667 cacheentry->pxdesc = legacy->variable; 1668 #endif 1669 } 1670 } 1671 #endif 1672 } 1673 return (cacheentry); 1674 } 1675 1676 /* 1677 * Fetch owner, group and permission of a file, if cached 1678 * 1679 * Beware : do not use the returned entry after a cache update : 1680 * the cache may be relocated making the returned entry meaningless 1681 * 1682 * returns the cache entry, or NULL if not available 1683 */ 1684 1685 static struct CACHED_PERMISSIONS *fetch_cache(struct SECURITY_CONTEXT *scx, 1686 ntfs_inode *ni) 1687 { 1688 struct CACHED_PERMISSIONS *cacheentry; 1689 struct PERMISSIONS_CACHE *pcache; 1690 u32 securindex; 1691 unsigned int index1; 1692 unsigned int index2; 1693 1694 /* cacheing is only possible if a security_id has been defined */ 1695 cacheentry = (struct CACHED_PERMISSIONS*)NULL; 1696 if (test_nino_flag(ni, v3_Extensions) 1697 && (ni->security_id)) { 1698 securindex = le32_to_cpu(ni->security_id); 1699 index1 = securindex >> CACHE_PERMISSIONS_BITS; 1700 index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1); 1701 pcache = *scx->pseccache; 1702 if (pcache 1703 && (pcache->head.last >= index1) 1704 && pcache->cachetable[index1]) { 1705 cacheentry = &pcache->cachetable[index1][index2]; 1706 /* reject if entry is not valid */ 1707 if (!cacheentry->valid) 1708 cacheentry = (struct CACHED_PERMISSIONS*)NULL; 1709 else 1710 pcache->head.p_hits++; 1711 if (pcache) 1712 pcache->head.p_reads++; 1713 } 1714 } 1715 #if CACHE_LEGACY_SIZE 1716 else { 1717 cacheentry = (struct CACHED_PERMISSIONS*)NULL; 1718 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { 1719 struct CACHED_PERMISSIONS_LEGACY wanted; 1720 struct CACHED_PERMISSIONS_LEGACY *legacy; 1721 1722 wanted.mft_no = ni->mft_no; 1723 wanted.variable = (void*)NULL; 1724 wanted.varsize = 0; 1725 legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_fetch_cache( 1726 scx->vol->legacy_cache, GENERIC(&wanted), 1727 (cache_compare)leg_compare); 1728 if (legacy) cacheentry = &legacy->perm; 1729 } 1730 } 1731 #endif 1732 #if POSIXACLS 1733 if (cacheentry && !cacheentry->pxdesc) { 1734 ntfs_log_error("No Posix descriptor in cache\n"); 1735 cacheentry = (struct CACHED_PERMISSIONS*)NULL; 1736 } 1737 #endif 1738 return (cacheentry); 1739 } 1740 1741 /* 1742 * Retrieve a security attribute from $Secure 1743 */ 1744 1745 static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id) 1746 { 1747 struct SII *psii; 1748 union { 1749 struct { 1750 le32 dataoffsl; 1751 le32 dataoffsh; 1752 } parts; 1753 le64 all; 1754 } realign; 1755 int found; 1756 size_t size; 1757 size_t rdsize; 1758 s64 offs; 1759 ntfs_inode *ni; 1760 ntfs_index_context *xsii; 1761 char *securattr; 1762 1763 securattr = (char*)NULL; 1764 ni = vol->secure_ni; 1765 xsii = vol->secure_xsii; 1766 if (ni && xsii) { 1767 ntfs_index_ctx_reinit(xsii); 1768 found = 1769 !ntfs_index_lookup((char*)&id, 1770 sizeof(SII_INDEX_KEY), xsii); 1771 if (found) { 1772 psii = (struct SII*)xsii->entry; 1773 size = 1774 (size_t) le32_to_cpu(psii->datasize) 1775 - sizeof(SECURITY_DESCRIPTOR_HEADER); 1776 /* work around bad alignment problem */ 1777 realign.parts.dataoffsh = psii->dataoffsh; 1778 realign.parts.dataoffsl = psii->dataoffsl; 1779 offs = le64_to_cpu(realign.all) 1780 + sizeof(SECURITY_DESCRIPTOR_HEADER); 1781 1782 securattr = (char*)ntfs_malloc(size); 1783 if (securattr) { 1784 rdsize = ntfs_attr_data_read( 1785 ni, STREAM_SDS, 4, 1786 securattr, size, offs); 1787 if ((rdsize != size) 1788 || !ntfs_valid_descr(securattr, 1789 rdsize)) { 1790 /* error to be logged by caller */ 1791 free(securattr); 1792 securattr = (char*)NULL; 1793 } 1794 } 1795 } else 1796 if (errno != ENOENT) 1797 ntfs_log_perror("Inconsistency in index $SII"); 1798 } 1799 if (!securattr) { 1800 ntfs_log_error("Failed to retrieve a security descriptor\n"); 1801 errno = EIO; 1802 } 1803 return (securattr); 1804 } 1805 1806 /* 1807 * Get the security descriptor associated to a file 1808 * 1809 * Either : 1810 * - read the security descriptor attribute (v1.x format) 1811 * - or find the descriptor in $Secure:$SDS (v3.x format) 1812 * 1813 * in both case, sanity checks are done on the attribute and 1814 * the descriptor can be assumed safe 1815 * 1816 * The returned descriptor is dynamically allocated and has to be freed 1817 */ 1818 1819 static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni) 1820 { 1821 SII_INDEX_KEY securid; 1822 char *securattr; 1823 s64 readallsz; 1824 1825 /* 1826 * Warning : in some situations, after fixing by chkdsk, 1827 * v3_Extensions are marked present (long standard informations) 1828 * with a default security descriptor inserted in an 1829 * attribute 1830 */ 1831 if (test_nino_flag(ni, v3_Extensions) 1832 && vol->secure_ni && ni->security_id) { 1833 /* get v3.x descriptor in $Secure */ 1834 securid.security_id = ni->security_id; 1835 securattr = retrievesecurityattr(vol,securid); 1836 if (!securattr) 1837 ntfs_log_error("Bad security descriptor for 0x%lx\n", 1838 (long)le32_to_cpu(ni->security_id)); 1839 } else { 1840 /* get v1.x security attribute */ 1841 readallsz = 0; 1842 securattr = ntfs_attr_readall(ni, AT_SECURITY_DESCRIPTOR, 1843 AT_UNNAMED, 0, &readallsz); 1844 if (securattr && !ntfs_valid_descr(securattr, readallsz)) { 1845 ntfs_log_error("Bad security descriptor for inode %lld\n", 1846 (long long)ni->mft_no); 1847 free(securattr); 1848 securattr = (char*)NULL; 1849 } 1850 } 1851 if (!securattr) { 1852 /* 1853 * in some situations, there is no security 1854 * descriptor, and chkdsk does not detect or fix 1855 * anything. This could be a normal situation. 1856 * When this happens, simulate a descriptor with 1857 * minimum rights, so that a real descriptor can 1858 * be created by chown or chmod 1859 */ 1860 ntfs_log_error("No security descriptor found for inode %lld\n", 1861 (long long)ni->mft_no); 1862 securattr = ntfs_build_descr(0, 0, adminsid, adminsid); 1863 } 1864 return (securattr); 1865 } 1866 1867 #if POSIXACLS 1868 1869 /* 1870 * Determine which access types to a file are allowed 1871 * according to the relation of current process to the file 1872 * 1873 * Do not call if default_permissions is set 1874 */ 1875 1876 static int access_check_posix(struct SECURITY_CONTEXT *scx, 1877 struct POSIX_SECURITY *pxdesc, mode_t request, 1878 uid_t uid, gid_t gid) 1879 { 1880 struct POSIX_ACE *pxace; 1881 int userperms; 1882 int groupperms; 1883 int mask; 1884 BOOL somegroup; 1885 BOOL needgroups; 1886 mode_t perms; 1887 int i; 1888 1889 perms = pxdesc->mode; 1890 /* owner and root access */ 1891 if (!scx->uid || (uid == scx->uid)) { 1892 if (!scx->uid) { 1893 /* root access if owner or other execution */ 1894 if (perms & 0101) 1895 perms |= 01777; 1896 else { 1897 /* root access if some group execution */ 1898 groupperms = 0; 1899 mask = 7; 1900 for (i=pxdesc->acccnt-1; i>=0 ; i--) { 1901 pxace = &pxdesc->acl.ace[i]; 1902 switch (pxace->tag) { 1903 case POSIX_ACL_USER_OBJ : 1904 case POSIX_ACL_GROUP_OBJ : 1905 case POSIX_ACL_GROUP : 1906 groupperms |= pxace->perms; 1907 break; 1908 case POSIX_ACL_MASK : 1909 mask = pxace->perms & 7; 1910 break; 1911 default : 1912 break; 1913 } 1914 } 1915 perms = (groupperms & mask & 1) | 6; 1916 } 1917 } else 1918 perms &= 07700; 1919 } else { 1920 /* 1921 * analyze designated users, get mask 1922 * and identify whether we need to check 1923 * the group memberships. The groups are 1924 * not needed when all groups have the 1925 * same permissions as other for the 1926 * requested modes. 1927 */ 1928 userperms = -1; 1929 groupperms = -1; 1930 needgroups = FALSE; 1931 mask = 7; 1932 for (i=pxdesc->acccnt-1; i>=0 ; i--) { 1933 pxace = &pxdesc->acl.ace[i]; 1934 switch (pxace->tag) { 1935 case POSIX_ACL_USER : 1936 if ((uid_t)pxace->id == scx->uid) 1937 userperms = pxace->perms; 1938 break; 1939 case POSIX_ACL_MASK : 1940 mask = pxace->perms & 7; 1941 break; 1942 case POSIX_ACL_GROUP_OBJ : 1943 case POSIX_ACL_GROUP : 1944 if (((pxace->perms & mask) ^ perms) 1945 & (request >> 6) & 7) 1946 needgroups = TRUE; 1947 break; 1948 default : 1949 break; 1950 } 1951 } 1952 /* designated users */ 1953 if (userperms >= 0) 1954 perms = (perms & 07000) + (userperms & mask); 1955 else if (!needgroups) 1956 perms &= 07007; 1957 else { 1958 /* owning group */ 1959 if (!(~(perms >> 3) & request & mask) 1960 && ((gid == scx->gid) 1961 || groupmember(scx, scx->uid, gid))) 1962 perms &= 07070; 1963 else { 1964 /* other groups */ 1965 groupperms = -1; 1966 somegroup = FALSE; 1967 for (i=pxdesc->acccnt-1; i>=0 ; i--) { 1968 pxace = &pxdesc->acl.ace[i]; 1969 if ((pxace->tag == POSIX_ACL_GROUP) 1970 && groupmember(scx, uid, pxace->id)) { 1971 if (!(~pxace->perms & request & mask)) 1972 groupperms = pxace->perms; 1973 somegroup = TRUE; 1974 } 1975 } 1976 if (groupperms >= 0) 1977 perms = (perms & 07000) + (groupperms & mask); 1978 else 1979 if (somegroup) 1980 perms = 0; 1981 else 1982 perms &= 07007; 1983 } 1984 } 1985 } 1986 return (perms); 1987 } 1988 1989 /* 1990 * Get permissions to access a file 1991 * Takes into account the relation of user to file (owner, group, ...) 1992 * Do no use as mode of the file 1993 * Do no call if default_permissions is set 1994 * 1995 * returns -1 if there is a problem 1996 */ 1997 1998 static int ntfs_get_perm(struct SECURITY_CONTEXT *scx, 1999 ntfs_inode * ni, mode_t request) 2000 { 2001 const SECURITY_DESCRIPTOR_RELATIVE *phead; 2002 const struct CACHED_PERMISSIONS *cached; 2003 char *securattr; 2004 const SID *usid; /* owner of file/directory */ 2005 const SID *gsid; /* group of file/directory */ 2006 uid_t uid; 2007 gid_t gid; 2008 int perm; 2009 BOOL isdir; 2010 struct POSIX_SECURITY *pxdesc; 2011 2012 if (!scx->mapping[MAPUSERS]) 2013 perm = 07777; 2014 else { 2015 /* check whether available in cache */ 2016 cached = fetch_cache(scx,ni); 2017 if (cached) { 2018 uid = cached->uid; 2019 gid = cached->gid; 2020 perm = access_check_posix(scx,cached->pxdesc,request,uid,gid); 2021 } else { 2022 perm = 0; /* default to no permission */ 2023 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) 2024 != const_cpu_to_le16(0); 2025 securattr = getsecurityattr(scx->vol, ni); 2026 if (securattr) { 2027 phead = (const SECURITY_DESCRIPTOR_RELATIVE*) 2028 securattr; 2029 gsid = (const SID*)& 2030 securattr[le32_to_cpu(phead->group)]; 2031 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); 2032 #if OWNERFROMACL 2033 usid = ntfs_acl_owner(securattr); 2034 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr, 2035 usid, gsid, isdir); 2036 if (pxdesc) 2037 perm = pxdesc->mode & 07777; 2038 else 2039 perm = -1; 2040 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 2041 #else 2042 usid = (const SID*)& 2043 securattr[le32_to_cpu(phead->owner)]; 2044 pxdesc = ntfs_build_permissions_posix(scx,securattr, 2045 usid, gsid, isdir); 2046 if (pxdesc) 2047 perm = pxdesc->mode & 07777; 2048 else 2049 perm = -1; 2050 if (!perm && ntfs_same_sid(usid, adminsid)) { 2051 uid = find_tenant(scx, securattr); 2052 if (uid) 2053 perm = 0700; 2054 } else 2055 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 2056 #endif 2057 /* 2058 * Create a security id if there were none 2059 * and upgrade option is selected 2060 */ 2061 if (!test_nino_flag(ni, v3_Extensions) 2062 && (perm >= 0) 2063 && (scx->vol->secure_flags 2064 & (1 << SECURITY_ADDSECURIDS))) { 2065 upgrade_secur_desc(scx->vol, 2066 securattr, ni); 2067 /* 2068 * fetch owner and group for cacheing 2069 * if there is a securid 2070 */ 2071 } 2072 if (test_nino_flag(ni, v3_Extensions) 2073 && (perm >= 0)) { 2074 enter_cache(scx, ni, uid, 2075 gid, pxdesc); 2076 } 2077 if (pxdesc) { 2078 perm = access_check_posix(scx,pxdesc,request,uid,gid); 2079 free(pxdesc); 2080 } 2081 free(securattr); 2082 } else { 2083 perm = -1; 2084 uid = gid = 0; 2085 } 2086 } 2087 } 2088 return (perm); 2089 } 2090 2091 /* 2092 * Get a Posix ACL 2093 * 2094 * returns size or -errno if there is a problem 2095 * if size was too small, no copy is done and errno is not set, 2096 * the caller is expected to issue a new call 2097 */ 2098 2099 int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, 2100 const char *name, char *value, size_t size) 2101 { 2102 const SECURITY_DESCRIPTOR_RELATIVE *phead; 2103 struct POSIX_SECURITY *pxdesc; 2104 const struct CACHED_PERMISSIONS *cached; 2105 char *securattr; 2106 const SID *usid; /* owner of file/directory */ 2107 const SID *gsid; /* group of file/directory */ 2108 uid_t uid; 2109 gid_t gid; 2110 BOOL isdir; 2111 size_t outsize; 2112 2113 outsize = 0; /* default to error */ 2114 if (!scx->mapping[MAPUSERS]) 2115 errno = ENOTSUP; 2116 else { 2117 /* check whether available in cache */ 2118 cached = fetch_cache(scx,ni); 2119 if (cached) 2120 pxdesc = cached->pxdesc; 2121 else { 2122 securattr = getsecurityattr(scx->vol, ni); 2123 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) 2124 != const_cpu_to_le16(0); 2125 if (securattr) { 2126 phead = 2127 (const SECURITY_DESCRIPTOR_RELATIVE*) 2128 securattr; 2129 gsid = (const SID*)& 2130 securattr[le32_to_cpu(phead->group)]; 2131 #if OWNERFROMACL 2132 usid = ntfs_acl_owner(securattr); 2133 #else 2134 usid = (const SID*)& 2135 securattr[le32_to_cpu(phead->owner)]; 2136 #endif 2137 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr, 2138 usid, gsid, isdir); 2139 2140 /* 2141 * fetch owner and group for cacheing 2142 */ 2143 if (pxdesc) { 2144 /* 2145 * Create a security id if there were none 2146 * and upgrade option is selected 2147 */ 2148 if (!test_nino_flag(ni, v3_Extensions) 2149 && (scx->vol->secure_flags 2150 & (1 << SECURITY_ADDSECURIDS))) { 2151 upgrade_secur_desc(scx->vol, 2152 securattr, ni); 2153 } 2154 #if OWNERFROMACL 2155 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 2156 #else 2157 if (!(pxdesc->mode & 07777) 2158 && ntfs_same_sid(usid, adminsid)) { 2159 uid = find_tenant(scx, 2160 securattr); 2161 } else 2162 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 2163 #endif 2164 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); 2165 if (pxdesc->tagsset & POSIX_ACL_EXTENSIONS) 2166 enter_cache(scx, ni, uid, 2167 gid, pxdesc); 2168 } 2169 free(securattr); 2170 } else 2171 pxdesc = (struct POSIX_SECURITY*)NULL; 2172 } 2173 2174 if (pxdesc) { 2175 if (ntfs_valid_posix(pxdesc)) { 2176 if (!strcmp(name,"system.posix_acl_default")) { 2177 if (ni->mrec->flags 2178 & MFT_RECORD_IS_DIRECTORY) 2179 outsize = sizeof(struct POSIX_ACL) 2180 + pxdesc->defcnt*sizeof(struct POSIX_ACE); 2181 else { 2182 /* 2183 * getting default ACL from plain file : 2184 * return EACCES if size > 0 as 2185 * indicated in the man, but return ok 2186 * if size == 0, so that ls does not 2187 * display an error 2188 */ 2189 if (size > 0) { 2190 outsize = 0; 2191 errno = EACCES; 2192 } else 2193 outsize = sizeof(struct POSIX_ACL); 2194 } 2195 if (outsize && (outsize <= size)) { 2196 memcpy(value,&pxdesc->acl,sizeof(struct POSIX_ACL)); 2197 memcpy(&value[sizeof(struct POSIX_ACL)], 2198 &pxdesc->acl.ace[pxdesc->firstdef], 2199 outsize-sizeof(struct POSIX_ACL)); 2200 } 2201 } else { 2202 outsize = sizeof(struct POSIX_ACL) 2203 + pxdesc->acccnt*sizeof(struct POSIX_ACE); 2204 if (outsize <= size) 2205 memcpy(value,&pxdesc->acl,outsize); 2206 } 2207 } else { 2208 outsize = 0; 2209 errno = EIO; 2210 ntfs_log_error("Invalid Posix ACL built\n"); 2211 } 2212 if (!cached) 2213 free(pxdesc); 2214 } else 2215 outsize = 0; 2216 } 2217 return (outsize ? (int)outsize : -errno); 2218 } 2219 2220 #else /* POSIXACLS */ 2221 2222 2223 /* 2224 * Get permissions to access a file 2225 * Takes into account the relation of user to file (owner, group, ...) 2226 * Do no use as mode of the file 2227 * 2228 * returns -1 if there is a problem 2229 */ 2230 2231 static int ntfs_get_perm(struct SECURITY_CONTEXT *scx, 2232 ntfs_inode *ni, mode_t request) 2233 { 2234 const SECURITY_DESCRIPTOR_RELATIVE *phead; 2235 const struct CACHED_PERMISSIONS *cached; 2236 char *securattr; 2237 const SID *usid; /* owner of file/directory */ 2238 const SID *gsid; /* group of file/directory */ 2239 BOOL isdir; 2240 uid_t uid; 2241 gid_t gid; 2242 int perm; 2243 2244 if (!scx->mapping[MAPUSERS] || (!scx->uid && !(request & S_IEXEC))) 2245 perm = 07777; 2246 else { 2247 /* check whether available in cache */ 2248 cached = fetch_cache(scx,ni); 2249 if (cached) { 2250 perm = cached->mode; 2251 uid = cached->uid; 2252 gid = cached->gid; 2253 } else { 2254 perm = 0; /* default to no permission */ 2255 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) 2256 != const_cpu_to_le16(0); 2257 securattr = getsecurityattr(scx->vol, ni); 2258 if (securattr) { 2259 phead = (const SECURITY_DESCRIPTOR_RELATIVE*) 2260 securattr; 2261 gsid = (const SID*)& 2262 securattr[le32_to_cpu(phead->group)]; 2263 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); 2264 #if OWNERFROMACL 2265 usid = ntfs_acl_owner(securattr); 2266 perm = ntfs_build_permissions(securattr, 2267 usid, gsid, isdir); 2268 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 2269 #else 2270 usid = (const SID*)& 2271 securattr[le32_to_cpu(phead->owner)]; 2272 perm = ntfs_build_permissions(securattr, 2273 usid, gsid, isdir); 2274 if (!perm && ntfs_same_sid(usid, adminsid)) { 2275 uid = find_tenant(scx, securattr); 2276 if (uid) 2277 perm = 0700; 2278 } else 2279 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 2280 #endif 2281 /* 2282 * Create a security id if there were none 2283 * and upgrade option is selected 2284 */ 2285 if (!test_nino_flag(ni, v3_Extensions) 2286 && (perm >= 0) 2287 && (scx->vol->secure_flags 2288 & (1 << SECURITY_ADDSECURIDS))) { 2289 upgrade_secur_desc(scx->vol, 2290 securattr, ni); 2291 /* 2292 * fetch owner and group for cacheing 2293 * if there is a securid 2294 */ 2295 } 2296 if (test_nino_flag(ni, v3_Extensions) 2297 && (perm >= 0)) { 2298 enter_cache(scx, ni, uid, 2299 gid, perm); 2300 } 2301 free(securattr); 2302 } else { 2303 perm = -1; 2304 uid = gid = 0; 2305 } 2306 } 2307 if (perm >= 0) { 2308 if (!scx->uid) { 2309 /* root access and execution */ 2310 if (perm & 0111) 2311 perm |= 01777; 2312 else 2313 perm = 0; 2314 } else 2315 if (uid == scx->uid) 2316 perm &= 07700; 2317 else 2318 /* 2319 * avoid checking group membership 2320 * when the requested perms for group 2321 * are the same as perms for other 2322 */ 2323 if ((gid == scx->gid) 2324 || ((((perm >> 3) ^ perm) 2325 & (request >> 6) & 7) 2326 && groupmember(scx, scx->uid, gid))) 2327 perm &= 07070; 2328 else 2329 perm &= 07007; 2330 } 2331 } 2332 return (perm); 2333 } 2334 2335 #endif /* POSIXACLS */ 2336 2337 /* 2338 * Get an NTFS ACL 2339 * 2340 * Returns size or -errno if there is a problem 2341 * if size was too small, no copy is done and errno is not set, 2342 * the caller is expected to issue a new call 2343 */ 2344 2345 int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, 2346 char *value, size_t size) 2347 { 2348 char *securattr; 2349 size_t outsize; 2350 2351 outsize = 0; /* default to no data and no error */ 2352 securattr = getsecurityattr(scx->vol, ni); 2353 if (securattr) { 2354 outsize = ntfs_attr_size(securattr); 2355 if (outsize <= size) { 2356 memcpy(value,securattr,outsize); 2357 } 2358 free(securattr); 2359 } 2360 return (outsize ? (int)outsize : -errno); 2361 } 2362 2363 /* 2364 * Get owner, group and permissions in an stat structure 2365 * returns permissions, or -1 if there is a problem 2366 */ 2367 2368 int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx, 2369 ntfs_inode * ni, struct stat *stbuf) 2370 { 2371 const SECURITY_DESCRIPTOR_RELATIVE *phead; 2372 char *securattr; 2373 const SID *usid; /* owner of file/directory */ 2374 const SID *gsid; /* group of file/directory */ 2375 const struct CACHED_PERMISSIONS *cached; 2376 int perm; 2377 BOOL isdir; 2378 #if POSIXACLS 2379 struct POSIX_SECURITY *pxdesc; 2380 #endif 2381 2382 if (!scx->mapping[MAPUSERS]) 2383 perm = 07777; 2384 else { 2385 /* check whether available in cache */ 2386 cached = fetch_cache(scx,ni); 2387 if (cached) { 2388 perm = cached->mode; 2389 stbuf->st_uid = cached->uid; 2390 stbuf->st_gid = cached->gid; 2391 stbuf->st_mode = (stbuf->st_mode & ~07777) + perm; 2392 } else { 2393 perm = -1; /* default to error */ 2394 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) 2395 != const_cpu_to_le16(0); 2396 securattr = getsecurityattr(scx->vol, ni); 2397 if (securattr) { 2398 phead = 2399 (const SECURITY_DESCRIPTOR_RELATIVE*) 2400 securattr; 2401 gsid = (const SID*)& 2402 securattr[le32_to_cpu(phead->group)]; 2403 #if OWNERFROMACL 2404 usid = ntfs_acl_owner(securattr); 2405 #else 2406 usid = (const SID*)& 2407 securattr[le32_to_cpu(phead->owner)]; 2408 #endif 2409 #if POSIXACLS 2410 pxdesc = ntfs_build_permissions_posix(scx->mapping, securattr, 2411 usid, gsid, isdir); 2412 if (pxdesc) 2413 perm = pxdesc->mode & 07777; 2414 else 2415 perm = -1; 2416 #else 2417 perm = ntfs_build_permissions(securattr, 2418 usid, gsid, isdir); 2419 #endif 2420 /* 2421 * fetch owner and group for cacheing 2422 */ 2423 if (perm >= 0) { 2424 /* 2425 * Create a security id if there were none 2426 * and upgrade option is selected 2427 */ 2428 if (!test_nino_flag(ni, v3_Extensions) 2429 && (scx->vol->secure_flags 2430 & (1 << SECURITY_ADDSECURIDS))) { 2431 upgrade_secur_desc(scx->vol, 2432 securattr, ni); 2433 } 2434 #if OWNERFROMACL 2435 stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 2436 #else 2437 if (!perm && ntfs_same_sid(usid, adminsid)) { 2438 stbuf->st_uid = 2439 find_tenant(scx, 2440 securattr); 2441 if (stbuf->st_uid) 2442 perm = 0700; 2443 } else 2444 stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 2445 #endif 2446 stbuf->st_gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); 2447 stbuf->st_mode = 2448 (stbuf->st_mode & ~07777) + perm; 2449 #if POSIXACLS 2450 enter_cache(scx, ni, stbuf->st_uid, 2451 stbuf->st_gid, pxdesc); 2452 free(pxdesc); 2453 #else 2454 enter_cache(scx, ni, stbuf->st_uid, 2455 stbuf->st_gid, perm); 2456 #endif 2457 } 2458 free(securattr); 2459 } 2460 } 2461 } 2462 return (perm); 2463 } 2464 2465 #if POSIXACLS 2466 2467 /* 2468 * Get the base for a Posix inheritance and 2469 * build an inherited Posix descriptor 2470 */ 2471 2472 static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx, 2473 ntfs_inode *dir_ni, mode_t mode, BOOL isdir) 2474 { 2475 const struct CACHED_PERMISSIONS *cached; 2476 const SECURITY_DESCRIPTOR_RELATIVE *phead; 2477 struct POSIX_SECURITY *pxdesc; 2478 struct POSIX_SECURITY *pydesc; 2479 char *securattr; 2480 const SID *usid; 2481 const SID *gsid; 2482 uid_t uid; 2483 gid_t gid; 2484 2485 pydesc = (struct POSIX_SECURITY*)NULL; 2486 /* check whether parent directory is available in cache */ 2487 cached = fetch_cache(scx,dir_ni); 2488 if (cached) { 2489 uid = cached->uid; 2490 gid = cached->gid; 2491 pxdesc = cached->pxdesc; 2492 if (pxdesc) { 2493 pydesc = ntfs_build_inherited_posix(pxdesc,mode, 2494 scx->umask,isdir); 2495 } 2496 } else { 2497 securattr = getsecurityattr(scx->vol, dir_ni); 2498 if (securattr) { 2499 phead = (const SECURITY_DESCRIPTOR_RELATIVE*) 2500 securattr; 2501 gsid = (const SID*)& 2502 securattr[le32_to_cpu(phead->group)]; 2503 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); 2504 #if OWNERFROMACL 2505 usid = ntfs_acl_owner(securattr); 2506 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr, 2507 usid, gsid, TRUE); 2508 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 2509 #else 2510 usid = (const SID*)& 2511 securattr[le32_to_cpu(phead->owner)]; 2512 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr, 2513 usid, gsid, TRUE); 2514 if (pxdesc && ntfs_same_sid(usid, adminsid)) { 2515 uid = find_tenant(scx, securattr); 2516 } else 2517 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 2518 #endif 2519 if (pxdesc) { 2520 /* 2521 * Create a security id if there were none 2522 * and upgrade option is selected 2523 */ 2524 if (!test_nino_flag(dir_ni, v3_Extensions) 2525 && (scx->vol->secure_flags 2526 & (1 << SECURITY_ADDSECURIDS))) { 2527 upgrade_secur_desc(scx->vol, 2528 securattr, dir_ni); 2529 /* 2530 * fetch owner and group for cacheing 2531 * if there is a securid 2532 */ 2533 } 2534 if (test_nino_flag(dir_ni, v3_Extensions)) { 2535 enter_cache(scx, dir_ni, uid, 2536 gid, pxdesc); 2537 } 2538 pydesc = ntfs_build_inherited_posix(pxdesc, 2539 mode, scx->umask, isdir); 2540 free(pxdesc); 2541 } 2542 free(securattr); 2543 } 2544 } 2545 return (pydesc); 2546 } 2547 2548 /* 2549 * Allocate a security_id for a file being created 2550 * 2551 * Returns zero if not possible (NTFS v3.x required) 2552 */ 2553 2554 le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx, 2555 uid_t uid, gid_t gid, ntfs_inode *dir_ni, 2556 mode_t mode, BOOL isdir) 2557 { 2558 #if !FORCE_FORMAT_v1x 2559 const struct CACHED_SECURID *cached; 2560 struct CACHED_SECURID wanted; 2561 struct POSIX_SECURITY *pxdesc; 2562 char *newattr; 2563 int newattrsz; 2564 const SID *usid; 2565 const SID *gsid; 2566 BIGSID defusid; 2567 BIGSID defgsid; 2568 le32 securid; 2569 #endif 2570 2571 securid = const_cpu_to_le32(0); 2572 2573 #if !FORCE_FORMAT_v1x 2574 2575 pxdesc = inherit_posix(scx, dir_ni, mode, isdir); 2576 if (pxdesc) { 2577 /* check whether target securid is known in cache */ 2578 2579 wanted.uid = uid; 2580 wanted.gid = gid; 2581 wanted.dmode = pxdesc->mode & mode & 07777; 2582 if (isdir) wanted.dmode |= 0x10000; 2583 wanted.variable = (void*)pxdesc; 2584 wanted.varsize = sizeof(struct POSIX_SECURITY) 2585 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); 2586 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache( 2587 scx->vol->securid_cache, GENERIC(&wanted), 2588 (cache_compare)compare); 2589 /* quite simple, if we are lucky */ 2590 if (cached) 2591 securid = cached->securid; 2592 2593 /* not in cache : make sure we can create ids */ 2594 2595 if (!cached && (scx->vol->major_ver >= 3)) { 2596 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid); 2597 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid); 2598 if (!usid || !gsid) { 2599 ntfs_log_error("File created by an unmapped user/group %d/%d\n", 2600 (int)uid, (int)gid); 2601 usid = gsid = adminsid; 2602 } 2603 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc, 2604 isdir, usid, gsid); 2605 if (newattr) { 2606 newattrsz = ntfs_attr_size(newattr); 2607 securid = setsecurityattr(scx->vol, 2608 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr, 2609 newattrsz); 2610 if (securid) { 2611 /* update cache, for subsequent use */ 2612 wanted.securid = securid; 2613 ntfs_enter_cache(scx->vol->securid_cache, 2614 GENERIC(&wanted), 2615 (cache_compare)compare); 2616 } 2617 free(newattr); 2618 } else { 2619 /* 2620 * could not build new security attribute 2621 * errno set by ntfs_build_descr() 2622 */ 2623 } 2624 } 2625 free(pxdesc); 2626 } 2627 #endif 2628 return (securid); 2629 } 2630 2631 /* 2632 * Apply Posix inheritance to a newly created file 2633 * (for NTFS 1.x only : no securid) 2634 */ 2635 2636 int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx, 2637 ntfs_inode *ni, uid_t uid, gid_t gid, 2638 ntfs_inode *dir_ni, mode_t mode) 2639 { 2640 struct POSIX_SECURITY *pxdesc; 2641 char *newattr; 2642 const SID *usid; 2643 const SID *gsid; 2644 BIGSID defusid; 2645 BIGSID defgsid; 2646 BOOL isdir; 2647 int res; 2648 2649 res = -1; 2650 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); 2651 pxdesc = inherit_posix(scx, dir_ni, mode, isdir); 2652 if (pxdesc) { 2653 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid); 2654 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid); 2655 if (!usid || !gsid) { 2656 ntfs_log_error("File created by an unmapped user/group %d/%d\n", 2657 (int)uid, (int)gid); 2658 usid = gsid = adminsid; 2659 } 2660 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc, 2661 isdir, usid, gsid); 2662 if (newattr) { 2663 /* Adjust Windows read-only flag */ 2664 res = update_secur_descr(scx->vol, newattr, ni); 2665 if (!res && !isdir) { 2666 if (mode & S_IWUSR) 2667 ni->flags &= ~FILE_ATTR_READONLY; 2668 else 2669 ni->flags |= FILE_ATTR_READONLY; 2670 } 2671 #if CACHE_LEGACY_SIZE 2672 /* also invalidate legacy cache */ 2673 if (isdir && !ni->security_id) { 2674 struct CACHED_PERMISSIONS_LEGACY legacy; 2675 2676 legacy.mft_no = ni->mft_no; 2677 legacy.variable = pxdesc; 2678 legacy.varsize = sizeof(struct POSIX_SECURITY) 2679 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); 2680 ntfs_invalidate_cache(scx->vol->legacy_cache, 2681 GENERIC(&legacy), 2682 (cache_compare)leg_compare,0); 2683 } 2684 #endif 2685 free(newattr); 2686 2687 } else { 2688 /* 2689 * could not build new security attribute 2690 * errno set by ntfs_build_descr() 2691 */ 2692 } 2693 } 2694 return (res); 2695 } 2696 2697 #else 2698 2699 le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx, 2700 uid_t uid, gid_t gid, mode_t mode, BOOL isdir) 2701 { 2702 #if !FORCE_FORMAT_v1x 2703 const struct CACHED_SECURID *cached; 2704 struct CACHED_SECURID wanted; 2705 char *newattr; 2706 int newattrsz; 2707 const SID *usid; 2708 const SID *gsid; 2709 BIGSID defusid; 2710 BIGSID defgsid; 2711 le32 securid; 2712 #endif 2713 2714 securid = const_cpu_to_le32(0); 2715 2716 #if !FORCE_FORMAT_v1x 2717 /* check whether target securid is known in cache */ 2718 2719 wanted.uid = uid; 2720 wanted.gid = gid; 2721 wanted.dmode = mode & 07777; 2722 if (isdir) wanted.dmode |= 0x10000; 2723 wanted.variable = (void*)NULL; 2724 wanted.varsize = 0; 2725 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache( 2726 scx->vol->securid_cache, GENERIC(&wanted), 2727 (cache_compare)compare); 2728 /* quite simple, if we are lucky */ 2729 if (cached) 2730 securid = cached->securid; 2731 2732 /* not in cache : make sure we can create ids */ 2733 2734 if (!cached && (scx->vol->major_ver >= 3)) { 2735 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid); 2736 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid); 2737 if (!usid || !gsid) { 2738 ntfs_log_error("File created by an unmapped user/group %d/%d\n", 2739 (int)uid, (int)gid); 2740 usid = gsid = adminsid; 2741 } 2742 newattr = ntfs_build_descr(mode, isdir, usid, gsid); 2743 if (newattr) { 2744 newattrsz = ntfs_attr_size(newattr); 2745 securid = setsecurityattr(scx->vol, 2746 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr, 2747 newattrsz); 2748 if (securid) { 2749 /* update cache, for subsequent use */ 2750 wanted.securid = securid; 2751 ntfs_enter_cache(scx->vol->securid_cache, 2752 GENERIC(&wanted), 2753 (cache_compare)compare); 2754 } 2755 free(newattr); 2756 } else { 2757 /* 2758 * could not build new security attribute 2759 * errno set by ntfs_build_descr() 2760 */ 2761 } 2762 } 2763 #endif 2764 return (securid); 2765 } 2766 2767 #endif 2768 2769 /* 2770 * Update ownership and mode of a file, reusing an existing 2771 * security descriptor when possible 2772 * 2773 * Returns zero if successful 2774 */ 2775 2776 #if POSIXACLS 2777 int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, 2778 uid_t uid, gid_t gid, mode_t mode, 2779 struct POSIX_SECURITY *pxdesc) 2780 #else 2781 int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, 2782 uid_t uid, gid_t gid, mode_t mode) 2783 #endif 2784 { 2785 int res; 2786 const struct CACHED_SECURID *cached; 2787 struct CACHED_SECURID wanted; 2788 char *newattr; 2789 const SID *usid; 2790 const SID *gsid; 2791 BIGSID defusid; 2792 BIGSID defgsid; 2793 BOOL isdir; 2794 2795 res = 0; 2796 2797 /* check whether target securid is known in cache */ 2798 2799 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); 2800 wanted.uid = uid; 2801 wanted.gid = gid; 2802 wanted.dmode = mode & 07777; 2803 if (isdir) wanted.dmode |= 0x10000; 2804 #if POSIXACLS 2805 wanted.variable = (void*)pxdesc; 2806 if (pxdesc) 2807 wanted.varsize = sizeof(struct POSIX_SECURITY) 2808 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); 2809 else 2810 wanted.varsize = 0; 2811 #else 2812 wanted.variable = (void*)NULL; 2813 wanted.varsize = 0; 2814 #endif 2815 if (test_nino_flag(ni, v3_Extensions)) { 2816 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache( 2817 scx->vol->securid_cache, GENERIC(&wanted), 2818 (cache_compare)compare); 2819 /* quite simple, if we are lucky */ 2820 if (cached) { 2821 ni->security_id = cached->securid; 2822 NInoSetDirty(ni); 2823 } 2824 } else cached = (struct CACHED_SECURID*)NULL; 2825 2826 if (!cached) { 2827 /* 2828 * Do not use usid and gsid from former attributes, 2829 * but recompute them to get repeatable results 2830 * which can be kept in cache. 2831 */ 2832 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid); 2833 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid); 2834 if (!usid || !gsid) { 2835 ntfs_log_error("File made owned by an unmapped user/group %d/%d\n", 2836 uid, gid); 2837 usid = gsid = adminsid; 2838 } 2839 #if POSIXACLS 2840 if (pxdesc) 2841 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc, 2842 isdir, usid, gsid); 2843 else 2844 newattr = ntfs_build_descr(mode, 2845 isdir, usid, gsid); 2846 #else 2847 newattr = ntfs_build_descr(mode, 2848 isdir, usid, gsid); 2849 #endif 2850 if (newattr) { 2851 res = update_secur_descr(scx->vol, newattr, ni); 2852 if (!res) { 2853 /* adjust Windows read-only flag */ 2854 if (!isdir) { 2855 if (mode & S_IWUSR) 2856 ni->flags &= ~FILE_ATTR_READONLY; 2857 else 2858 ni->flags |= FILE_ATTR_READONLY; 2859 NInoFileNameSetDirty(ni); 2860 } 2861 /* update cache, for subsequent use */ 2862 if (test_nino_flag(ni, v3_Extensions)) { 2863 wanted.securid = ni->security_id; 2864 ntfs_enter_cache(scx->vol->securid_cache, 2865 GENERIC(&wanted), 2866 (cache_compare)compare); 2867 } 2868 #if CACHE_LEGACY_SIZE 2869 /* also invalidate legacy cache */ 2870 if (isdir && !ni->security_id) { 2871 struct CACHED_PERMISSIONS_LEGACY legacy; 2872 2873 legacy.mft_no = ni->mft_no; 2874 #if POSIXACLS 2875 legacy.variable = wanted.variable; 2876 legacy.varsize = wanted.varsize; 2877 #else 2878 legacy.variable = (void*)NULL; 2879 legacy.varsize = 0; 2880 #endif 2881 ntfs_invalidate_cache(scx->vol->legacy_cache, 2882 GENERIC(&legacy), 2883 (cache_compare)leg_compare,0); 2884 } 2885 #endif 2886 } 2887 free(newattr); 2888 } else { 2889 /* 2890 * could not build new security attribute 2891 * errno set by ntfs_build_descr() 2892 */ 2893 res = -1; 2894 } 2895 } 2896 return (res); 2897 } 2898 2899 /* 2900 * Check whether user has ownership rights on a file 2901 * 2902 * Returns TRUE if allowed 2903 * if not, errno tells why 2904 */ 2905 2906 BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni) 2907 { 2908 const struct CACHED_PERMISSIONS *cached; 2909 char *oldattr; 2910 const SID *usid; 2911 uid_t processuid; 2912 uid_t uid; 2913 BOOL gotowner; 2914 int allowed; 2915 2916 processuid = scx->uid; 2917 /* TODO : use CAP_FOWNER process capability */ 2918 /* 2919 * Always allow for root 2920 * Also always allow if no mapping has been defined 2921 */ 2922 if (!scx->mapping[MAPUSERS] || !processuid) 2923 allowed = TRUE; 2924 else { 2925 gotowner = FALSE; /* default */ 2926 /* get the owner, either from cache or from old attribute */ 2927 cached = fetch_cache(scx, ni); 2928 if (cached) { 2929 uid = cached->uid; 2930 gotowner = TRUE; 2931 } else { 2932 oldattr = getsecurityattr(scx->vol, ni); 2933 if (oldattr) { 2934 #if OWNERFROMACL 2935 usid = ntfs_acl_owner(oldattr); 2936 #else 2937 const SECURITY_DESCRIPTOR_RELATIVE *phead; 2938 2939 phead = (const SECURITY_DESCRIPTOR_RELATIVE*) 2940 oldattr; 2941 usid = (const SID*)&oldattr 2942 [le32_to_cpu(phead->owner)]; 2943 #endif 2944 uid = ntfs_find_user(scx->mapping[MAPUSERS], 2945 usid); 2946 gotowner = TRUE; 2947 free(oldattr); 2948 } 2949 } 2950 allowed = FALSE; 2951 if (gotowner) { 2952 /* TODO : use CAP_FOWNER process capability */ 2953 if (!processuid || (processuid == uid)) 2954 allowed = TRUE; 2955 else 2956 errno = EPERM; 2957 } 2958 } 2959 return (allowed); 2960 } 2961 2962 #ifdef HAVE_SETXATTR /* extended attributes interface required */ 2963 2964 #if POSIXACLS 2965 2966 /* 2967 * Set a new access or default Posix ACL to a file 2968 * (or remove ACL if no input data) 2969 * Validity of input data is checked after merging 2970 * 2971 * Returns 0, or -1 if there is a problem which errno describes 2972 */ 2973 2974 int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, 2975 const char *name, const char *value, size_t size, 2976 int flags) 2977 { 2978 const SECURITY_DESCRIPTOR_RELATIVE *phead; 2979 const struct CACHED_PERMISSIONS *cached; 2980 char *oldattr; 2981 uid_t processuid; 2982 const SID *usid; 2983 const SID *gsid; 2984 uid_t uid; 2985 uid_t gid; 2986 int res; 2987 BOOL isdir; 2988 BOOL deflt; 2989 BOOL exist; 2990 int count; 2991 struct POSIX_SECURITY *oldpxdesc; 2992 struct POSIX_SECURITY *newpxdesc; 2993 2994 /* get the current pxsec, either from cache or from old attribute */ 2995 res = -1; 2996 deflt = !strcmp(name,"system.posix_acl_default"); 2997 if (size) 2998 count = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE); 2999 else 3000 count = 0; 3001 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); 3002 newpxdesc = (struct POSIX_SECURITY*)NULL; 3003 if ((!value 3004 || (((const struct POSIX_ACL*)value)->version == POSIX_VERSION)) 3005 && (!deflt || isdir || (!size && !value))) { 3006 cached = fetch_cache(scx, ni); 3007 if (cached) { 3008 uid = cached->uid; 3009 gid = cached->gid; 3010 oldpxdesc = cached->pxdesc; 3011 if (oldpxdesc) { 3012 newpxdesc = ntfs_replace_acl(oldpxdesc, 3013 (const struct POSIX_ACL*)value,count,deflt); 3014 } 3015 } else { 3016 oldattr = getsecurityattr(scx->vol, ni); 3017 if (oldattr) { 3018 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr; 3019 #if OWNERFROMACL 3020 usid = ntfs_acl_owner(oldattr); 3021 #else 3022 usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)]; 3023 #endif 3024 gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)]; 3025 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 3026 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); 3027 oldpxdesc = ntfs_build_permissions_posix(scx->mapping, 3028 oldattr, usid, gsid, isdir); 3029 if (oldpxdesc) { 3030 if (deflt) 3031 exist = oldpxdesc->defcnt > 0; 3032 else 3033 exist = oldpxdesc->acccnt > 3; 3034 if ((exist && (flags & XATTR_CREATE)) 3035 || (!exist && (flags & XATTR_REPLACE))) { 3036 errno = (exist ? EEXIST : ENODATA); 3037 } else { 3038 newpxdesc = ntfs_replace_acl(oldpxdesc, 3039 (const struct POSIX_ACL*)value,count,deflt); 3040 } 3041 free(oldpxdesc); 3042 } 3043 free(oldattr); 3044 } 3045 } 3046 } else 3047 errno = EINVAL; 3048 3049 if (newpxdesc) { 3050 processuid = scx->uid; 3051 /* TODO : use CAP_FOWNER process capability */ 3052 if (!processuid || (uid == processuid)) { 3053 /* 3054 * clear setgid if file group does 3055 * not match process group 3056 */ 3057 if (processuid && (gid != scx->gid) 3058 && !groupmember(scx, scx->uid, gid)) { 3059 newpxdesc->mode &= ~S_ISGID; 3060 } 3061 res = ntfs_set_owner_mode(scx, ni, uid, gid, 3062 newpxdesc->mode, newpxdesc); 3063 } else 3064 errno = EPERM; 3065 free(newpxdesc); 3066 } 3067 return (res ? -1 : 0); 3068 } 3069 3070 /* 3071 * Remove a default Posix ACL from a file 3072 * 3073 * Returns 0, or -1 if there is a problem which errno describes 3074 */ 3075 3076 int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, 3077 const char *name) 3078 { 3079 return (ntfs_set_posix_acl(scx, ni, name, 3080 (const char*)NULL, 0, 0)); 3081 } 3082 3083 #endif 3084 3085 /* 3086 * Set a new NTFS ACL to a file 3087 * 3088 * Returns 0, or -1 if there is a problem 3089 */ 3090 3091 int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, 3092 const char *value, size_t size, int flags) 3093 { 3094 char *attr; 3095 int res; 3096 3097 res = -1; 3098 if ((size > 0) 3099 && !(flags & XATTR_CREATE) 3100 && ntfs_valid_descr(value,size) 3101 && (ntfs_attr_size(value) == size)) { 3102 /* need copying in order to write */ 3103 attr = (char*)ntfs_malloc(size); 3104 if (attr) { 3105 memcpy(attr,value,size); 3106 res = update_secur_descr(scx->vol, attr, ni); 3107 /* 3108 * No need to invalidate standard caches : 3109 * the relation between a securid and 3110 * the associated protection is unchanged, 3111 * only the relation between a file and 3112 * its securid and protection is changed. 3113 */ 3114 #if CACHE_LEGACY_SIZE 3115 /* 3116 * we must however invalidate the legacy 3117 * cache, which is based on inode numbers. 3118 * For safety, invalidate even if updating 3119 * failed. 3120 */ 3121 if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) 3122 && !ni->security_id) { 3123 struct CACHED_PERMISSIONS_LEGACY legacy; 3124 3125 legacy.mft_no = ni->mft_no; 3126 legacy.variable = (char*)NULL; 3127 legacy.varsize = 0; 3128 ntfs_invalidate_cache(scx->vol->legacy_cache, 3129 GENERIC(&legacy), 3130 (cache_compare)leg_compare,0); 3131 } 3132 #endif 3133 free(attr); 3134 } else 3135 errno = ENOMEM; 3136 } else 3137 errno = EINVAL; 3138 return (res ? -1 : 0); 3139 } 3140 3141 #endif /* HAVE_SETXATTR */ 3142 3143 /* 3144 * Set new permissions to a file 3145 * Checks user mapping has been defined before request for setting 3146 * 3147 * rejected if request is not originated by owner or root 3148 * 3149 * returns 0 on success 3150 * -1 on failure, with errno = EIO 3151 */ 3152 3153 int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode) 3154 { 3155 const SECURITY_DESCRIPTOR_RELATIVE *phead; 3156 const struct CACHED_PERMISSIONS *cached; 3157 char *oldattr; 3158 const SID *usid; 3159 const SID *gsid; 3160 uid_t processuid; 3161 uid_t uid; 3162 uid_t gid; 3163 int res; 3164 #if POSIXACLS 3165 BOOL isdir; 3166 int pxsize; 3167 const struct POSIX_SECURITY *oldpxdesc; 3168 struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL; 3169 #endif 3170 3171 /* get the current owner, either from cache or from old attribute */ 3172 res = 0; 3173 cached = fetch_cache(scx, ni); 3174 if (cached) { 3175 uid = cached->uid; 3176 gid = cached->gid; 3177 #if POSIXACLS 3178 oldpxdesc = cached->pxdesc; 3179 if (oldpxdesc) { 3180 /* must copy before merging */ 3181 pxsize = sizeof(struct POSIX_SECURITY) 3182 + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE); 3183 newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize); 3184 if (newpxdesc) { 3185 memcpy(newpxdesc, oldpxdesc, pxsize); 3186 if (ntfs_merge_mode_posix(newpxdesc, mode)) 3187 res = -1; 3188 } else 3189 res = -1; 3190 } else 3191 newpxdesc = (struct POSIX_SECURITY*)NULL; 3192 #endif 3193 } else { 3194 oldattr = getsecurityattr(scx->vol, ni); 3195 if (oldattr) { 3196 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr; 3197 #if OWNERFROMACL 3198 usid = ntfs_acl_owner(oldattr); 3199 #else 3200 usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)]; 3201 #endif 3202 gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)]; 3203 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 3204 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); 3205 #if POSIXACLS 3206 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); 3207 newpxdesc = ntfs_build_permissions_posix(scx->mapping, 3208 oldattr, usid, gsid, isdir); 3209 if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode)) 3210 res = -1; 3211 #endif 3212 free(oldattr); 3213 } else 3214 res = -1; 3215 } 3216 3217 if (!res) { 3218 processuid = scx->uid; 3219 /* TODO : use CAP_FOWNER process capability */ 3220 if (!processuid || (uid == processuid)) { 3221 /* 3222 * clear setgid if file group does 3223 * not match process group 3224 */ 3225 if (processuid && (gid != scx->gid) 3226 && !groupmember(scx, scx->uid, gid)) 3227 mode &= ~S_ISGID; 3228 #if POSIXACLS 3229 if (newpxdesc) { 3230 newpxdesc->mode = mode; 3231 res = ntfs_set_owner_mode(scx, ni, uid, gid, 3232 mode, newpxdesc); 3233 } else 3234 res = ntfs_set_owner_mode(scx, ni, uid, gid, 3235 mode, newpxdesc); 3236 #else 3237 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode); 3238 #endif 3239 } else { 3240 errno = EPERM; 3241 res = -1; /* neither owner nor root */ 3242 } 3243 } else { 3244 /* 3245 * Should not happen : a default descriptor is generated 3246 * by getsecurityattr() when there are none 3247 */ 3248 ntfs_log_error("File has no security descriptor\n"); 3249 res = -1; 3250 errno = EIO; 3251 } 3252 #if POSIXACLS 3253 if (newpxdesc) free(newpxdesc); 3254 #endif 3255 return (res ? -1 : 0); 3256 } 3257 3258 /* 3259 * Create a default security descriptor for files whose descriptor 3260 * cannot be inherited 3261 */ 3262 3263 int ntfs_sd_add_everyone(ntfs_inode *ni) 3264 { 3265 /* JPA SECURITY_DESCRIPTOR_ATTR *sd; */ 3266 SECURITY_DESCRIPTOR_RELATIVE *sd; 3267 ACL *acl; 3268 ACCESS_ALLOWED_ACE *ace; 3269 SID *sid; 3270 int ret, sd_len; 3271 3272 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */ 3273 /* 3274 * Calculate security descriptor length. We have 2 sub-authorities in 3275 * owner and group SIDs, but structure SID contain only one, so add 3276 * 4 bytes to every SID. 3277 */ 3278 sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) + 3279 sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE); 3280 sd = (SECURITY_DESCRIPTOR_RELATIVE*)ntfs_calloc(sd_len); 3281 if (!sd) 3282 return -1; 3283 3284 sd->revision = SECURITY_DESCRIPTOR_REVISION; 3285 sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE; 3286 3287 sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR)); 3288 sid->revision = SID_REVISION; 3289 sid->sub_authority_count = 2; 3290 sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); 3291 sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); 3292 sid->identifier_authority.value[5] = 5; 3293 sd->owner = cpu_to_le32((u8*)sid - (u8*)sd); 3294 3295 sid = (SID*)((u8*)sid + sizeof(SID) + 4); 3296 sid->revision = SID_REVISION; 3297 sid->sub_authority_count = 2; 3298 sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); 3299 sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); 3300 sid->identifier_authority.value[5] = 5; 3301 sd->group = cpu_to_le32((u8*)sid - (u8*)sd); 3302 3303 acl = (ACL*)((u8*)sid + sizeof(SID) + 4); 3304 acl->revision = ACL_REVISION; 3305 acl->size = const_cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)); 3306 acl->ace_count = const_cpu_to_le16(1); 3307 sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd); 3308 3309 ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL)); 3310 ace->type = ACCESS_ALLOWED_ACE_TYPE; 3311 ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; 3312 ace->size = const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE)); 3313 ace->mask = const_cpu_to_le32(0x1f01ff); /* FIXME */ 3314 ace->sid.revision = SID_REVISION; 3315 ace->sid.sub_authority_count = 1; 3316 ace->sid.sub_authority[0] = const_cpu_to_le32(0); 3317 ace->sid.identifier_authority.value[5] = 1; 3318 3319 ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8*)sd, 3320 sd_len); 3321 if (ret) 3322 ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR"); 3323 3324 free(sd); 3325 return ret; 3326 } 3327 3328 /* 3329 * Check whether user can access a file in a specific way 3330 * 3331 * Returns 1 if access is allowed, including user is root or no 3332 * user mapping defined 3333 * 2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX 3334 * 0 and sets errno if there is a problem or if access 3335 * is not allowed 3336 * 3337 * This is used for Posix ACL and checking creation of DOS file names 3338 */ 3339 3340 int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, 3341 ntfs_inode *ni, 3342 int accesstype) /* access type required (S_Ixxx values) */ 3343 { 3344 int perm; 3345 int res; 3346 int allow; 3347 struct stat stbuf; 3348 3349 /* 3350 * Always allow for root unless execution is requested. 3351 * (was checked by fuse until kernel 2.6.29) 3352 * Also always allow if no mapping has been defined 3353 */ 3354 if (!scx->mapping[MAPUSERS] 3355 || (!scx->uid 3356 && (!(accesstype & S_IEXEC) 3357 || (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)))) 3358 allow = 1; 3359 else { 3360 perm = ntfs_get_perm(scx, ni, accesstype); 3361 if (perm >= 0) { 3362 res = EACCES; 3363 switch (accesstype) { 3364 case S_IEXEC: 3365 allow = (perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0; 3366 break; 3367 case S_IWRITE: 3368 allow = (perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0; 3369 break; 3370 case S_IWRITE + S_IEXEC: 3371 allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) 3372 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); 3373 break; 3374 case S_IREAD: 3375 allow = (perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0; 3376 break; 3377 case S_IREAD + S_IEXEC: 3378 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0) 3379 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); 3380 break; 3381 case S_IREAD + S_IWRITE: 3382 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0) 3383 && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0); 3384 break; 3385 case S_IWRITE + S_IEXEC + S_ISVTX: 3386 if (perm & S_ISVTX) { 3387 if ((ntfs_get_owner_mode(scx,ni,&stbuf) >= 0) 3388 && (stbuf.st_uid == scx->uid)) 3389 allow = 1; 3390 else 3391 allow = 2; 3392 } else 3393 allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) 3394 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); 3395 break; 3396 case S_IREAD + S_IWRITE + S_IEXEC: 3397 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0) 3398 && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) 3399 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); 3400 break; 3401 default : 3402 res = EINVAL; 3403 allow = 0; 3404 break; 3405 } 3406 if (!allow) 3407 errno = res; 3408 } else 3409 allow = 0; 3410 } 3411 return (allow); 3412 } 3413 3414 /* 3415 * Check whether user can create a file (or directory) 3416 * 3417 * Returns TRUE if access is allowed, 3418 * Also returns the gid and dsetgid applicable to the created file 3419 */ 3420 3421 int ntfs_allowed_create(struct SECURITY_CONTEXT *scx, 3422 ntfs_inode *dir_ni, gid_t *pgid, mode_t *pdsetgid) 3423 { 3424 int perm; 3425 int res; 3426 int allow; 3427 struct stat stbuf; 3428 3429 /* 3430 * Always allow for root. 3431 * Also always allow if no mapping has been defined 3432 */ 3433 if (!scx->mapping[MAPUSERS]) 3434 perm = 0777; 3435 else 3436 perm = ntfs_get_perm(scx, dir_ni, S_IWRITE + S_IEXEC); 3437 if (!scx->mapping[MAPUSERS] 3438 || !scx->uid) { 3439 allow = 1; 3440 } else { 3441 perm = ntfs_get_perm(scx, dir_ni, S_IWRITE + S_IEXEC); 3442 if (perm >= 0) { 3443 res = EACCES; 3444 allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) 3445 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); 3446 if (!allow) 3447 errno = res; 3448 } else 3449 allow = 0; 3450 } 3451 *pgid = scx->gid; 3452 *pdsetgid = 0; 3453 /* return directory group if S_ISGID is set */ 3454 if (allow && (perm & S_ISGID)) { 3455 if (ntfs_get_owner_mode(scx, dir_ni, &stbuf) >= 0) { 3456 *pdsetgid = stbuf.st_mode & S_ISGID; 3457 if (perm & S_ISGID) 3458 *pgid = stbuf.st_gid; 3459 } 3460 } 3461 return (allow); 3462 } 3463 3464 #if 0 /* not needed any more */ 3465 3466 /* 3467 * Check whether user can access the parent directory 3468 * of a file in a specific way 3469 * 3470 * Returns true if access is allowed, including user is root and 3471 * no user mapping defined 3472 * 3473 * Sets errno if there is a problem or if not allowed 3474 * 3475 * This is used for Posix ACL and checking creation of DOS file names 3476 */ 3477 3478 BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, 3479 const char *path, int accesstype) 3480 { 3481 int allow; 3482 char *dirpath; 3483 char *name; 3484 ntfs_inode *ni; 3485 ntfs_inode *dir_ni; 3486 struct stat stbuf; 3487 3488 allow = 0; 3489 dirpath = strdup(path); 3490 if (dirpath) { 3491 /* the root of file system is seen as a parent of itself */ 3492 /* is that correct ? */ 3493 name = strrchr(dirpath, '/'); 3494 *name = 0; 3495 dir_ni = ntfs_pathname_to_inode(scx->vol, NULL, dirpath); 3496 if (dir_ni) { 3497 allow = ntfs_allowed_access(scx, 3498 dir_ni, accesstype); 3499 ntfs_inode_close(dir_ni); 3500 /* 3501 * for an not-owned sticky directory, have to 3502 * check whether file itself is owned 3503 */ 3504 if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX)) 3505 && (allow == 2)) { 3506 ni = ntfs_pathname_to_inode(scx->vol, NULL, 3507 path); 3508 allow = FALSE; 3509 if (ni) { 3510 allow = (ntfs_get_owner_mode(scx,ni,&stbuf) >= 0) 3511 && (stbuf.st_uid == scx->uid); 3512 ntfs_inode_close(ni); 3513 } 3514 } 3515 } 3516 free(dirpath); 3517 } 3518 return (allow); /* errno is set if not allowed */ 3519 } 3520 3521 #endif 3522 3523 /* 3524 * Define a new owner/group to a file 3525 * 3526 * returns zero if successful 3527 */ 3528 3529 int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, 3530 uid_t uid, gid_t gid) 3531 { 3532 const SECURITY_DESCRIPTOR_RELATIVE *phead; 3533 const struct CACHED_PERMISSIONS *cached; 3534 char *oldattr; 3535 const SID *usid; 3536 const SID *gsid; 3537 uid_t fileuid; 3538 uid_t filegid; 3539 mode_t mode; 3540 int perm; 3541 BOOL isdir; 3542 int res; 3543 #if POSIXACLS 3544 struct POSIX_SECURITY *pxdesc; 3545 BOOL pxdescbuilt = FALSE; 3546 #endif 3547 3548 res = 0; 3549 /* get the current owner and mode from cache or security attributes */ 3550 oldattr = (char*)NULL; 3551 cached = fetch_cache(scx,ni); 3552 if (cached) { 3553 fileuid = cached->uid; 3554 filegid = cached->gid; 3555 mode = cached->mode; 3556 #if POSIXACLS 3557 pxdesc = cached->pxdesc; 3558 if (!pxdesc) 3559 res = -1; 3560 #endif 3561 } else { 3562 fileuid = 0; 3563 filegid = 0; 3564 mode = 0; 3565 oldattr = getsecurityattr(scx->vol, ni); 3566 if (oldattr) { 3567 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) 3568 != const_cpu_to_le16(0); 3569 phead = (const SECURITY_DESCRIPTOR_RELATIVE*) 3570 oldattr; 3571 gsid = (const SID*) 3572 &oldattr[le32_to_cpu(phead->group)]; 3573 #if OWNERFROMACL 3574 usid = ntfs_acl_owner(oldattr); 3575 #else 3576 usid = (const SID*) 3577 &oldattr[le32_to_cpu(phead->owner)]; 3578 #endif 3579 #if POSIXACLS 3580 pxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr, 3581 usid, gsid, isdir); 3582 if (pxdesc) { 3583 pxdescbuilt = TRUE; 3584 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 3585 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); 3586 mode = perm = pxdesc->mode; 3587 } else 3588 res = -1; 3589 #else 3590 mode = perm = ntfs_build_permissions(oldattr, 3591 usid, gsid, isdir); 3592 if (perm >= 0) { 3593 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 3594 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); 3595 } else 3596 res = -1; 3597 #endif 3598 free(oldattr); 3599 } else 3600 res = -1; 3601 } 3602 if (!res) { 3603 /* check requested by root */ 3604 /* or chgrp requested by owner to an owned group */ 3605 if (!scx->uid 3606 || ((((int)uid < 0) || (uid == fileuid)) 3607 && ((gid == scx->gid) || groupmember(scx, scx->uid, gid)) 3608 && (fileuid == scx->uid))) { 3609 /* replace by the new usid and gsid */ 3610 /* or reuse old gid and sid for cacheing */ 3611 if ((int)uid < 0) 3612 uid = fileuid; 3613 if ((int)gid < 0) 3614 gid = filegid; 3615 #if !defined(__sun) || !defined (__SVR4) 3616 /* clear setuid and setgid if owner has changed */ 3617 /* unless request originated by root */ 3618 if (uid && (fileuid != uid)) 3619 mode &= 01777; 3620 #endif 3621 #if POSIXACLS 3622 res = ntfs_set_owner_mode(scx, ni, uid, gid, 3623 mode, pxdesc); 3624 #else 3625 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode); 3626 #endif 3627 } else { 3628 res = -1; /* neither owner nor root */ 3629 errno = EPERM; 3630 } 3631 #if POSIXACLS 3632 if (pxdescbuilt) 3633 free(pxdesc); 3634 #endif 3635 } else { 3636 /* 3637 * Should not happen : a default descriptor is generated 3638 * by getsecurityattr() when there are none 3639 */ 3640 ntfs_log_error("File has no security descriptor\n"); 3641 res = -1; 3642 errno = EIO; 3643 } 3644 return (res ? -1 : 0); 3645 } 3646 3647 /* 3648 * Define new owner/group and mode to a file 3649 * 3650 * returns zero if successful 3651 */ 3652 3653 int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, 3654 uid_t uid, gid_t gid, const mode_t mode) 3655 { 3656 const struct CACHED_PERMISSIONS *cached; 3657 char *oldattr; 3658 uid_t fileuid; 3659 uid_t filegid; 3660 int res; 3661 #if POSIXACLS 3662 const SECURITY_DESCRIPTOR_RELATIVE *phead; 3663 const SID *usid; 3664 const SID *gsid; 3665 BOOL isdir; 3666 const struct POSIX_SECURITY *oldpxdesc; 3667 struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL; 3668 int pxsize; 3669 #endif 3670 3671 res = 0; 3672 /* get the current owner and mode from cache or security attributes */ 3673 oldattr = (char*)NULL; 3674 cached = fetch_cache(scx,ni); 3675 if (cached) { 3676 fileuid = cached->uid; 3677 filegid = cached->gid; 3678 #if POSIXACLS 3679 oldpxdesc = cached->pxdesc; 3680 if (oldpxdesc) { 3681 /* must copy before merging */ 3682 pxsize = sizeof(struct POSIX_SECURITY) 3683 + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE); 3684 newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize); 3685 if (newpxdesc) { 3686 memcpy(newpxdesc, oldpxdesc, pxsize); 3687 if (ntfs_merge_mode_posix(newpxdesc, mode)) 3688 res = -1; 3689 } else 3690 res = -1; 3691 } 3692 #endif 3693 } else { 3694 fileuid = 0; 3695 filegid = 0; 3696 oldattr = getsecurityattr(scx->vol, ni); 3697 if (oldattr) { 3698 #if POSIXACLS 3699 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) 3700 != const_cpu_to_le16(0); 3701 phead = (const SECURITY_DESCRIPTOR_RELATIVE*) 3702 oldattr; 3703 gsid = (const SID*) 3704 &oldattr[le32_to_cpu(phead->group)]; 3705 #if OWNERFROMACL 3706 usid = ntfs_acl_owner(oldattr); 3707 #else 3708 usid = (const SID*) 3709 &oldattr[le32_to_cpu(phead->owner)]; 3710 #endif 3711 newpxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr, 3712 usid, gsid, isdir); 3713 if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode)) 3714 res = -1; 3715 else { 3716 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid); 3717 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); 3718 } 3719 #endif 3720 free(oldattr); 3721 } else 3722 res = -1; 3723 } 3724 if (!res) { 3725 /* check requested by root */ 3726 /* or chgrp requested by owner to an owned group */ 3727 if (!scx->uid 3728 || ((((int)uid < 0) || (uid == fileuid)) 3729 && ((gid == scx->gid) || groupmember(scx, scx->uid, gid)) 3730 && (fileuid == scx->uid))) { 3731 /* replace by the new usid and gsid */ 3732 /* or reuse old gid and sid for cacheing */ 3733 if ((int)uid < 0) 3734 uid = fileuid; 3735 if ((int)gid < 0) 3736 gid = filegid; 3737 #if POSIXACLS 3738 res = ntfs_set_owner_mode(scx, ni, uid, gid, 3739 mode, newpxdesc); 3740 #else 3741 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode); 3742 #endif 3743 } else { 3744 res = -1; /* neither owner nor root */ 3745 errno = EPERM; 3746 } 3747 } else { 3748 /* 3749 * Should not happen : a default descriptor is generated 3750 * by getsecurityattr() when there are none 3751 */ 3752 ntfs_log_error("File has no security descriptor\n"); 3753 res = -1; 3754 errno = EIO; 3755 } 3756 #if POSIXACLS 3757 free(newpxdesc); 3758 #endif 3759 return (res ? -1 : 0); 3760 } 3761 3762 /* 3763 * Build a security id for a descriptor inherited from 3764 * parent directory the Windows way 3765 */ 3766 3767 static le32 build_inherited_id(struct SECURITY_CONTEXT *scx, 3768 const char *parentattr, BOOL fordir) 3769 { 3770 const SECURITY_DESCRIPTOR_RELATIVE *pphead; 3771 const ACL *ppacl; 3772 const SID *usid; 3773 const SID *gsid; 3774 BIGSID defusid; 3775 BIGSID defgsid; 3776 int offpacl; 3777 int offowner; 3778 int offgroup; 3779 SECURITY_DESCRIPTOR_RELATIVE *pnhead; 3780 ACL *pnacl; 3781 int parentattrsz; 3782 char *newattr; 3783 int newattrsz; 3784 int aclsz; 3785 int usidsz; 3786 int gsidsz; 3787 int pos; 3788 le32 securid; 3789 3790 parentattrsz = ntfs_attr_size(parentattr); 3791 pphead = (const SECURITY_DESCRIPTOR_RELATIVE*)parentattr; 3792 if (scx->mapping[MAPUSERS]) { 3793 usid = ntfs_find_usid(scx->mapping[MAPUSERS], scx->uid, (SID*)&defusid); 3794 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS], scx->gid, (SID*)&defgsid); 3795 if (!usid) 3796 usid = adminsid; 3797 if (!gsid) 3798 gsid = adminsid; 3799 } else { 3800 /* 3801 * If there is no user mapping, we have to copy owner 3802 * and group from parent directory. 3803 * Windows never has to do that, because it can always 3804 * rely on a user mapping 3805 */ 3806 offowner = le32_to_cpu(pphead->owner); 3807 usid = (const SID*)&parentattr[offowner]; 3808 offgroup = le32_to_cpu(pphead->group); 3809 gsid = (const SID*)&parentattr[offgroup]; 3810 } 3811 /* 3812 * new attribute is smaller than parent's 3813 * except for differences in SIDs which appear in 3814 * owner, group and possible grants and denials in 3815 * generic creator-owner and creator-group ACEs. 3816 * For directories, an ACE may be duplicated for 3817 * access and inheritance, so we double the count. 3818 */ 3819 usidsz = ntfs_sid_size(usid); 3820 gsidsz = ntfs_sid_size(gsid); 3821 newattrsz = parentattrsz + 3*usidsz + 3*gsidsz; 3822 if (fordir) 3823 newattrsz *= 2; 3824 newattr = (char*)ntfs_malloc(newattrsz); 3825 if (newattr) { 3826 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr; 3827 pnhead->revision = SECURITY_DESCRIPTOR_REVISION; 3828 pnhead->alignment = 0; 3829 pnhead->control = (pphead->control 3830 & (SE_DACL_AUTO_INHERITED | SE_SACL_AUTO_INHERITED)) 3831 | SE_SELF_RELATIVE; 3832 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE); 3833 /* 3834 * locate and inherit DACL 3835 * do not test SE_DACL_PRESENT (wrong for "DR Watson") 3836 */ 3837 pnhead->dacl = const_cpu_to_le32(0); 3838 if (pphead->dacl) { 3839 offpacl = le32_to_cpu(pphead->dacl); 3840 ppacl = (const ACL*)&parentattr[offpacl]; 3841 pnacl = (ACL*)&newattr[pos]; 3842 aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, 3843 fordir, pphead->control 3844 & SE_DACL_AUTO_INHERITED); 3845 if (aclsz) { 3846 pnhead->dacl = cpu_to_le32(pos); 3847 pos += aclsz; 3848 pnhead->control |= SE_DACL_PRESENT; 3849 } 3850 } 3851 /* 3852 * locate and inherit SACL 3853 */ 3854 pnhead->sacl = const_cpu_to_le32(0); 3855 if (pphead->sacl) { 3856 offpacl = le32_to_cpu(pphead->sacl); 3857 ppacl = (const ACL*)&parentattr[offpacl]; 3858 pnacl = (ACL*)&newattr[pos]; 3859 aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, 3860 fordir, pphead->control 3861 & SE_SACL_AUTO_INHERITED); 3862 if (aclsz) { 3863 pnhead->sacl = cpu_to_le32(pos); 3864 pos += aclsz; 3865 pnhead->control |= SE_SACL_PRESENT; 3866 } 3867 } 3868 /* 3869 * inherit or redefine owner 3870 */ 3871 memcpy(&newattr[pos],usid,usidsz); 3872 pnhead->owner = cpu_to_le32(pos); 3873 pos += usidsz; 3874 /* 3875 * inherit or redefine group 3876 */ 3877 memcpy(&newattr[pos],gsid,gsidsz); 3878 pnhead->group = cpu_to_le32(pos); 3879 pos += gsidsz; 3880 securid = setsecurityattr(scx->vol, 3881 (SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos); 3882 free(newattr); 3883 } else 3884 securid = const_cpu_to_le32(0); 3885 return (securid); 3886 } 3887 3888 /* 3889 * Get an inherited security id 3890 * 3891 * For Windows compatibility, the normal initial permission setting 3892 * may be inherited from the parent directory instead of being 3893 * defined by the creation arguments. 3894 * 3895 * The following creates an inherited id for that purpose. 3896 * 3897 * Note : the owner and group of parent directory are also 3898 * inherited (which is not the case on Windows) if no user mapping 3899 * is defined. 3900 * 3901 * Returns the inherited id, or zero if not possible (eg on NTFS 1.x) 3902 */ 3903 3904 le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx, 3905 ntfs_inode *dir_ni, BOOL fordir) 3906 { 3907 struct CACHED_PERMISSIONS *cached; 3908 char *parentattr; 3909 le32 securid; 3910 3911 securid = const_cpu_to_le32(0); 3912 cached = (struct CACHED_PERMISSIONS*)NULL; 3913 /* 3914 * Try to get inherited id from cache 3915 */ 3916 if (test_nino_flag(dir_ni, v3_Extensions) 3917 && dir_ni->security_id) { 3918 cached = fetch_cache(scx, dir_ni); 3919 if (cached) 3920 securid = (fordir ? cached->inh_dirid 3921 : cached->inh_fileid); 3922 } 3923 /* 3924 * Not cached or not available in cache, compute it all 3925 * Note : if parent directory has no id, it is not cacheable 3926 */ 3927 if (!securid) { 3928 parentattr = getsecurityattr(scx->vol, dir_ni); 3929 if (parentattr) { 3930 securid = build_inherited_id(scx, 3931 parentattr, fordir); 3932 free(parentattr); 3933 /* 3934 * Store the result into cache for further use 3935 */ 3936 if (securid) { 3937 cached = fetch_cache(scx, dir_ni); 3938 if (cached) { 3939 if (fordir) 3940 cached->inh_dirid = securid; 3941 else 3942 cached->inh_fileid = securid; 3943 } 3944 } 3945 } 3946 } 3947 return (securid); 3948 } 3949 3950 /* 3951 * Link a group to a member of group 3952 * 3953 * Returns 0 if OK, -1 (and errno set) if error 3954 */ 3955 3956 static int link_single_group(struct MAPPING *usermapping, struct passwd *user, 3957 gid_t gid) 3958 { 3959 struct group *group; 3960 char **grmem; 3961 int grcnt; 3962 gid_t *groups; 3963 int res; 3964 3965 res = 0; 3966 group = getgrgid(gid); 3967 if (group && group->gr_mem) { 3968 grcnt = usermapping->grcnt; 3969 groups = usermapping->groups; 3970 grmem = group->gr_mem; 3971 while (*grmem && strcmp(user->pw_name, *grmem)) 3972 grmem++; 3973 if (*grmem) { 3974 if (!grcnt) 3975 groups = (gid_t*)malloc(sizeof(gid_t)); 3976 else 3977 groups = (gid_t*)realloc(groups, 3978 (grcnt+1)*sizeof(gid_t)); 3979 if (groups) 3980 groups[grcnt++] = gid; 3981 else { 3982 res = -1; 3983 errno = ENOMEM; 3984 } 3985 } 3986 usermapping->grcnt = grcnt; 3987 usermapping->groups = groups; 3988 } 3989 return (res); 3990 } 3991 3992 3993 /* 3994 * Statically link group to users 3995 * This is based on groups defined in /etc/group and does not take 3996 * the groups dynamically set by setgroups() nor any changes in 3997 * /etc/group into account 3998 * 3999 * Only mapped groups and root group are linked to mapped users 4000 * 4001 * Returns 0 if OK, -1 (and errno set) if error 4002 * 4003 */ 4004 4005 static int link_group_members(struct SECURITY_CONTEXT *scx) 4006 { 4007 struct MAPPING *usermapping; 4008 struct MAPPING *groupmapping; 4009 struct passwd *user; 4010 int res; 4011 4012 res = 0; 4013 for (usermapping=scx->mapping[MAPUSERS]; usermapping && !res; 4014 usermapping=usermapping->next) { 4015 usermapping->grcnt = 0; 4016 usermapping->groups = (gid_t*)NULL; 4017 user = getpwuid(usermapping->xid); 4018 if (user && user->pw_name) { 4019 for (groupmapping=scx->mapping[MAPGROUPS]; 4020 groupmapping && !res; 4021 groupmapping=groupmapping->next) { 4022 if (link_single_group(usermapping, user, 4023 groupmapping->xid)) 4024 res = -1; 4025 } 4026 if (!res && link_single_group(usermapping, 4027 user, (gid_t)0)) 4028 res = -1; 4029 } 4030 } 4031 return (res); 4032 } 4033 4034 /* 4035 * Apply default single user mapping 4036 * returns zero if successful 4037 */ 4038 4039 static int ntfs_do_default_mapping(struct SECURITY_CONTEXT *scx, 4040 uid_t uid, gid_t gid, const SID *usid) 4041 { 4042 struct MAPPING *usermapping; 4043 struct MAPPING *groupmapping; 4044 SID *sid; 4045 int sidsz; 4046 int res; 4047 4048 res = -1; 4049 sidsz = ntfs_sid_size(usid); 4050 sid = (SID*)ntfs_malloc(sidsz); 4051 if (sid) { 4052 memcpy(sid,usid,sidsz); 4053 usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING)); 4054 if (usermapping) { 4055 groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING)); 4056 if (groupmapping) { 4057 usermapping->sid = sid; 4058 usermapping->xid = uid; 4059 usermapping->next = (struct MAPPING*)NULL; 4060 groupmapping->sid = sid; 4061 groupmapping->xid = gid; 4062 groupmapping->next = (struct MAPPING*)NULL; 4063 scx->mapping[MAPUSERS] = usermapping; 4064 scx->mapping[MAPGROUPS] = groupmapping; 4065 res = 0; 4066 } 4067 } 4068 } 4069 return (res); 4070 } 4071 4072 /* 4073 * Make sure there are no ambiguous mapping 4074 * Ambiguous mapping may lead to undesired configurations and 4075 * we had rather be safe until the consequences are understood 4076 */ 4077 4078 #if 0 /* not activated for now */ 4079 4080 static BOOL check_mapping(const struct MAPPING *usermapping, 4081 const struct MAPPING *groupmapping) 4082 { 4083 const struct MAPPING *mapping1; 4084 const struct MAPPING *mapping2; 4085 BOOL ambiguous; 4086 4087 ambiguous = FALSE; 4088 for (mapping1=usermapping; mapping1; mapping1=mapping1->next) 4089 for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next) 4090 if (ntfs_same_sid(mapping1->sid,mapping2->sid)) { 4091 if (mapping1->xid != mapping2->xid) 4092 ambiguous = TRUE; 4093 } else { 4094 if (mapping1->xid == mapping2->xid) 4095 ambiguous = TRUE; 4096 } 4097 for (mapping1=groupmapping; mapping1; mapping1=mapping1->next) 4098 for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next) 4099 if (ntfs_same_sid(mapping1->sid,mapping2->sid)) { 4100 if (mapping1->xid != mapping2->xid) 4101 ambiguous = TRUE; 4102 } else { 4103 if (mapping1->xid == mapping2->xid) 4104 ambiguous = TRUE; 4105 } 4106 return (ambiguous); 4107 } 4108 4109 #endif 4110 4111 #if 0 /* not used any more */ 4112 4113 /* 4114 * Try and apply default single user mapping 4115 * returns zero if successful 4116 */ 4117 4118 static int ntfs_default_mapping(struct SECURITY_CONTEXT *scx) 4119 { 4120 const SECURITY_DESCRIPTOR_RELATIVE *phead; 4121 ntfs_inode *ni; 4122 char *securattr; 4123 const SID *usid; 4124 int res; 4125 4126 res = -1; 4127 ni = ntfs_pathname_to_inode(scx->vol, NULL, "/."); 4128 if (ni) { 4129 securattr = getsecurityattr(scx->vol, ni); 4130 if (securattr) { 4131 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; 4132 usid = (SID*)&securattr[le32_to_cpu(phead->owner)]; 4133 if (ntfs_is_user_sid(usid)) 4134 res = ntfs_do_default_mapping(scx, 4135 scx->uid, scx->gid, usid); 4136 free(securattr); 4137 } 4138 ntfs_inode_close(ni); 4139 } 4140 return (res); 4141 } 4142 4143 #endif 4144 4145 /* 4146 * Basic read from a user mapping file on another volume 4147 */ 4148 4149 static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused))) 4150 { 4151 return (read(*(int*)fileid, buf, size)); 4152 } 4153 4154 4155 /* 4156 * Read from a user mapping file on current NTFS partition 4157 */ 4158 4159 static int localread(void *fileid, char *buf, size_t size, off_t offs) 4160 { 4161 return (ntfs_attr_data_read((ntfs_inode*)fileid, 4162 AT_UNNAMED, 0, buf, size, offs)); 4163 } 4164 4165 /* 4166 * Build the user mapping 4167 * - according to a mapping file if defined (or default present), 4168 * - or try default single user mapping if possible 4169 * 4170 * The mapping is specific to a mounted device 4171 * No locking done, mounting assumed non multithreaded 4172 * 4173 * returns zero if mapping is successful 4174 * (failure should not be interpreted as an error) 4175 */ 4176 4177 int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path, 4178 BOOL allowdef) 4179 { 4180 struct MAPLIST *item; 4181 struct MAPLIST *firstitem; 4182 struct MAPPING *usermapping; 4183 struct MAPPING *groupmapping; 4184 ntfs_inode *ni; 4185 int fd; 4186 static struct { 4187 u8 revision; 4188 u8 levels; 4189 be16 highbase; 4190 be32 lowbase; 4191 le32 level1; 4192 le32 level2; 4193 le32 level3; 4194 le32 level4; 4195 le32 level5; 4196 } defmap = { 4197 1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5), 4198 const_cpu_to_le32(21), 4199 const_cpu_to_le32(DEFSECAUTH1), const_cpu_to_le32(DEFSECAUTH2), 4200 const_cpu_to_le32(DEFSECAUTH3), const_cpu_to_le32(DEFSECBASE) 4201 } ; 4202 4203 /* be sure not to map anything until done */ 4204 scx->mapping[MAPUSERS] = (struct MAPPING*)NULL; 4205 scx->mapping[MAPGROUPS] = (struct MAPPING*)NULL; 4206 4207 if (!usermap_path) usermap_path = MAPPINGFILE; 4208 if (usermap_path[0] == '/') { 4209 fd = open(usermap_path,O_RDONLY); 4210 if (fd > 0) { 4211 firstitem = ntfs_read_mapping(basicread, (void*)&fd); 4212 close(fd); 4213 } else 4214 firstitem = (struct MAPLIST*)NULL; 4215 } else { 4216 ni = ntfs_pathname_to_inode(scx->vol, NULL, usermap_path); 4217 if (ni) { 4218 firstitem = ntfs_read_mapping(localread, ni); 4219 ntfs_inode_close(ni); 4220 } else 4221 firstitem = (struct MAPLIST*)NULL; 4222 } 4223 4224 4225 if (firstitem) { 4226 usermapping = ntfs_do_user_mapping(firstitem); 4227 groupmapping = ntfs_do_group_mapping(firstitem); 4228 if (usermapping && groupmapping) { 4229 scx->mapping[MAPUSERS] = usermapping; 4230 scx->mapping[MAPGROUPS] = groupmapping; 4231 } else 4232 ntfs_log_error("There were no valid user or no valid group\n"); 4233 /* now we can free the memory copy of input text */ 4234 /* and rely on internal representation */ 4235 while (firstitem) { 4236 item = firstitem->next; 4237 free(firstitem); 4238 firstitem = item; 4239 } 4240 } else { 4241 /* no mapping file, try a default mapping */ 4242 if (allowdef) { 4243 if (!ntfs_do_default_mapping(scx, 4244 0, 0, (const SID*)&defmap)) 4245 ntfs_log_info("Using default user mapping\n"); 4246 } 4247 } 4248 return (!scx->mapping[MAPUSERS] || link_group_members(scx)); 4249 } 4250 4251 #ifdef HAVE_SETXATTR /* extended attributes interface required */ 4252 4253 /* 4254 * Get the ntfs attribute into an extended attribute 4255 * The attribute is returned according to cpu endianness 4256 */ 4257 4258 int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size) 4259 { 4260 u32 attrib; 4261 size_t outsize; 4262 4263 outsize = 0; /* default to no data and no error */ 4264 if (ni) { 4265 attrib = le32_to_cpu(ni->flags); 4266 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) 4267 attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY); 4268 else 4269 attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY); 4270 if (!attrib) 4271 attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL); 4272 outsize = sizeof(FILE_ATTR_FLAGS); 4273 if (size >= outsize) { 4274 if (value) 4275 memcpy(value,&attrib,outsize); 4276 else 4277 errno = EINVAL; 4278 } 4279 } 4280 return (outsize ? (int)outsize : -errno); 4281 } 4282 4283 /* 4284 * Return the ntfs attribute into an extended attribute 4285 * The attribute is expected according to cpu endianness 4286 * 4287 * Returns 0, or -1 if there is a problem 4288 */ 4289 4290 int ntfs_set_ntfs_attrib(ntfs_inode *ni, 4291 const char *value, size_t size, int flags) 4292 { 4293 u32 attrib; 4294 le32 settable; 4295 ATTR_FLAGS dirflags; 4296 int res; 4297 4298 res = -1; 4299 if (ni && value && (size >= sizeof(FILE_ATTR_FLAGS))) { 4300 if (!(flags & XATTR_CREATE)) { 4301 /* copy to avoid alignment problems */ 4302 memcpy(&attrib,value,sizeof(FILE_ATTR_FLAGS)); 4303 settable = FILE_ATTR_SETTABLE; 4304 res = 0; 4305 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { 4306 /* 4307 * Accept changing compression for a directory 4308 * and set index root accordingly 4309 */ 4310 settable |= FILE_ATTR_COMPRESSED; 4311 if ((ni->flags ^ cpu_to_le32(attrib)) 4312 & FILE_ATTR_COMPRESSED) { 4313 if (ni->flags & FILE_ATTR_COMPRESSED) 4314 dirflags = const_cpu_to_le16(0); 4315 else 4316 dirflags = ATTR_IS_COMPRESSED; 4317 res = ntfs_attr_set_flags(ni, 4318 AT_INDEX_ROOT, 4319 NTFS_INDEX_I30, 4, 4320 dirflags, 4321 ATTR_COMPRESSION_MASK); 4322 } 4323 } 4324 if (!res) { 4325 ni->flags = (ni->flags & ~settable) 4326 | (cpu_to_le32(attrib) & settable); 4327 NInoFileNameSetDirty(ni); 4328 NInoSetDirty(ni); 4329 } 4330 } else 4331 errno = EEXIST; 4332 } else 4333 errno = EINVAL; 4334 return (res ? -1 : 0); 4335 } 4336 4337 #endif /* HAVE_SETXATTR */ 4338 4339 /* 4340 * Open $Secure once for all 4341 * returns zero if it succeeds 4342 * non-zero if it fails. This is not an error (on NTFS v1.x) 4343 */ 4344 4345 4346 int ntfs_open_secure(ntfs_volume *vol) 4347 { 4348 ntfs_inode *ni; 4349 int res; 4350 4351 res = -1; 4352 vol->secure_ni = (ntfs_inode*)NULL; 4353 vol->secure_xsii = (ntfs_index_context*)NULL; 4354 vol->secure_xsdh = (ntfs_index_context*)NULL; 4355 if (vol->major_ver >= 3) { 4356 /* make sure this is a genuine $Secure inode 9 */ 4357 ni = ntfs_pathname_to_inode(vol, NULL, "$Secure"); 4358 if (ni && (ni->mft_no == 9)) { 4359 vol->secure_reentry = 0; 4360 vol->secure_xsii = ntfs_index_ctx_get(ni, 4361 sii_stream, 4); 4362 vol->secure_xsdh = ntfs_index_ctx_get(ni, 4363 sdh_stream, 4); 4364 if (ni && vol->secure_xsii && vol->secure_xsdh) { 4365 vol->secure_ni = ni; 4366 res = 0; 4367 } 4368 } 4369 } 4370 return (res); 4371 } 4372 4373 /* 4374 * Final cleaning 4375 * Allocated memory is freed to facilitate the detection of memory leaks 4376 */ 4377 4378 void ntfs_close_secure(struct SECURITY_CONTEXT *scx) 4379 { 4380 ntfs_volume *vol; 4381 4382 vol = scx->vol; 4383 if (vol->secure_ni) { 4384 ntfs_index_ctx_put(vol->secure_xsii); 4385 ntfs_index_ctx_put(vol->secure_xsdh); 4386 ntfs_inode_close(vol->secure_ni); 4387 4388 } 4389 ntfs_free_mapping(scx->mapping); 4390 free_caches(scx); 4391 } 4392 4393 /* 4394 * API for direct access to security descriptors 4395 * based on Win32 API 4396 */ 4397 4398 4399 /* 4400 * Selective feeding of a security descriptor into user buffer 4401 * 4402 * Returns TRUE if successful 4403 */ 4404 4405 static BOOL feedsecurityattr(const char *attr, u32 selection, 4406 char *buf, u32 buflen, u32 *psize) 4407 { 4408 const SECURITY_DESCRIPTOR_RELATIVE *phead; 4409 SECURITY_DESCRIPTOR_RELATIVE *pnhead; 4410 const ACL *pdacl; 4411 const ACL *psacl; 4412 const SID *pusid; 4413 const SID *pgsid; 4414 unsigned int offdacl; 4415 unsigned int offsacl; 4416 unsigned int offowner; 4417 unsigned int offgroup; 4418 unsigned int daclsz; 4419 unsigned int saclsz; 4420 unsigned int usidsz; 4421 unsigned int gsidsz; 4422 unsigned int size; /* size of requested attributes */ 4423 BOOL ok; 4424 unsigned int pos; 4425 unsigned int avail; 4426 le16 control; 4427 4428 avail = 0; 4429 control = SE_SELF_RELATIVE; 4430 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; 4431 size = sizeof(SECURITY_DESCRIPTOR_RELATIVE); 4432 4433 /* locate DACL if requested and available */ 4434 if (phead->dacl && (selection & DACL_SECURITY_INFORMATION)) { 4435 offdacl = le32_to_cpu(phead->dacl); 4436 pdacl = (const ACL*)&attr[offdacl]; 4437 daclsz = le16_to_cpu(pdacl->size); 4438 size += daclsz; 4439 avail |= DACL_SECURITY_INFORMATION; 4440 } else 4441 offdacl = daclsz = 0; 4442 4443 /* locate owner if requested and available */ 4444 offowner = le32_to_cpu(phead->owner); 4445 if (offowner && (selection & OWNER_SECURITY_INFORMATION)) { 4446 /* find end of USID */ 4447 pusid = (const SID*)&attr[offowner]; 4448 usidsz = ntfs_sid_size(pusid); 4449 size += usidsz; 4450 avail |= OWNER_SECURITY_INFORMATION; 4451 } else 4452 offowner = usidsz = 0; 4453 4454 /* locate group if requested and available */ 4455 offgroup = le32_to_cpu(phead->group); 4456 if (offgroup && (selection & GROUP_SECURITY_INFORMATION)) { 4457 /* find end of GSID */ 4458 pgsid = (const SID*)&attr[offgroup]; 4459 gsidsz = ntfs_sid_size(pgsid); 4460 size += gsidsz; 4461 avail |= GROUP_SECURITY_INFORMATION; 4462 } else 4463 offgroup = gsidsz = 0; 4464 4465 /* locate SACL if requested and available */ 4466 if (phead->sacl && (selection & SACL_SECURITY_INFORMATION)) { 4467 /* find end of SACL */ 4468 offsacl = le32_to_cpu(phead->sacl); 4469 psacl = (const ACL*)&attr[offsacl]; 4470 saclsz = le16_to_cpu(psacl->size); 4471 size += saclsz; 4472 avail |= SACL_SECURITY_INFORMATION; 4473 } else 4474 offsacl = saclsz = 0; 4475 4476 /* 4477 * Check having enough size in destination buffer 4478 * (required size is returned nevertheless so that 4479 * the request can be reissued with adequate size) 4480 */ 4481 if (size > buflen) { 4482 *psize = size; 4483 errno = EINVAL; 4484 ok = FALSE; 4485 } else { 4486 if (selection & OWNER_SECURITY_INFORMATION) 4487 control |= phead->control & SE_OWNER_DEFAULTED; 4488 if (selection & GROUP_SECURITY_INFORMATION) 4489 control |= phead->control & SE_GROUP_DEFAULTED; 4490 if (selection & DACL_SECURITY_INFORMATION) 4491 control |= phead->control 4492 & (SE_DACL_PRESENT 4493 | SE_DACL_DEFAULTED 4494 | SE_DACL_AUTO_INHERITED 4495 | SE_DACL_PROTECTED); 4496 if (selection & SACL_SECURITY_INFORMATION) 4497 control |= phead->control 4498 & (SE_SACL_PRESENT 4499 | SE_SACL_DEFAULTED 4500 | SE_SACL_AUTO_INHERITED 4501 | SE_SACL_PROTECTED); 4502 /* 4503 * copy header and feed new flags, even if no detailed data 4504 */ 4505 memcpy(buf,attr,sizeof(SECURITY_DESCRIPTOR_RELATIVE)); 4506 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)buf; 4507 pnhead->control = control; 4508 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE); 4509 4510 /* copy DACL if requested and available */ 4511 if (selection & avail & DACL_SECURITY_INFORMATION) { 4512 pnhead->dacl = cpu_to_le32(pos); 4513 memcpy(&buf[pos],&attr[offdacl],daclsz); 4514 pos += daclsz; 4515 } else 4516 pnhead->dacl = const_cpu_to_le32(0); 4517 4518 /* copy SACL if requested and available */ 4519 if (selection & avail & SACL_SECURITY_INFORMATION) { 4520 pnhead->sacl = cpu_to_le32(pos); 4521 memcpy(&buf[pos],&attr[offsacl],saclsz); 4522 pos += saclsz; 4523 } else 4524 pnhead->sacl = const_cpu_to_le32(0); 4525 4526 /* copy owner if requested and available */ 4527 if (selection & avail & OWNER_SECURITY_INFORMATION) { 4528 pnhead->owner = cpu_to_le32(pos); 4529 memcpy(&buf[pos],&attr[offowner],usidsz); 4530 pos += usidsz; 4531 } else 4532 pnhead->owner = const_cpu_to_le32(0); 4533 4534 /* copy group if requested and available */ 4535 if (selection & avail & GROUP_SECURITY_INFORMATION) { 4536 pnhead->group = cpu_to_le32(pos); 4537 memcpy(&buf[pos],&attr[offgroup],gsidsz); 4538 pos += gsidsz; 4539 } else 4540 pnhead->group = const_cpu_to_le32(0); 4541 if (pos != size) 4542 ntfs_log_error("Error in security descriptor size\n"); 4543 *psize = size; 4544 ok = TRUE; 4545 } 4546 4547 return (ok); 4548 } 4549 4550 /* 4551 * Merge a new security descriptor into the old one 4552 * and assign to designated file 4553 * 4554 * Returns TRUE if successful 4555 */ 4556 4557 static BOOL mergesecurityattr(ntfs_volume *vol, const char *oldattr, 4558 const char *newattr, u32 selection, ntfs_inode *ni) 4559 { 4560 const SECURITY_DESCRIPTOR_RELATIVE *oldhead; 4561 const SECURITY_DESCRIPTOR_RELATIVE *newhead; 4562 SECURITY_DESCRIPTOR_RELATIVE *targhead; 4563 const ACL *pdacl; 4564 const ACL *psacl; 4565 const SID *powner; 4566 const SID *pgroup; 4567 int offdacl; 4568 int offsacl; 4569 int offowner; 4570 int offgroup; 4571 unsigned int size; 4572 le16 control; 4573 char *target; 4574 int pos; 4575 int oldattrsz; 4576 int newattrsz; 4577 BOOL ok; 4578 4579 ok = FALSE; /* default return */ 4580 oldhead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr; 4581 newhead = (const SECURITY_DESCRIPTOR_RELATIVE*)newattr; 4582 oldattrsz = ntfs_attr_size(oldattr); 4583 newattrsz = ntfs_attr_size(newattr); 4584 target = (char*)ntfs_malloc(oldattrsz + newattrsz); 4585 if (target) { 4586 targhead = (SECURITY_DESCRIPTOR_RELATIVE*)target; 4587 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE); 4588 control = SE_SELF_RELATIVE; 4589 /* 4590 * copy new DACL if selected 4591 * or keep old DACL if any 4592 */ 4593 if ((selection & DACL_SECURITY_INFORMATION) ? 4594 newhead->dacl : oldhead->dacl) { 4595 if (selection & DACL_SECURITY_INFORMATION) { 4596 offdacl = le32_to_cpu(newhead->dacl); 4597 pdacl = (const ACL*)&newattr[offdacl]; 4598 } else { 4599 offdacl = le32_to_cpu(oldhead->dacl); 4600 pdacl = (const ACL*)&oldattr[offdacl]; 4601 } 4602 size = le16_to_cpu(pdacl->size); 4603 memcpy(&target[pos], pdacl, size); 4604 targhead->dacl = cpu_to_le32(pos); 4605 pos += size; 4606 } else 4607 targhead->dacl = const_cpu_to_le32(0); 4608 if (selection & DACL_SECURITY_INFORMATION) { 4609 control |= newhead->control 4610 & (SE_DACL_PRESENT 4611 | SE_DACL_DEFAULTED 4612 | SE_DACL_PROTECTED); 4613 if (newhead->control & SE_DACL_AUTO_INHERIT_REQ) 4614 control |= SE_DACL_AUTO_INHERITED; 4615 } else 4616 control |= oldhead->control 4617 & (SE_DACL_PRESENT 4618 | SE_DACL_DEFAULTED 4619 | SE_DACL_AUTO_INHERITED 4620 | SE_DACL_PROTECTED); 4621 /* 4622 * copy new SACL if selected 4623 * or keep old SACL if any 4624 */ 4625 if ((selection & SACL_SECURITY_INFORMATION) ? 4626 newhead->sacl : oldhead->sacl) { 4627 if (selection & SACL_SECURITY_INFORMATION) { 4628 offsacl = le32_to_cpu(newhead->sacl); 4629 psacl = (const ACL*)&newattr[offsacl]; 4630 } else { 4631 offsacl = le32_to_cpu(oldhead->sacl); 4632 psacl = (const ACL*)&oldattr[offsacl]; 4633 } 4634 size = le16_to_cpu(psacl->size); 4635 memcpy(&target[pos], psacl, size); 4636 targhead->sacl = cpu_to_le32(pos); 4637 pos += size; 4638 } else 4639 targhead->sacl = const_cpu_to_le32(0); 4640 if (selection & SACL_SECURITY_INFORMATION) { 4641 control |= newhead->control 4642 & (SE_SACL_PRESENT 4643 | SE_SACL_DEFAULTED 4644 | SE_SACL_PROTECTED); 4645 if (newhead->control & SE_SACL_AUTO_INHERIT_REQ) 4646 control |= SE_SACL_AUTO_INHERITED; 4647 } else 4648 control |= oldhead->control 4649 & (SE_SACL_PRESENT 4650 | SE_SACL_DEFAULTED 4651 | SE_SACL_AUTO_INHERITED 4652 | SE_SACL_PROTECTED); 4653 /* 4654 * copy new OWNER if selected 4655 * or keep old OWNER if any 4656 */ 4657 if ((selection & OWNER_SECURITY_INFORMATION) ? 4658 newhead->owner : oldhead->owner) { 4659 if (selection & OWNER_SECURITY_INFORMATION) { 4660 offowner = le32_to_cpu(newhead->owner); 4661 powner = (const SID*)&newattr[offowner]; 4662 } else { 4663 offowner = le32_to_cpu(oldhead->owner); 4664 powner = (const SID*)&oldattr[offowner]; 4665 } 4666 size = ntfs_sid_size(powner); 4667 memcpy(&target[pos], powner, size); 4668 targhead->owner = cpu_to_le32(pos); 4669 pos += size; 4670 } else 4671 targhead->owner = const_cpu_to_le32(0); 4672 if (selection & OWNER_SECURITY_INFORMATION) 4673 control |= newhead->control & SE_OWNER_DEFAULTED; 4674 else 4675 control |= oldhead->control & SE_OWNER_DEFAULTED; 4676 /* 4677 * copy new GROUP if selected 4678 * or keep old GROUP if any 4679 */ 4680 if ((selection & GROUP_SECURITY_INFORMATION) ? 4681 newhead->group : oldhead->group) { 4682 if (selection & GROUP_SECURITY_INFORMATION) { 4683 offgroup = le32_to_cpu(newhead->group); 4684 pgroup = (const SID*)&newattr[offgroup]; 4685 control |= newhead->control 4686 & SE_GROUP_DEFAULTED; 4687 } else { 4688 offgroup = le32_to_cpu(oldhead->group); 4689 pgroup = (const SID*)&oldattr[offgroup]; 4690 control |= oldhead->control 4691 & SE_GROUP_DEFAULTED; 4692 } 4693 size = ntfs_sid_size(pgroup); 4694 memcpy(&target[pos], pgroup, size); 4695 targhead->group = cpu_to_le32(pos); 4696 pos += size; 4697 } else 4698 targhead->group = const_cpu_to_le32(0); 4699 if (selection & GROUP_SECURITY_INFORMATION) 4700 control |= newhead->control & SE_GROUP_DEFAULTED; 4701 else 4702 control |= oldhead->control & SE_GROUP_DEFAULTED; 4703 targhead->revision = SECURITY_DESCRIPTOR_REVISION; 4704 targhead->alignment = 0; 4705 targhead->control = control; 4706 ok = !update_secur_descr(vol, target, ni); 4707 free(target); 4708 } 4709 return (ok); 4710 } 4711 4712 /* 4713 * Return the security descriptor of a file 4714 * This is intended to be similar to GetFileSecurity() from Win32 4715 * in order to facilitate the development of portable tools 4716 * 4717 * returns zero if unsuccessful (following Win32 conventions) 4718 * -1 if no securid 4719 * the securid if any 4720 * 4721 * The Win32 API is : 4722 * 4723 * BOOL WINAPI GetFileSecurity( 4724 * __in LPCTSTR lpFileName, 4725 * __in SECURITY_INFORMATION RequestedInformation, 4726 * __out_opt PSECURITY_DESCRIPTOR pSecurityDescriptor, 4727 * __in DWORD nLength, 4728 * __out LPDWORD lpnLengthNeeded 4729 * ); 4730 * 4731 */ 4732 4733 int ntfs_get_file_security(struct SECURITY_API *scapi, 4734 const char *path, u32 selection, 4735 char *buf, u32 buflen, u32 *psize) 4736 { 4737 ntfs_inode *ni; 4738 char *attr; 4739 int res; 4740 4741 res = 0; /* default return */ 4742 if (scapi && (scapi->magic == MAGIC_API)) { 4743 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path); 4744 if (ni) { 4745 attr = getsecurityattr(scapi->security.vol, ni); 4746 if (attr) { 4747 if (feedsecurityattr(attr,selection, 4748 buf,buflen,psize)) { 4749 if (test_nino_flag(ni, v3_Extensions) 4750 && ni->security_id) 4751 res = le32_to_cpu( 4752 ni->security_id); 4753 else 4754 res = -1; 4755 } 4756 free(attr); 4757 } 4758 ntfs_inode_close(ni); 4759 } else 4760 errno = ENOENT; 4761 if (!res) *psize = 0; 4762 } else 4763 errno = EINVAL; /* do not clear *psize */ 4764 return (res); 4765 } 4766 4767 4768 /* 4769 * Set the security descriptor of a file or directory 4770 * This is intended to be similar to SetFileSecurity() from Win32 4771 * in order to facilitate the development of portable tools 4772 * 4773 * returns zero if unsuccessful (following Win32 conventions) 4774 * -1 if no securid 4775 * the securid if any 4776 * 4777 * The Win32 API is : 4778 * 4779 * BOOL WINAPI SetFileSecurity( 4780 * __in LPCTSTR lpFileName, 4781 * __in SECURITY_INFORMATION SecurityInformation, 4782 * __in PSECURITY_DESCRIPTOR pSecurityDescriptor 4783 * ); 4784 */ 4785 4786 int ntfs_set_file_security(struct SECURITY_API *scapi, 4787 const char *path, u32 selection, const char *attr) 4788 { 4789 const SECURITY_DESCRIPTOR_RELATIVE *phead; 4790 ntfs_inode *ni; 4791 int attrsz; 4792 BOOL missing; 4793 char *oldattr; 4794 int res; 4795 4796 res = 0; /* default return */ 4797 if (scapi && (scapi->magic == MAGIC_API) && attr) { 4798 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; 4799 attrsz = ntfs_attr_size(attr); 4800 /* if selected, owner and group must be present or defaulted */ 4801 missing = ((selection & OWNER_SECURITY_INFORMATION) 4802 && !phead->owner 4803 && !(phead->control & SE_OWNER_DEFAULTED)) 4804 || ((selection & GROUP_SECURITY_INFORMATION) 4805 && !phead->group 4806 && !(phead->control & SE_GROUP_DEFAULTED)); 4807 if (!missing 4808 && (phead->control & SE_SELF_RELATIVE) 4809 && ntfs_valid_descr(attr, attrsz)) { 4810 ni = ntfs_pathname_to_inode(scapi->security.vol, 4811 NULL, path); 4812 if (ni) { 4813 oldattr = getsecurityattr(scapi->security.vol, 4814 ni); 4815 if (oldattr) { 4816 if (mergesecurityattr( 4817 scapi->security.vol, 4818 oldattr, attr, 4819 selection, ni)) { 4820 if (test_nino_flag(ni, 4821 v3_Extensions)) 4822 res = le32_to_cpu( 4823 ni->security_id); 4824 else 4825 res = -1; 4826 } 4827 free(oldattr); 4828 } 4829 ntfs_inode_close(ni); 4830 } 4831 } else 4832 errno = EINVAL; 4833 } else 4834 errno = EINVAL; 4835 return (res); 4836 } 4837 4838 4839 /* 4840 * Return the attributes of a file 4841 * This is intended to be similar to GetFileAttributes() from Win32 4842 * in order to facilitate the development of portable tools 4843 * 4844 * returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES) 4845 * 4846 * The Win32 API is : 4847 * 4848 * DWORD WINAPI GetFileAttributes( 4849 * __in LPCTSTR lpFileName 4850 * ); 4851 */ 4852 4853 int ntfs_get_file_attributes(struct SECURITY_API *scapi, const char *path) 4854 { 4855 ntfs_inode *ni; 4856 s32 attrib; 4857 4858 attrib = -1; /* default return */ 4859 if (scapi && (scapi->magic == MAGIC_API) && path) { 4860 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path); 4861 if (ni) { 4862 attrib = le32_to_cpu(ni->flags); 4863 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) 4864 attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY); 4865 else 4866 attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY); 4867 if (!attrib) 4868 attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL); 4869 4870 ntfs_inode_close(ni); 4871 } else 4872 errno = ENOENT; 4873 } else 4874 errno = EINVAL; /* do not clear *psize */ 4875 return (attrib); 4876 } 4877 4878 4879 /* 4880 * Set attributes to a file or directory 4881 * This is intended to be similar to SetFileAttributes() from Win32 4882 * in order to facilitate the development of portable tools 4883 * 4884 * Only a few flags can be set (same list as Win32) 4885 * 4886 * returns zero if unsuccessful (following Win32 conventions) 4887 * nonzero if successful 4888 * 4889 * The Win32 API is : 4890 * 4891 * BOOL WINAPI SetFileAttributes( 4892 * __in LPCTSTR lpFileName, 4893 * __in DWORD dwFileAttributes 4894 * ); 4895 */ 4896 4897 BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi, 4898 const char *path, s32 attrib) 4899 { 4900 ntfs_inode *ni; 4901 le32 settable; 4902 ATTR_FLAGS dirflags; 4903 int res; 4904 4905 res = 0; /* default return */ 4906 if (scapi && (scapi->magic == MAGIC_API) && path) { 4907 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path); 4908 if (ni) { 4909 settable = FILE_ATTR_SETTABLE; 4910 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { 4911 /* 4912 * Accept changing compression for a directory 4913 * and set index root accordingly 4914 */ 4915 settable |= FILE_ATTR_COMPRESSED; 4916 if ((ni->flags ^ cpu_to_le32(attrib)) 4917 & FILE_ATTR_COMPRESSED) { 4918 if (ni->flags & FILE_ATTR_COMPRESSED) 4919 dirflags = const_cpu_to_le16(0); 4920 else 4921 dirflags = ATTR_IS_COMPRESSED; 4922 res = ntfs_attr_set_flags(ni, 4923 AT_INDEX_ROOT, 4924 NTFS_INDEX_I30, 4, 4925 dirflags, 4926 ATTR_COMPRESSION_MASK); 4927 } 4928 } 4929 if (!res) { 4930 ni->flags = (ni->flags & ~settable) 4931 | (cpu_to_le32(attrib) & settable); 4932 NInoSetDirty(ni); 4933 NInoFileNameSetDirty(ni); 4934 } 4935 if (!ntfs_inode_close(ni)) 4936 res = -1; 4937 } else 4938 errno = ENOENT; 4939 } 4940 return (res); 4941 } 4942 4943 4944 BOOL ntfs_read_directory(struct SECURITY_API *scapi, 4945 const char *path, ntfs_filldir_t callback, void *context) 4946 { 4947 ntfs_inode *ni; 4948 BOOL ok; 4949 s64 pos; 4950 4951 ok = FALSE; /* default return */ 4952 if (scapi && (scapi->magic == MAGIC_API) && callback) { 4953 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path); 4954 if (ni) { 4955 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { 4956 pos = 0; 4957 ntfs_readdir(ni,&pos,context,callback); 4958 ok = !ntfs_inode_close(ni); 4959 } else { 4960 ntfs_inode_close(ni); 4961 errno = ENOTDIR; 4962 } 4963 } else 4964 errno = ENOENT; 4965 } else 4966 errno = EINVAL; /* do not clear *psize */ 4967 return (ok); 4968 } 4969 4970 /* 4971 * read $SDS (for auditing security data) 4972 * 4973 * Returns the number or read bytes, or -1 if there is an error 4974 */ 4975 4976 int ntfs_read_sds(struct SECURITY_API *scapi, 4977 char *buf, u32 size, u32 offset) 4978 { 4979 int got; 4980 4981 got = -1; /* default return */ 4982 if (scapi && (scapi->magic == MAGIC_API)) { 4983 if (scapi->security.vol->secure_ni) 4984 got = ntfs_attr_data_read(scapi->security.vol->secure_ni, 4985 STREAM_SDS, 4, buf, size, offset); 4986 else 4987 errno = EOPNOTSUPP; 4988 } else 4989 errno = EINVAL; 4990 return (got); 4991 } 4992 4993 /* 4994 * read $SII (for auditing security data) 4995 * 4996 * Returns next entry, or NULL if there is an error 4997 */ 4998 4999 INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi, 5000 INDEX_ENTRY *entry) 5001 { 5002 SII_INDEX_KEY key; 5003 INDEX_ENTRY *ret; 5004 BOOL found; 5005 ntfs_index_context *xsii; 5006 5007 ret = (INDEX_ENTRY*)NULL; /* default return */ 5008 if (scapi && (scapi->magic == MAGIC_API)) { 5009 xsii = scapi->security.vol->secure_xsii; 5010 if (xsii) { 5011 if (!entry) { 5012 key.security_id = const_cpu_to_le32(0); 5013 found = !ntfs_index_lookup((char*)&key, 5014 sizeof(SII_INDEX_KEY), xsii); 5015 /* not supposed to find */ 5016 if (!found && (errno == ENOENT)) 5017 ret = xsii->entry; 5018 } else 5019 ret = ntfs_index_next(entry,xsii); 5020 if (!ret) 5021 errno = ENODATA; 5022 } else 5023 errno = EOPNOTSUPP; 5024 } else 5025 errno = EINVAL; 5026 return (ret); 5027 } 5028 5029 /* 5030 * read $SDH (for auditing security data) 5031 * 5032 * Returns next entry, or NULL if there is an error 5033 */ 5034 5035 INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi, 5036 INDEX_ENTRY *entry) 5037 { 5038 SDH_INDEX_KEY key; 5039 INDEX_ENTRY *ret; 5040 BOOL found; 5041 ntfs_index_context *xsdh; 5042 5043 ret = (INDEX_ENTRY*)NULL; /* default return */ 5044 if (scapi && (scapi->magic == MAGIC_API)) { 5045 xsdh = scapi->security.vol->secure_xsdh; 5046 if (xsdh) { 5047 if (!entry) { 5048 key.hash = const_cpu_to_le32(0); 5049 key.security_id = const_cpu_to_le32(0); 5050 found = !ntfs_index_lookup((char*)&key, 5051 sizeof(SDH_INDEX_KEY), xsdh); 5052 /* not supposed to find */ 5053 if (!found && (errno == ENOENT)) 5054 ret = xsdh->entry; 5055 } else 5056 ret = ntfs_index_next(entry,xsdh); 5057 if (!ret) 5058 errno = ENODATA; 5059 } else errno = ENOTSUP; 5060 } else 5061 errno = EINVAL; 5062 return (ret); 5063 } 5064 5065 /* 5066 * Get the mapped user SID 5067 * A buffer of 40 bytes has to be supplied 5068 * 5069 * returns the size of the SID, or zero and errno set if not found 5070 */ 5071 5072 int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf) 5073 { 5074 const SID *usid; 5075 BIGSID defusid; 5076 int size; 5077 5078 size = 0; 5079 if (scapi && (scapi->magic == MAGIC_API)) { 5080 usid = ntfs_find_usid(scapi->security.mapping[MAPUSERS], uid, (SID*)&defusid); 5081 if (usid) { 5082 size = ntfs_sid_size(usid); 5083 memcpy(buf,usid,size); 5084 } else 5085 errno = ENODATA; 5086 } else 5087 errno = EINVAL; 5088 return (size); 5089 } 5090 5091 /* 5092 * Get the mapped group SID 5093 * A buffer of 40 bytes has to be supplied 5094 * 5095 * returns the size of the SID, or zero and errno set if not found 5096 */ 5097 5098 int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf) 5099 { 5100 const SID *gsid; 5101 BIGSID defgsid; 5102 int size; 5103 5104 size = 0; 5105 if (scapi && (scapi->magic == MAGIC_API)) { 5106 gsid = ntfs_find_gsid(scapi->security.mapping[MAPGROUPS], gid, (SID*)&defgsid); 5107 if (gsid) { 5108 size = ntfs_sid_size(gsid); 5109 memcpy(buf,gsid,size); 5110 } else 5111 errno = ENODATA; 5112 } else 5113 errno = EINVAL; 5114 return (size); 5115 } 5116 5117 /* 5118 * Get the user mapped to a SID 5119 * 5120 * returns the uid, or -1 if not found 5121 */ 5122 5123 int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid) 5124 { 5125 int uid; 5126 5127 uid = -1; 5128 if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(usid)) { 5129 if (ntfs_same_sid(usid,adminsid)) 5130 uid = 0; 5131 else { 5132 uid = ntfs_find_user(scapi->security.mapping[MAPUSERS], usid); 5133 if (!uid) { 5134 uid = -1; 5135 errno = ENODATA; 5136 } 5137 } 5138 } else 5139 errno = EINVAL; 5140 return (uid); 5141 } 5142 5143 /* 5144 * Get the group mapped to a SID 5145 * 5146 * returns the uid, or -1 if not found 5147 */ 5148 5149 int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid) 5150 { 5151 int gid; 5152 5153 gid = -1; 5154 if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(gsid)) { 5155 if (ntfs_same_sid(gsid,adminsid)) 5156 gid = 0; 5157 else { 5158 gid = ntfs_find_group(scapi->security.mapping[MAPGROUPS], gsid); 5159 if (!gid) { 5160 gid = -1; 5161 errno = ENODATA; 5162 } 5163 } 5164 } else 5165 errno = EINVAL; 5166 return (gid); 5167 } 5168 5169 /* 5170 * Initializations before calling ntfs_get_file_security() 5171 * ntfs_set_file_security() and ntfs_read_directory() 5172 * 5173 * Only allowed for root 5174 * 5175 * Returns an (obscured) struct SECURITY_API* needed for further calls 5176 * NULL if not root (EPERM) or device is mounted (EBUSY) 5177 */ 5178 5179 struct SECURITY_API *ntfs_initialize_file_security(const char *device, 5180 unsigned long flags) 5181 { 5182 ntfs_volume *vol; 5183 unsigned long mntflag; 5184 int mnt; 5185 struct SECURITY_API *scapi; 5186 struct SECURITY_CONTEXT *scx; 5187 5188 scapi = (struct SECURITY_API*)NULL; 5189 mnt = ntfs_check_if_mounted(device, &mntflag); 5190 if (!mnt && !(mntflag & NTFS_MF_MOUNTED) && !getuid()) { 5191 vol = ntfs_mount(device, flags); 5192 if (vol) { 5193 scapi = (struct SECURITY_API*) 5194 ntfs_malloc(sizeof(struct SECURITY_API)); 5195 if (!ntfs_volume_get_free_space(vol) 5196 && scapi) { 5197 scapi->magic = MAGIC_API; 5198 scapi->seccache = (struct PERMISSIONS_CACHE*)NULL; 5199 scx = &scapi->security; 5200 scx->vol = vol; 5201 scx->uid = getuid(); 5202 scx->gid = getgid(); 5203 scx->pseccache = &scapi->seccache; 5204 scx->vol->secure_flags = 0; 5205 /* accept no mapping and no $Secure */ 5206 ntfs_build_mapping(scx,(const char*)NULL,TRUE); 5207 ntfs_open_secure(vol); 5208 } else { 5209 if (scapi) 5210 free(scapi); 5211 else 5212 errno = ENOMEM; 5213 mnt = ntfs_umount(vol,FALSE); 5214 scapi = (struct SECURITY_API*)NULL; 5215 } 5216 } 5217 } else 5218 if (getuid()) 5219 errno = EPERM; 5220 else 5221 errno = EBUSY; 5222 return (scapi); 5223 } 5224 5225 /* 5226 * Leaving after ntfs_initialize_file_security() 5227 * 5228 * Returns FALSE if FAILED 5229 */ 5230 5231 BOOL ntfs_leave_file_security(struct SECURITY_API *scapi) 5232 { 5233 int ok; 5234 ntfs_volume *vol; 5235 5236 ok = FALSE; 5237 if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) { 5238 vol = scapi->security.vol; 5239 ntfs_close_secure(&scapi->security); 5240 free(scapi); 5241 if (!ntfs_umount(vol, 0)) 5242 ok = TRUE; 5243 } 5244 return (ok); 5245 } 5246 5247