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