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