2 * security.c - Handling security/ACLs in NTFS. Originated from the Linux-NTFS project.
4 * Copyright (c) 2004 Anton Altaparmakov
5 * Copyright (c) 2005-2006 Szabolcs Szakacsits
6 * Copyright (c) 2006 Yura Pakhuchiy
7 * Copyright (c) 2007-2010 Jean-Pierre Andre
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.
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.
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
31 /*#ifdef HAVE_STDIO_H*/
40 /*#ifdef HAVE_ERRNO_H*/
43 /*#ifdef HAVE_FCNTL_H*/
47 #include <sys/xattr.h>
49 #ifdef HAVE_SYS_STAT_H
57 #include <ntfs-3g/param.h>
58 #include <ntfs-3g/types.h>
59 #include <ntfs-3g/layout.h>
60 #include <ntfs-3g/attrib.h>
61 #include <ntfs-3g/index.h>
62 #include <ntfs-3g/dir.h>
63 #include <ntfs-3g/bitmap.h>
64 #include <ntfs-3g/security.h>
65 #include <ntfs-3g/acls.h>
66 #include <ntfs-3g/cache.h>
67 #include <ntfs-3g/misc.h>
70 * JPA NTFS constants or structs
71 * should be moved to layout.h
74 #define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */
75 #define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */
76 #define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */
77 #define FIRST_SECURITY_ID 0x100 /* Lowest security id */
79 /* Mask for attributes which can be forced */
80 #define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY \
84 | FILE_ATTR_TEMPORARY \
86 | FILE_ATTR_NOT_CONTENT_INDEXED )
88 struct SII { /* this is an image of an $SII index entry */
98 /* did not find official description for the following */
101 le32 dataoffsl; /* documented as badly aligned */
106 struct SDH { /* this is an image of an $SDH index entry */
117 /* did not find official description for the following */
127 * A few useful constants
130 static ntfschar sii_stream[] = { const_cpu_to_le16('$'),
131 const_cpu_to_le16('S'),
132 const_cpu_to_le16('I'),
133 const_cpu_to_le16('I'),
134 const_cpu_to_le16(0) };
135 static ntfschar sdh_stream[] = { const_cpu_to_le16('$'),
136 const_cpu_to_le16('S'),
137 const_cpu_to_le16('D'),
138 const_cpu_to_le16('H'),
139 const_cpu_to_le16(0) };
145 extern const SID *nullsid;
151 static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
152 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
153 static const GUID *const zero_guid = &__zero_guid;
156 * ntfs_guid_is_zero - check if a GUID is zero
157 * @guid: [IN] guid to check
159 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
160 * and FALSE otherwise.
162 BOOL ntfs_guid_is_zero(const GUID *guid)
164 return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
168 * ntfs_guid_to_mbs - convert a GUID to a multi byte string
169 * @guid: [IN] guid to convert
170 * @guid_str: [OUT] string in which to return the GUID (optional)
172 * Convert the GUID pointed to by @guid to a multi byte string of the form
173 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
174 * needs to be able to store at least 37 bytes.
176 * If @guid_str is not NULL it will contain the converted GUID on return. If
177 * it is NULL a string will be allocated and this will be returned. The caller
178 * is responsible for free()ing the string in that case.
180 * On success return the converted string and on failure return NULL with errno
181 * set to the error code.
183 char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
192 _guid_str = guid_str;
194 _guid_str = (char*)ntfs_malloc(37);
198 res = snprintf(_guid_str, 37,
199 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
200 (unsigned int)le32_to_cpu(guid->data1),
201 le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
202 guid->data4[0], guid->data4[1],
203 guid->data4[2], guid->data4[3], guid->data4[4],
204 guid->data4[5], guid->data4[6], guid->data4[7]);
214 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
215 * @sid: [IN] SID for which to determine the maximum string size
217 * Determine the maximum multi byte string size in bytes which is needed to
218 * store the standard textual representation of the SID pointed to by @sid.
219 * See ntfs_sid_to_mbs(), below.
221 * On success return the maximum number of bytes needed to store the multi byte
222 * string and on failure return -1 with errno set to the error code.
224 int ntfs_sid_to_mbs_size(const SID *sid)
228 if (!ntfs_sid_is_valid(sid)) {
232 /* Start with "S-". */
235 * Add the SID_REVISION. Hopefully the compiler will optimize this
236 * away as SID_REVISION is a constant.
238 for (i = SID_REVISION; i > 0; i /= 10)
243 * Add the identifier authority. If it needs to be in decimal, the
244 * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
245 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
247 if (!sid->identifier_authority.high_part)
252 * Finally, add the sub authorities. For each we have a "-" followed
253 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
255 size += (1 + 10) * sid->sub_authority_count;
256 /* We need the zero byte at the end, too. */
258 return size * sizeof(char);
262 * ntfs_sid_to_mbs - convert a SID to a multi byte string
263 * @sid: [IN] SID to convert
264 * @sid_str: [OUT] string in which to return the SID (optional)
265 * @sid_str_size: [IN] size in bytes of @sid_str
267 * Convert the SID pointed to by @sid to its standard textual representation.
268 * @sid_str (if not NULL) needs to be able to store at least
269 * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
270 * @sid_str if @sid_str is not NULL.
272 * The standard textual representation of the SID is of the form:
275 * - The first "S" is the literal character 'S' identifying the following
277 * - R is the revision level of the SID expressed as a sequence of digits
279 * - I is the 48-bit identifier_authority, expressed as digits in decimal,
280 * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
281 * - S... is one or more sub_authority values, expressed as digits in
284 * If @sid_str is not NULL it will contain the converted SUID on return. If it
285 * is NULL a string will be allocated and this will be returned. The caller is
286 * responsible for free()ing the string in that case.
288 * On success return the converted string and on failure return NULL with errno
289 * set to the error code.
291 char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
299 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
300 * check @sid, too. 8 is the minimum SID string size.
302 if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
306 /* Allocate string if not provided. */
308 cnt = ntfs_sid_to_mbs_size(sid);
311 s = (char*)ntfs_malloc(cnt);
315 /* So we know we allocated it. */
321 /* Start with "S-R-". */
322 i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
323 if (i < 0 || i >= cnt)
327 /* Add the identifier authority. */
328 for (u = i = 0, j = 40; i < 6; i++, j -= 8)
329 u += (u64)sid->identifier_authority.value[i] << j;
330 if (!sid->identifier_authority.high_part)
331 i = snprintf(s, cnt, "%lu", (unsigned long)u);
333 i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
334 if (i < 0 || i >= cnt)
338 /* Finally, add the sub authorities. */
339 for (j = 0; j < sid->sub_authority_count; j++) {
340 leauth = sid->sub_authority[j];
341 i = snprintf(s, cnt, "-%u", (unsigned int)
342 le32_to_cpu(leauth));
343 if (i < 0 || i >= cnt)
361 * ntfs_generate_guid - generatates a random current guid.
362 * @guid: [OUT] pointer to a GUID struct to hold the generated guid.
364 * perhaps not a very good random number generator though...
366 void ntfs_generate_guid(GUID *guid)
371 for (i = 0; i < sizeof(GUID); i++) {
372 p[i] = (u8)(random() & 0xFF);
374 p[7] = (p[7] & 0x0F) | 0x40;
376 p[8] = (p[8] & 0x3F) | 0x80;
381 * ntfs_security_hash - calculate the hash of a security descriptor
382 * @sd: self-relative security descriptor whose hash to calculate
383 * @length: size in bytes of the security descritor @sd
385 * Calculate the hash of the self-relative security descriptor @sd of length
388 * This hash is used in the $Secure system file as the primary key for the $SDH
389 * index and is also stored in the header of each security descriptor in the
390 * $SDS data stream as well as in the index data of both the $SII and $SDH
391 * indexes. In all three cases it forms part of the SDS_ENTRY_HEADER
394 * Return the calculated security hash in little endian.
396 le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len)
398 const le32 *pos = (const le32*)sd;
399 const le32 *end = pos + (len >> 2);
403 hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3);
406 return cpu_to_le32(hash);
410 * Get the first entry of current index block
411 * cut and pasted form ntfs_ie_get_first() in index.c
414 static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih)
416 return (INDEX_ENTRY*)((u8*)ih + le32_to_cpu(ih->entries_offset));
420 * Stuff a 256KB block into $SDS before writing descriptors
423 * This prevents $SDS from being automatically declared as sparse
424 * when the second copy of the first security descriptor is written
425 * 256KB further ahead.
427 * Having $SDS declared as a sparse file is not wrong by itself
428 * and chkdsk leaves it as a sparse file. It does however complain
429 * and add a sparse flag (0x0200) into field file_attributes of
430 * STANDARD_INFORMATION of $Secure. This probably means that a
431 * sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse
432 * files (FILE_ATTR_SPARSE_FILE).
434 * Windows normally does not convert to sparse attribute or sparse
435 * file. Stuffing is just a way to get to the same result.
438 static int entersecurity_stuff(ntfs_volume *vol, off_t offs)
447 stuff = (char*)ntfs_malloc(STUFFSZ);
449 memset(stuff, 0, STUFFSZ);
451 written = ntfs_attr_data_write(vol->secure_ni,
452 STREAM_SDS, 4, stuff, STUFFSZ, offs);
453 if (written == STUFFSZ) {
460 } while (!res && (total < ALIGN_SDS_BLOCK));
470 * Enter a new security descriptor into $Secure (data only)
471 * it has to be written twice with an offset of 256KB
473 * Should only be called by entersecurityattr() to ensure consistency
475 * Returns zero if sucessful
478 static int entersecurity_data(ntfs_volume *vol,
479 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
480 le32 hash, le32 keyid, off_t offs, int gap)
487 SECURITY_DESCRIPTOR_HEADER *phsds;
490 fullsz = attrsz + gap + sizeof(SECURITY_DESCRIPTOR_HEADER);
491 fullattr = (char*)ntfs_malloc(fullsz);
494 * Clear the gap from previous descriptor
495 * this could be useful for appending the second
496 * copy to the end of file. When creating a new
497 * 256K block, the gap is cleared while writing
501 memset(fullattr,0,gap);
502 memcpy(&fullattr[gap + sizeof(SECURITY_DESCRIPTOR_HEADER)],
504 phsds = (SECURITY_DESCRIPTOR_HEADER*)&fullattr[gap];
506 phsds->security_id = keyid;
507 phsds->offset = cpu_to_le64(offs);
508 phsds->length = cpu_to_le32(fullsz - gap);
509 written1 = ntfs_attr_data_write(vol->secure_ni,
510 STREAM_SDS, 4, fullattr, fullsz,
512 written2 = ntfs_attr_data_write(vol->secure_ni,
513 STREAM_SDS, 4, fullattr, fullsz,
514 offs - gap + ALIGN_SDS_BLOCK);
515 if ((written1 == fullsz)
516 && (written2 == written1))
527 * Enter a new security descriptor in $Secure (indexes only)
529 * Should only be called by entersecurityattr() to ensure consistency
531 * Returns zero if sucessful
534 static int entersecurity_indexes(ntfs_volume *vol, s64 attrsz,
535 le32 hash, le32 keyid, off_t offs)
545 ntfs_index_context *xsii;
546 ntfs_index_context *xsdh;
551 /* enter a new $SII record */
553 xsii = vol->secure_xsii;
554 ntfs_index_ctx_reinit(xsii);
555 newsii.offs = const_cpu_to_le16(20);
556 newsii.size = const_cpu_to_le16(sizeof(struct SII) - 20);
557 newsii.fill1 = const_cpu_to_le32(0);
558 newsii.indexsz = const_cpu_to_le16(sizeof(struct SII));
559 newsii.indexksz = const_cpu_to_le16(sizeof(SII_INDEX_KEY));
560 newsii.flags = const_cpu_to_le16(0);
561 newsii.fill2 = const_cpu_to_le16(0);
562 newsii.keysecurid = keyid;
564 newsii.securid = keyid;
565 realign.all = cpu_to_le64(offs);
566 newsii.dataoffsh = realign.parts.dataoffsh;
567 newsii.dataoffsl = realign.parts.dataoffsl;
568 newsii.datasize = cpu_to_le32(attrsz
569 + sizeof(SECURITY_DESCRIPTOR_HEADER));
570 if (!ntfs_ie_add(xsii,(INDEX_ENTRY*)&newsii)) {
572 /* enter a new $SDH record */
574 xsdh = vol->secure_xsdh;
575 ntfs_index_ctx_reinit(xsdh);
576 newsdh.offs = const_cpu_to_le16(24);
577 newsdh.size = const_cpu_to_le16(
578 sizeof(SECURITY_DESCRIPTOR_HEADER));
579 newsdh.fill1 = const_cpu_to_le32(0);
580 newsdh.indexsz = const_cpu_to_le16(
582 newsdh.indexksz = const_cpu_to_le16(
583 sizeof(SDH_INDEX_KEY));
584 newsdh.flags = const_cpu_to_le16(0);
585 newsdh.fill2 = const_cpu_to_le16(0);
586 newsdh.keyhash = hash;
587 newsdh.keysecurid = keyid;
589 newsdh.securid = keyid;
590 newsdh.dataoffsh = realign.parts.dataoffsh;
591 newsdh.dataoffsl = realign.parts.dataoffsl;
592 newsdh.datasize = cpu_to_le32(attrsz
593 + sizeof(SECURITY_DESCRIPTOR_HEADER));
594 /* special filler value, Windows generally */
595 /* fills with 0x00490049, sometimes with zero */
596 newsdh.fill3 = const_cpu_to_le32(0x00490049);
597 if (!ntfs_ie_add(xsdh,(INDEX_ENTRY*)&newsdh))
604 * Enter a new security descriptor in $Secure (data and indexes)
605 * Returns id of entry, or zero if there is a problem.
606 * (should not be called for NTFS version < 3.0)
608 * important : calls have to be serialized, however no locking is
609 * needed while fuse is not multithreaded
612 static le32 entersecurityattr(ntfs_volume *vol,
613 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
633 ntfs_index_context *xsii;
638 /* find the first available securid beyond the last key */
639 /* in $Secure:$SII. This also determines the first */
640 /* available location in $Secure:$SDS, as this stream */
641 /* is always appended to and the id's are allocated */
644 securid = const_cpu_to_le32(0);
645 xsii = vol->secure_xsii;
646 ntfs_index_ctx_reinit(xsii);
648 keyid = const_cpu_to_le32(-1);
650 found = !ntfs_index_lookup((char*)&keyid,
651 sizeof(SII_INDEX_KEY), xsii);
652 if (!found && (errno != ENOENT)) {
653 ntfs_log_perror("Inconsistency in index $SII");
654 psii = (struct SII*)NULL;
656 /* restore errno to avoid misinterpretation */
659 psii = (struct SII*)xsii->entry;
663 * Get last entry in block, but must get first one
664 * one first, as we should already be beyond the
665 * last one. For some reason the search for the last
666 * entry sometimes does not return the last block...
667 * we assume this can only happen in root block
669 if (xsii->is_in_root)
670 entry = ntfs_ie_get_first
671 ((INDEX_HEADER*)&xsii->ir->index);
673 entry = ntfs_ie_get_first
674 ((INDEX_HEADER*)&xsii->ib->index);
676 * All index blocks should be at least half full
677 * so there always is a last entry but one,
678 * except when creating the first entry in index root.
679 * This was however found not to be true : chkdsk
680 * sometimes deletes all the (unused) keys in the last
681 * index block without rebalancing the tree.
682 * When this happens, a new search is restarted from
685 keyid = const_cpu_to_le32(0);
688 next = ntfs_index_next(entry,xsii);
690 psii = (struct SII*)next;
691 /* save last key and */
692 /* available position */
693 keyid = psii->keysecurid;
694 realign.parts.dataoffsh
696 realign.parts.dataoffsl
698 offs = le64_to_cpu(realign.all);
699 size = le32_to_cpu(psii->datasize);
702 if (!entry && !keyid && !retries) {
703 /* search failed, retry from smallest key */
704 ntfs_index_ctx_reinit(xsii);
705 found = !ntfs_index_lookup((char*)&keyid,
706 sizeof(SII_INDEX_KEY), xsii);
707 if (!found && (errno != ENOENT)) {
708 ntfs_log_perror("Index $SII is broken");
720 * could not find any entry, before creating the first
721 * entry, make a double check by making sure size of $SII
722 * is less than needed for one entry
724 securid = const_cpu_to_le32(0);
725 na = ntfs_attr_open(vol->secure_ni,AT_INDEX_ROOT,sii_stream,4);
727 if ((size_t)na->data_size < sizeof(struct SII)) {
728 ntfs_log_error("Creating the first security_id\n");
729 securid = const_cpu_to_le32(FIRST_SECURITY_ID);
734 ntfs_log_error("Error creating a security_id\n");
738 newkey = le32_to_cpu(keyid) + 1;
739 securid = cpu_to_le32(newkey);
742 * The security attr has to be written twice 256KB
743 * apart. This implies that offsets like
744 * 0x40000*odd_integer must be left available for
745 * the second copy. So align to next block when
746 * the last byte overflows on a wrong block.
750 gap = (-size) & (ALIGN_SDS_ENTRY - 1);
752 if ((offs + attrsz + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
754 offs = ((offs + attrsz
755 + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
756 | (ALIGN_SDS_BLOCK - 1)) + 1;
758 if (!(offs & (ALIGN_SDS_BLOCK - 1)))
759 entersecurity_stuff(vol, offs);
761 * now write the security attr to storage :
762 * first data, then SII, then SDH
763 * If failure occurs while writing SDS, data will never
764 * be accessed through indexes, and will be overwritten
765 * by the next allocated descriptor
766 * If failure occurs while writing SII, the id has not
767 * recorded and will be reallocated later
768 * If failure occurs while writing SDH, the space allocated
769 * in SDS or SII will not be reused, an inconsistency
770 * will persist with no significant consequence
772 if (entersecurity_data(vol, attr, attrsz, hash, securid, offs, gap)
773 || entersecurity_indexes(vol, attrsz, hash, securid, offs))
774 securid = const_cpu_to_le32(0);
776 /* inode now is dirty, synchronize it all */
777 ntfs_index_entry_mark_dirty(vol->secure_xsii);
778 ntfs_index_ctx_reinit(vol->secure_xsii);
779 ntfs_index_entry_mark_dirty(vol->secure_xsdh);
780 ntfs_index_ctx_reinit(vol->secure_xsdh);
781 NInoSetDirty(vol->secure_ni);
782 if (ntfs_inode_sync(vol->secure_ni))
783 ntfs_log_perror("Could not sync $Secure\n");
788 * Find a matching security descriptor in $Secure,
789 * if none, allocate a new id and write the descriptor to storage
790 * Returns id of entry, or zero if there is a problem.
792 * important : calls have to be serialized, however no locking is
793 * needed while fuse is not multithreaded
796 static le32 setsecurityattr(ntfs_volume *vol,
797 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz)
799 struct SDH *psdh; /* this is an image of index (le) */
813 ntfs_index_context *xsdh;
821 hash = ntfs_security_hash(attr,attrsz);
822 oldattr = (char*)NULL;
823 securid = const_cpu_to_le32(0);
825 xsdh = vol->secure_xsdh;
826 if (vol->secure_ni && xsdh && !vol->secure_reentry++) {
827 ntfs_index_ctx_reinit(xsdh);
829 * find the nearest key as (hash,0)
830 * (do not search for partial key : in case of collision,
831 * it could return a key which is not the first one which
835 key.security_id = const_cpu_to_le32(0);
837 found = !ntfs_index_lookup((char*)&key,
838 sizeof(SDH_INDEX_KEY), xsdh);
839 if (!found && (errno != ENOENT))
840 ntfs_log_perror("Inconsistency in index $SDH");
842 /* restore errno to avoid misinterpretation */
847 * lookup() may return a node with no data,
850 if (entry->ie_flags & INDEX_ENTRY_END)
851 entry = ntfs_index_next(entry,xsdh);
854 psdh = (struct SDH*)entry;
856 size = (size_t) le32_to_cpu(psdh->datasize)
857 - sizeof(SECURITY_DESCRIPTOR_HEADER);
859 /* if hash is not the same, the key is not present */
860 if (psdh && (size > 0)
861 && (psdh->keyhash == hash)) {
862 /* if hash is the same */
863 /* check the whole record */
864 realign.parts.dataoffsh = psdh->dataoffsh;
865 realign.parts.dataoffsl = psdh->dataoffsl;
866 offs = le64_to_cpu(realign.all)
867 + sizeof(SECURITY_DESCRIPTOR_HEADER);
868 oldattr = (char*)ntfs_malloc(size);
870 rdsize = ntfs_attr_data_read(
873 oldattr, size, offs);
874 found = (rdsize == size)
875 && !memcmp(oldattr,attr,size);
877 /* if the records do not compare */
878 /* (hash collision), try next one */
880 entry = ntfs_index_next(
887 } while (collision && entry);
889 securid = psdh->keysecurid;
893 securid = const_cpu_to_le32(0);
897 * have to build a new one
899 securid = entersecurityattr(vol,
905 if (--vol->secure_reentry)
906 ntfs_log_perror("Reentry error, check no multithreading\n");
912 * Update the security descriptor of a file
913 * Either as an attribute (complying with pre v3.x NTFS version)
914 * or, when possible, as an entry in $Secure (for NTFS v3.x)
916 * returns 0 if success
919 static int update_secur_descr(ntfs_volume *vol,
920 char *newattr, ntfs_inode *ni)
927 newattrsz = ntfs_attr_size(newattr);
929 #if !FORCE_FORMAT_v1x
930 if ((vol->major_ver < 3) || !vol->secure_ni) {
933 /* update for NTFS format v1.x */
935 /* update the old security attribute */
936 na = ntfs_attr_open(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0);
938 /* resize attribute */
939 res = ntfs_attr_truncate(na, (s64) newattrsz);
940 /* overwrite value */
942 written = (int)ntfs_attr_pwrite(na, (s64) 0,
943 (s64) newattrsz, newattr);
944 if (written != newattrsz) {
945 ntfs_log_error("Failed to update "
946 "a v1.x security descriptor\n");
953 /* if old security attribute was found, also */
954 /* truncate standard information attribute to v1.x */
955 /* this is needed when security data is wanted */
956 /* as v1.x though volume is formatted for v3.x */
957 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
960 clear_nino_flag(ni, v3_Extensions);
962 * Truncating the record does not sweep extensions
963 * from copy in memory. Clear security_id to be safe
965 ni->security_id = const_cpu_to_le32(0);
966 res = ntfs_attr_truncate(na, (s64)48);
968 clear_nino_flag(ni, v3_Extensions);
972 * insert the new security attribute if there
975 res = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR,
976 AT_UNNAMED, 0, (u8*)newattr,
979 #if !FORCE_FORMAT_v1x
982 /* update for NTFS format v3.x */
986 securid = setsecurityattr(vol,
987 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
990 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
994 if (!test_nino_flag(ni, v3_Extensions)) {
995 /* expand standard information attribute to v3.x */
996 res = ntfs_attr_truncate(na,
997 (s64)sizeof(STANDARD_INFORMATION));
998 ni->owner_id = const_cpu_to_le32(0);
999 ni->quota_charged = const_cpu_to_le64(0);
1000 ni->usn = const_cpu_to_le64(0);
1001 ntfs_attr_remove(ni,
1002 AT_SECURITY_DESCRIPTOR,
1005 set_nino_flag(ni, v3_Extensions);
1006 ni->security_id = securid;
1007 ntfs_attr_close(na);
1009 ntfs_log_error("Failed to update "
1010 "standard informations\n");
1019 /* mark node as dirty */
1025 * Upgrade the security descriptor of a file
1026 * This is intended to allow graceful upgrades for files which
1027 * were created in previous versions, with a security attributes
1028 * and no security id.
1030 * It will allocate a security id and replace the individual
1031 * security attribute by a reference to the global one
1033 * Special files are not upgraded (currently / and files in
1036 * Though most code is similar to update_secur_desc() it has
1037 * been kept apart to facilitate the further processing of
1038 * special cases or even to remove it if found dangerous.
1040 * returns 0 if success,
1041 * 1 if not upgradable. This is not an error.
1042 * -1 if there is a problem
1045 static int upgrade_secur_desc(ntfs_volume *vol,
1046 const char *attr, ntfs_inode *ni)
1054 * upgrade requires NTFS format v3.x
1055 * also refuse upgrading for special files
1056 * whose number is less than FILE_first_user
1059 if ((vol->major_ver >= 3)
1060 && (ni->mft_no >= FILE_first_user)) {
1061 attrsz = ntfs_attr_size(attr);
1062 securid = setsecurityattr(vol,
1063 (const SECURITY_DESCRIPTOR_RELATIVE*)attr,
1066 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
1069 /* expand standard information attribute to v3.x */
1070 res = ntfs_attr_truncate(na,
1071 (s64)sizeof(STANDARD_INFORMATION));
1072 ni->owner_id = const_cpu_to_le32(0);
1073 ni->quota_charged = const_cpu_to_le64(0);
1074 ni->usn = const_cpu_to_le64(0);
1075 ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR,
1077 set_nino_flag(ni, v3_Extensions);
1078 ni->security_id = securid;
1079 ntfs_attr_close(na);
1081 ntfs_log_error("Failed to upgrade "
1082 "standard informations\n");
1088 /* mark node as dirty */
1097 * Optional simplified checking of group membership
1099 * This only takes into account the groups defined in
1100 * /etc/group at initialization time.
1101 * It does not take into account the groups dynamically set by
1102 * setgroups() nor the changes in /etc/group since initialization
1104 * This optional method could be useful if standard checking
1105 * leads to a performance concern.
1107 * Should not be called for user root, however the group may be root
1111 static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1116 struct MAPPING *user;
1120 user = scx->mapping[MAPUSERS];
1121 while (user && ((uid_t)user->xid != uid))
1124 groups = user->groups;
1125 grcnt = user->grcnt;
1126 while ((--grcnt >= 0) && (groups[grcnt] != gid)) { }
1127 ingroup = (grcnt >= 0);
1135 * Check whether current thread owner is member of file group
1137 * Should not be called for user root, however the group may be root
1139 * As indicated by Miklos Szeredi :
1141 * The group list is available in
1143 * /proc/$PID/task/$TID/status
1145 * and fuse supplies TID in get_fuse_context()->pid. The only problem is
1146 * finding out PID, for which I have no good solution, except to iterate
1147 * through all processes. This is rather slow, but may be speeded up
1148 * with caching and heuristics (for single threaded programs PID = TID).
1150 * The following implementation gets the group list from
1151 * /proc/$TID/task/$TID/status which apparently exists and
1152 * contains the same data.
1155 static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1157 static char key[] = "\nGroups:";
1160 enum { INKEY, INSEP, INNUM, INEND } state;
1170 if (scx->vol->secure_flags & (1 << SECURITY_STATICGRPS))
1171 ismember = staticgroupmember(scx, uid, gid);
1173 ismember = FALSE; /* default return */
1175 sprintf(filename,"/proc/%u/task/%u/status",tid,tid);
1176 fd = open(filename,O_RDONLY);
1178 got = read(fd, buf, BUFSZ);
1185 * A simple automaton to process lines like
1186 * Groups: 14 500 513
1192 got = read(fd, buf, BUFSZ);
1195 c = *p++; /* 0 at end of file */
1199 if (key[matched] == c) {
1200 if (!key[++matched])
1209 if ((c >= '0') && (c <= '9')) {
1213 if ((c != ' ') && (c != '\t'))
1217 if ((c >= '0') && (c <= '9'))
1218 grp = grp*10 + c - '0';
1220 ismember = (grp == gid);
1221 if ((c != ' ') && (c != '\t'))
1229 } while (!ismember && c && (state != INEND));
1232 ntfs_log_error("No group record found in %s\n",filename);
1234 ntfs_log_error("Could not open %s\n",filename);
1240 * Cacheing is done two-way :
1241 * - from uid, gid and perm to securid (CACHED_SECURID)
1242 * - from a securid to uid, gid and perm (CACHED_PERMISSIONS)
1244 * CACHED_SECURID data is kept in a most-recent-first list
1245 * which should not be too long to be efficient. Its optimal
1246 * size is depends on usage and is hard to determine.
1248 * CACHED_PERMISSIONS data is kept in a two-level indexed array. It
1249 * is optimal at the expense of storage. Use of a most-recent-first
1250 * list would save memory and provide similar performances for
1251 * standard usage, but not for file servers with too many file
1254 * CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS
1255 * for legacy directories which were not allocated a security_id
1256 * it is organized in a most-recent-first list.
1258 * In main caches, data is never invalidated, as the meaning of
1259 * a security_id only changes when user mapping is changed, which
1260 * current implies remounting. However returned entries may be
1261 * overwritten at next update, so data has to be copied elsewhere
1262 * before another cache update is made.
1263 * In legacy cache, data has to be invalidated when protection is
1266 * Though the same data may be found in both list, they
1267 * must be kept separately : the interpretation of ACL
1268 * in both direction are approximations which could be non
1269 * reciprocal for some configuration of the user mapping data
1271 * During the process of recompiling ntfs-3g from a tgz archive,
1272 * security processing added 7.6% to the cpu time used by ntfs-3g
1273 * and 30% if the cache is disabled.
1276 static struct PERMISSIONS_CACHE *create_caches(struct SECURITY_CONTEXT *scx,
1279 struct PERMISSIONS_CACHE *cache;
1280 unsigned int index1;
1283 cache = (struct PERMISSIONS_CACHE*)NULL;
1284 /* create the first permissions blocks */
1285 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1286 cache = (struct PERMISSIONS_CACHE*)
1287 ntfs_malloc(sizeof(struct PERMISSIONS_CACHE)
1288 + index1*sizeof(struct CACHED_PERMISSIONS*));
1290 cache->head.last = index1;
1291 cache->head.p_reads = 0;
1292 cache->head.p_hits = 0;
1293 cache->head.p_writes = 0;
1294 *scx->pseccache = cache;
1295 for (i=0; i<=index1; i++)
1296 cache->cachetable[i]
1297 = (struct CACHED_PERMISSIONS*)NULL;
1303 * Free memory used by caches
1304 * The only purpose is to facilitate the detection of memory leaks
1307 static void free_caches(struct SECURITY_CONTEXT *scx)
1309 unsigned int index1;
1310 struct PERMISSIONS_CACHE *pseccache;
1312 pseccache = *scx->pseccache;
1314 for (index1=0; index1<=pseccache->head.last; index1++)
1315 if (pseccache->cachetable[index1]) {
1317 struct CACHED_PERMISSIONS *cacheentry;
1318 unsigned int index2;
1320 for (index2=0; index2<(1<< CACHE_PERMISSIONS_BITS); index2++) {
1321 cacheentry = &pseccache->cachetable[index1][index2];
1322 if (cacheentry->valid
1323 && cacheentry->pxdesc)
1324 free(cacheentry->pxdesc);
1327 free(pseccache->cachetable[index1]);
1333 static int compare(const struct CACHED_SECURID *cached,
1334 const struct CACHED_SECURID *item)
1340 /* only compare data and sizes */
1341 csize = (cached->variable ?
1342 sizeof(struct POSIX_ACL)
1343 + (((struct POSIX_SECURITY*)cached->variable)->acccnt
1344 + ((struct POSIX_SECURITY*)cached->variable)->defcnt)
1345 *sizeof(struct POSIX_ACE) :
1347 isize = (item->variable ?
1348 sizeof(struct POSIX_ACL)
1349 + (((struct POSIX_SECURITY*)item->variable)->acccnt
1350 + ((struct POSIX_SECURITY*)item->variable)->defcnt)
1351 *sizeof(struct POSIX_ACE) :
1353 return ((cached->uid != item->uid)
1354 || (cached->gid != item->gid)
1355 || (cached->dmode != item->dmode)
1359 && memcmp(&((struct POSIX_SECURITY*)cached->variable)->acl,
1360 &((struct POSIX_SECURITY*)item->variable)->acl, csize)));
1362 return ((cached->uid != item->uid)
1363 || (cached->gid != item->gid)
1364 || (cached->dmode != item->dmode));
1368 static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached,
1369 const struct CACHED_PERMISSIONS_LEGACY *item)
1371 return (cached->mft_no != item->mft_no);
1375 * Resize permission cache table
1376 * do not call unless resizing is needed
1378 * If allocation fails, the cache size is not updated
1379 * Lack of memory is not considered as an error, the cache is left
1380 * consistent and errno is not set.
1383 static void resize_cache(struct SECURITY_CONTEXT *scx,
1386 struct PERMISSIONS_CACHE *oldcache;
1387 struct PERMISSIONS_CACHE *newcache;
1390 unsigned int index1;
1393 oldcache = *scx->pseccache;
1394 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1395 newcnt = index1 + 1;
1396 if (newcnt <= ((CACHE_PERMISSIONS_SIZE
1397 + (1 << CACHE_PERMISSIONS_BITS)
1398 - 1) >> CACHE_PERMISSIONS_BITS)) {
1399 /* expand cache beyond current end, do not use realloc() */
1400 /* to avoid losing data when there is no more memory */
1401 oldcnt = oldcache->head.last + 1;
1402 newcache = (struct PERMISSIONS_CACHE*)
1404 sizeof(struct PERMISSIONS_CACHE)
1405 + (newcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
1407 memcpy(newcache,oldcache,
1408 sizeof(struct PERMISSIONS_CACHE)
1409 + (oldcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
1411 /* mark new entries as not valid */
1412 for (i=newcache->head.last+1; i<=index1; i++)
1413 newcache->cachetable[i]
1414 = (struct CACHED_PERMISSIONS*)NULL;
1415 newcache->head.last = index1;
1416 *scx->pseccache = newcache;
1422 * Enter uid, gid and mode into cache, if possible
1424 * returns the updated or created cache entry,
1425 * or NULL if not possible (typically if there is no
1426 * security id associated)
1430 static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
1431 ntfs_inode *ni, uid_t uid, gid_t gid,
1432 struct POSIX_SECURITY *pxdesc)
1434 static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
1435 ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode)
1438 struct CACHED_PERMISSIONS *cacheentry;
1439 struct CACHED_PERMISSIONS *cacheblock;
1440 struct PERMISSIONS_CACHE *pcache;
1444 struct POSIX_SECURITY *pxcached;
1446 unsigned int index1;
1447 unsigned int index2;
1450 /* cacheing is only possible if a security_id has been defined */
1451 if (test_nino_flag(ni, v3_Extensions)
1452 && ni->security_id) {
1454 * Immediately test the most frequent situation
1455 * where the entry exists
1457 securindex = le32_to_cpu(ni->security_id);
1458 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1459 index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
1460 pcache = *scx->pseccache;
1462 && (pcache->head.last >= index1)
1463 && pcache->cachetable[index1]) {
1464 cacheentry = &pcache->cachetable[index1][index2];
1465 cacheentry->uid = uid;
1466 cacheentry->gid = gid;
1468 if (cacheentry->valid && cacheentry->pxdesc)
1469 free(cacheentry->pxdesc);
1471 pxsize = sizeof(struct POSIX_SECURITY)
1472 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1473 pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
1475 memcpy(pxcached, pxdesc, pxsize);
1476 cacheentry->pxdesc = pxcached;
1478 cacheentry->valid = 0;
1479 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1481 cacheentry->mode = pxdesc->mode & 07777;
1483 cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
1485 cacheentry->mode = mode & 07777;
1487 cacheentry->inh_fileid = const_cpu_to_le32(0);
1488 cacheentry->inh_dirid = const_cpu_to_le32(0);
1489 cacheentry->valid = 1;
1490 pcache->head.p_writes++;
1493 /* create the first cache block */
1494 pcache = create_caches(scx, securindex);
1496 if (index1 > pcache->head.last) {
1497 resize_cache(scx, securindex);
1498 pcache = *scx->pseccache;
1501 /* allocate block, if cache table was allocated */
1502 if (pcache && (index1 <= pcache->head.last)) {
1503 cacheblock = (struct CACHED_PERMISSIONS*)
1504 malloc(sizeof(struct CACHED_PERMISSIONS)
1505 << CACHE_PERMISSIONS_BITS);
1506 pcache->cachetable[index1] = cacheblock;
1507 for (i=0; i<(1 << CACHE_PERMISSIONS_BITS); i++)
1508 cacheblock[i].valid = 0;
1509 cacheentry = &cacheblock[index2];
1511 cacheentry->uid = uid;
1512 cacheentry->gid = gid;
1515 pxsize = sizeof(struct POSIX_SECURITY)
1516 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1517 pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
1519 memcpy(pxcached, pxdesc, pxsize);
1520 cacheentry->pxdesc = pxcached;
1522 cacheentry->valid = 0;
1523 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1525 cacheentry->mode = pxdesc->mode & 07777;
1527 cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
1529 cacheentry->mode = mode & 07777;
1531 cacheentry->inh_fileid = const_cpu_to_le32(0);
1532 cacheentry->inh_dirid = const_cpu_to_le32(0);
1533 cacheentry->valid = 1;
1534 pcache->head.p_writes++;
1537 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1540 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1541 #if CACHE_LEGACY_SIZE
1542 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1543 struct CACHED_PERMISSIONS_LEGACY wanted;
1544 struct CACHED_PERMISSIONS_LEGACY *legacy;
1546 wanted.perm.uid = uid;
1547 wanted.perm.gid = gid;
1549 wanted.perm.mode = pxdesc->mode & 07777;
1550 wanted.perm.inh_fileid = const_cpu_to_le32(0);
1551 wanted.perm.inh_dirid = const_cpu_to_le32(0);
1552 wanted.mft_no = ni->mft_no;
1553 wanted.variable = (void*)pxdesc;
1554 wanted.varsize = sizeof(struct POSIX_SECURITY)
1555 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1557 wanted.perm.mode = mode & 07777;
1558 wanted.perm.inh_fileid = const_cpu_to_le32(0);
1559 wanted.perm.inh_dirid = const_cpu_to_le32(0);
1560 wanted.mft_no = ni->mft_no;
1561 wanted.variable = (void*)NULL;
1564 legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_enter_cache(
1565 scx->vol->legacy_cache, GENERIC(&wanted),
1566 (cache_compare)leg_compare);
1568 cacheentry = &legacy->perm;
1571 * give direct access to the cached pxdesc
1572 * in the permissions structure
1574 cacheentry->pxdesc = legacy->variable;
1580 return (cacheentry);
1584 * Fetch owner, group and permission of a file, if cached
1586 * Beware : do not use the returned entry after a cache update :
1587 * the cache may be relocated making the returned entry meaningless
1589 * returns the cache entry, or NULL if not available
1592 static struct CACHED_PERMISSIONS *fetch_cache(struct SECURITY_CONTEXT *scx,
1595 struct CACHED_PERMISSIONS *cacheentry;
1596 struct PERMISSIONS_CACHE *pcache;
1598 unsigned int index1;
1599 unsigned int index2;
1601 /* cacheing is only possible if a security_id has been defined */
1602 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1603 if (test_nino_flag(ni, v3_Extensions)
1604 && (ni->security_id)) {
1605 securindex = le32_to_cpu(ni->security_id);
1606 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1607 index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
1608 pcache = *scx->pseccache;
1610 && (pcache->head.last >= index1)
1611 && pcache->cachetable[index1]) {
1612 cacheentry = &pcache->cachetable[index1][index2];
1613 /* reject if entry is not valid */
1614 if (!cacheentry->valid)
1615 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1617 pcache->head.p_hits++;
1619 pcache->head.p_reads++;
1622 #if CACHE_LEGACY_SIZE
1624 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1625 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1626 struct CACHED_PERMISSIONS_LEGACY wanted;
1627 struct CACHED_PERMISSIONS_LEGACY *legacy;
1629 wanted.mft_no = ni->mft_no;
1630 wanted.variable = (void*)NULL;
1632 legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_fetch_cache(
1633 scx->vol->legacy_cache, GENERIC(&wanted),
1634 (cache_compare)leg_compare);
1635 if (legacy) cacheentry = &legacy->perm;
1640 if (cacheentry && !cacheentry->pxdesc) {
1641 ntfs_log_error("No Posix descriptor in cache\n");
1642 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1645 return (cacheentry);
1649 * Retrieve a security attribute from $Secure
1652 static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id)
1667 ntfs_index_context *xsii;
1670 securattr = (char*)NULL;
1671 ni = vol->secure_ni;
1672 xsii = vol->secure_xsii;
1674 ntfs_index_ctx_reinit(xsii);
1676 !ntfs_index_lookup((char*)&id,
1677 sizeof(SII_INDEX_KEY), xsii);
1679 psii = (struct SII*)xsii->entry;
1681 (size_t) le32_to_cpu(psii->datasize)
1682 - sizeof(SECURITY_DESCRIPTOR_HEADER);
1683 /* work around bad alignment problem */
1684 realign.parts.dataoffsh = psii->dataoffsh;
1685 realign.parts.dataoffsl = psii->dataoffsl;
1686 offs = le64_to_cpu(realign.all)
1687 + sizeof(SECURITY_DESCRIPTOR_HEADER);
1689 securattr = (char*)ntfs_malloc(size);
1691 rdsize = ntfs_attr_data_read(
1693 securattr, size, offs);
1694 if ((rdsize != size)
1695 || !ntfs_valid_descr(securattr,
1697 /* error to be logged by caller */
1699 securattr = (char*)NULL;
1703 if (errno != ENOENT)
1704 ntfs_log_perror("Inconsistency in index $SII");
1707 ntfs_log_error("Failed to retrieve a security descriptor\n");
1714 * Get the security descriptor associated to a file
1717 * - read the security descriptor attribute (v1.x format)
1718 * - or find the descriptor in $Secure:$SDS (v3.x format)
1720 * in both case, sanity checks are done on the attribute and
1721 * the descriptor can be assumed safe
1723 * The returned descriptor is dynamically allocated and has to be freed
1726 static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni)
1728 SII_INDEX_KEY securid;
1733 * Warning : in some situations, after fixing by chkdsk,
1734 * v3_Extensions are marked present (long standard informations)
1735 * with a default security descriptor inserted in an
1738 if (test_nino_flag(ni, v3_Extensions)
1739 && vol->secure_ni && ni->security_id) {
1740 /* get v3.x descriptor in $Secure */
1741 securid.security_id = ni->security_id;
1742 securattr = retrievesecurityattr(vol,securid);
1744 ntfs_log_error("Bad security descriptor for 0x%lx\n",
1745 (long)le32_to_cpu(ni->security_id));
1747 /* get v1.x security attribute */
1749 securattr = ntfs_attr_readall(ni, AT_SECURITY_DESCRIPTOR,
1750 AT_UNNAMED, 0, &readallsz);
1751 if (securattr && !ntfs_valid_descr(securattr, readallsz)) {
1752 ntfs_log_error("Bad security descriptor for inode %lld\n",
1753 (long long)ni->mft_no);
1755 securattr = (char*)NULL;
1760 * in some situations, there is no security
1761 * descriptor, and chkdsk does not detect or fix
1762 * anything. This could be a normal situation.
1763 * When this happens, simulate a descriptor with
1764 * minimum rights, so that a real descriptor can
1765 * be created by chown or chmod
1767 ntfs_log_error("No security descriptor found for inode %lld\n",
1768 (long long)ni->mft_no);
1769 securattr = ntfs_build_descr(0, 0, adminsid, adminsid);
1777 * Determine which access types to a file are allowed
1778 * according to the relation of current process to the file
1780 * Do not call if default_permissions is set
1783 static int access_check_posix(struct SECURITY_CONTEXT *scx,
1784 struct POSIX_SECURITY *pxdesc, mode_t request,
1785 uid_t uid, gid_t gid)
1787 struct POSIX_ACE *pxace;
1796 perms = pxdesc->mode;
1797 /* owner and root access */
1798 if (!scx->uid || (uid == scx->uid)) {
1800 /* root access if owner or other execution */
1804 /* root access if some group execution */
1807 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1808 pxace = &pxdesc->acl.ace[i];
1809 switch (pxace->tag) {
1810 case POSIX_ACL_USER_OBJ :
1811 case POSIX_ACL_GROUP_OBJ :
1812 case POSIX_ACL_GROUP :
1813 groupperms |= pxace->perms;
1815 case POSIX_ACL_MASK :
1816 mask = pxace->perms & 7;
1822 perms = (groupperms & mask & 1) | 6;
1828 * analyze designated users, get mask
1829 * and identify whether we need to check
1830 * the group memberships. The groups are
1831 * not needed when all groups have the
1832 * same permissions as other for the
1839 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1840 pxace = &pxdesc->acl.ace[i];
1841 switch (pxace->tag) {
1842 case POSIX_ACL_USER :
1843 if ((uid_t)pxace->id == scx->uid)
1844 userperms = pxace->perms;
1846 case POSIX_ACL_MASK :
1847 mask = pxace->perms & 7;
1849 case POSIX_ACL_GROUP_OBJ :
1850 case POSIX_ACL_GROUP :
1851 if (((pxace->perms & mask) ^ perms)
1852 & (request >> 6) & 7)
1859 /* designated users */
1861 perms = (perms & 07000) + (userperms & mask);
1862 else if (!needgroups)
1866 if (!(~(perms >> 3) & request & mask)
1867 && ((gid == scx->gid)
1868 || groupmember(scx, scx->uid, gid)))
1874 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1875 pxace = &pxdesc->acl.ace[i];
1876 if ((pxace->tag == POSIX_ACL_GROUP)
1877 && groupmember(scx, uid, pxace->id)) {
1878 if (!(~pxace->perms & request & mask))
1879 groupperms = pxace->perms;
1883 if (groupperms >= 0)
1884 perms = (perms & 07000) + (groupperms & mask);
1897 * Get permissions to access a file
1898 * Takes into account the relation of user to file (owner, group, ...)
1899 * Do no use as mode of the file
1900 * Do no call if default_permissions is set
1902 * returns -1 if there is a problem
1905 static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
1906 ntfs_inode * ni, mode_t request)
1908 const SECURITY_DESCRIPTOR_RELATIVE *phead;
1909 const struct CACHED_PERMISSIONS *cached;
1911 const SID *usid; /* owner of file/directory */
1912 const SID *gsid; /* group of file/directory */
1917 struct POSIX_SECURITY *pxdesc;
1919 if (!scx->mapping[MAPUSERS])
1922 /* check whether available in cache */
1923 cached = fetch_cache(scx,ni);
1927 perm = access_check_posix(scx,cached->pxdesc,request,uid,gid);
1929 perm = 0; /* default to no permission */
1930 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
1931 != const_cpu_to_le16(0);
1932 securattr = getsecurityattr(scx->vol, ni);
1934 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
1936 gsid = (const SID*)&
1937 securattr[le32_to_cpu(phead->group)];
1938 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
1940 usid = ntfs_acl_owner(securattr);
1941 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
1944 perm = pxdesc->mode & 07777;
1947 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
1949 usid = (const SID*)&
1950 securattr[le32_to_cpu(phead->owner)];
1951 pxdesc = ntfs_build_permissions_posix(scx,securattr,
1954 perm = pxdesc->mode & 07777;
1957 if (!perm && ntfs_same_sid(usid, adminsid)) {
1958 uid = find_tenant(scx, securattr);
1962 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
1965 * Create a security id if there were none
1966 * and upgrade option is selected
1968 if (!test_nino_flag(ni, v3_Extensions)
1970 && (scx->vol->secure_flags
1971 & (1 << SECURITY_ADDSECURIDS))) {
1972 upgrade_secur_desc(scx->vol,
1975 * fetch owner and group for cacheing
1976 * if there is a securid
1979 if (test_nino_flag(ni, v3_Extensions)
1981 enter_cache(scx, ni, uid,
1985 perm = access_check_posix(scx,pxdesc,request,uid,gid);
2001 * returns size or -errno if there is a problem
2002 * if size was too small, no copy is done and errno is not set,
2003 * the caller is expected to issue a new call
2006 int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2007 const char *name, char *value, size_t size)
2009 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2010 struct POSIX_SECURITY *pxdesc;
2011 const struct CACHED_PERMISSIONS *cached;
2013 const SID *usid; /* owner of file/directory */
2014 const SID *gsid; /* group of file/directory */
2020 outsize = 0; /* default to error */
2021 if (!scx->mapping[MAPUSERS])
2024 /* check whether available in cache */
2025 cached = fetch_cache(scx,ni);
2027 pxdesc = cached->pxdesc;
2029 securattr = getsecurityattr(scx->vol, ni);
2030 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2031 != const_cpu_to_le16(0);
2034 (const SECURITY_DESCRIPTOR_RELATIVE*)
2036 gsid = (const SID*)&
2037 securattr[le32_to_cpu(phead->group)];
2039 usid = ntfs_acl_owner(securattr);
2041 usid = (const SID*)&
2042 securattr[le32_to_cpu(phead->owner)];
2044 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2048 * fetch owner and group for cacheing
2052 * Create a security id if there were none
2053 * and upgrade option is selected
2055 if (!test_nino_flag(ni, v3_Extensions)
2056 && (scx->vol->secure_flags
2057 & (1 << SECURITY_ADDSECURIDS))) {
2058 upgrade_secur_desc(scx->vol,
2062 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2064 if (!(pxdesc->mode & 07777)
2065 && ntfs_same_sid(usid, adminsid)) {
2066 uid = find_tenant(scx,
2069 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2071 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2072 if (pxdesc->tagsset & POSIX_ACL_EXTENSIONS)
2073 enter_cache(scx, ni, uid,
2078 pxdesc = (struct POSIX_SECURITY*)NULL;
2082 if (ntfs_valid_posix(pxdesc)) {
2083 if (!strcmp(name,"system.posix_acl_default")) {
2085 & MFT_RECORD_IS_DIRECTORY)
2086 outsize = sizeof(struct POSIX_ACL)
2087 + pxdesc->defcnt*sizeof(struct POSIX_ACE);
2090 * getting default ACL from plain file :
2091 * return EACCES if size > 0 as
2092 * indicated in the man, but return ok
2093 * if size == 0, so that ls does not
2100 outsize = sizeof(struct POSIX_ACL);
2102 if (outsize && (outsize <= size)) {
2103 memcpy(value,&pxdesc->acl,sizeof(struct POSIX_ACL));
2104 memcpy(&value[sizeof(struct POSIX_ACL)],
2105 &pxdesc->acl.ace[pxdesc->firstdef],
2106 outsize-sizeof(struct POSIX_ACL));
2109 outsize = sizeof(struct POSIX_ACL)
2110 + pxdesc->acccnt*sizeof(struct POSIX_ACE);
2111 if (outsize <= size)
2112 memcpy(value,&pxdesc->acl,outsize);
2117 ntfs_log_error("Invalid Posix ACL built\n");
2124 return (outsize ? (int)outsize : -errno);
2127 #else /* POSIXACLS */
2131 * Get permissions to access a file
2132 * Takes into account the relation of user to file (owner, group, ...)
2133 * Do no use as mode of the file
2135 * returns -1 if there is a problem
2138 static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
2139 ntfs_inode *ni, mode_t request)
2141 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2142 const struct CACHED_PERMISSIONS *cached;
2144 const SID *usid; /* owner of file/directory */
2145 const SID *gsid; /* group of file/directory */
2151 if (!scx->mapping[MAPUSERS] || (!scx->uid && !(request & S_IEXEC)))
2154 /* check whether available in cache */
2155 cached = fetch_cache(scx,ni);
2157 perm = cached->mode;
2161 perm = 0; /* default to no permission */
2162 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2163 != const_cpu_to_le16(0);
2164 securattr = getsecurityattr(scx->vol, ni);
2166 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2168 gsid = (const SID*)&
2169 securattr[le32_to_cpu(phead->group)];
2170 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2172 usid = ntfs_acl_owner(securattr);
2173 perm = ntfs_build_permissions(securattr,
2175 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2177 usid = (const SID*)&
2178 securattr[le32_to_cpu(phead->owner)];
2179 perm = ntfs_build_permissions(securattr,
2181 if (!perm && ntfs_same_sid(usid, adminsid)) {
2182 uid = find_tenant(scx, securattr);
2186 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2189 * Create a security id if there were none
2190 * and upgrade option is selected
2192 if (!test_nino_flag(ni, v3_Extensions)
2194 && (scx->vol->secure_flags
2195 & (1 << SECURITY_ADDSECURIDS))) {
2196 upgrade_secur_desc(scx->vol,
2199 * fetch owner and group for cacheing
2200 * if there is a securid
2203 if (test_nino_flag(ni, v3_Extensions)
2205 enter_cache(scx, ni, uid,
2216 /* root access and execution */
2222 if (uid == scx->uid)
2226 * avoid checking group membership
2227 * when the requested perms for group
2228 * are the same as perms for other
2230 if ((gid == scx->gid)
2231 || ((((perm >> 3) ^ perm)
2232 & (request >> 6) & 7)
2233 && groupmember(scx, scx->uid, gid)))
2242 #endif /* POSIXACLS */
2247 * Returns size or -errno if there is a problem
2248 * if size was too small, no copy is done and errno is not set,
2249 * the caller is expected to issue a new call
2252 int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2253 char *value, size_t size)
2258 outsize = 0; /* default to no data and no error */
2259 securattr = getsecurityattr(scx->vol, ni);
2261 outsize = ntfs_attr_size(securattr);
2262 if (outsize <= size) {
2263 memcpy(value,securattr,outsize);
2267 return (outsize ? (int)outsize : -errno);
2271 * Get owner, group and permissions in an stat structure
2272 * returns permissions, or -1 if there is a problem
2275 int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
2276 ntfs_inode * ni, struct stat *stbuf)
2278 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2280 const SID *usid; /* owner of file/directory */
2281 const SID *gsid; /* group of file/directory */
2282 const struct CACHED_PERMISSIONS *cached;
2286 struct POSIX_SECURITY *pxdesc;
2289 if (!scx->mapping[MAPUSERS])
2292 /* check whether available in cache */
2293 cached = fetch_cache(scx,ni);
2295 perm = cached->mode;
2296 stbuf->st_uid = cached->uid;
2297 stbuf->st_gid = cached->gid;
2298 stbuf->st_mode = (stbuf->st_mode & ~07777) + perm;
2300 perm = -1; /* default to error */
2301 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2302 != const_cpu_to_le16(0);
2303 securattr = getsecurityattr(scx->vol, ni);
2306 (const SECURITY_DESCRIPTOR_RELATIVE*)
2308 gsid = (const SID*)&
2309 securattr[le32_to_cpu(phead->group)];
2311 usid = ntfs_acl_owner(securattr);
2313 usid = (const SID*)&
2314 securattr[le32_to_cpu(phead->owner)];
2317 pxdesc = ntfs_build_permissions_posix(scx->mapping, securattr,
2320 perm = pxdesc->mode & 07777;
2324 perm = ntfs_build_permissions(securattr,
2328 * fetch owner and group for cacheing
2332 * Create a security id if there were none
2333 * and upgrade option is selected
2335 if (!test_nino_flag(ni, v3_Extensions)
2336 && (scx->vol->secure_flags
2337 & (1 << SECURITY_ADDSECURIDS))) {
2338 upgrade_secur_desc(scx->vol,
2342 stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2344 if (!perm && ntfs_same_sid(usid, adminsid)) {
2351 stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2353 stbuf->st_gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2355 (stbuf->st_mode & ~07777) + perm;
2357 enter_cache(scx, ni, stbuf->st_uid,
2358 stbuf->st_gid, pxdesc);
2361 enter_cache(scx, ni, stbuf->st_uid,
2362 stbuf->st_gid, perm);
2375 * Get the base for a Posix inheritance and
2376 * build an inherited Posix descriptor
2379 static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx,
2380 ntfs_inode *dir_ni, mode_t mode, BOOL isdir)
2382 const struct CACHED_PERMISSIONS *cached;
2383 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2384 struct POSIX_SECURITY *pxdesc;
2385 struct POSIX_SECURITY *pydesc;
2392 pydesc = (struct POSIX_SECURITY*)NULL;
2393 /* check whether parent directory is available in cache */
2394 cached = fetch_cache(scx,dir_ni);
2398 pxdesc = cached->pxdesc;
2400 pydesc = ntfs_build_inherited_posix(pxdesc,mode,
2404 securattr = getsecurityattr(scx->vol, dir_ni);
2406 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2408 gsid = (const SID*)&
2409 securattr[le32_to_cpu(phead->group)];
2410 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2412 usid = ntfs_acl_owner(securattr);
2413 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2415 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2417 usid = (const SID*)&
2418 securattr[le32_to_cpu(phead->owner)];
2419 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2421 if (pxdesc && ntfs_same_sid(usid, adminsid)) {
2422 uid = find_tenant(scx, securattr);
2424 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2428 * Create a security id if there were none
2429 * and upgrade option is selected
2431 if (!test_nino_flag(dir_ni, v3_Extensions)
2432 && (scx->vol->secure_flags
2433 & (1 << SECURITY_ADDSECURIDS))) {
2434 upgrade_secur_desc(scx->vol,
2437 * fetch owner and group for cacheing
2438 * if there is a securid
2441 if (test_nino_flag(dir_ni, v3_Extensions)) {
2442 enter_cache(scx, dir_ni, uid,
2445 pydesc = ntfs_build_inherited_posix(pxdesc,
2446 mode, scx->umask, isdir);
2456 * Allocate a security_id for a file being created
2458 * Returns zero if not possible (NTFS v3.x required)
2461 le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
2462 uid_t uid, gid_t gid, ntfs_inode *dir_ni,
2463 mode_t mode, BOOL isdir)
2465 #if !FORCE_FORMAT_v1x
2466 const struct CACHED_SECURID *cached;
2467 struct CACHED_SECURID wanted;
2468 struct POSIX_SECURITY *pxdesc;
2478 securid = const_cpu_to_le32(0);
2480 #if !FORCE_FORMAT_v1x
2482 pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
2484 /* check whether target securid is known in cache */
2488 wanted.dmode = pxdesc->mode & mode & 07777;
2489 if (isdir) wanted.dmode |= 0x10000;
2490 wanted.variable = (void*)pxdesc;
2491 wanted.varsize = sizeof(struct POSIX_SECURITY)
2492 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2493 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2494 scx->vol->securid_cache, GENERIC(&wanted),
2495 (cache_compare)compare);
2496 /* quite simple, if we are lucky */
2498 securid = cached->securid;
2500 /* not in cache : make sure we can create ids */
2502 if (!cached && (scx->vol->major_ver >= 3)) {
2503 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2504 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2505 if (!usid || !gsid) {
2506 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2507 (int)uid, (int)gid);
2508 usid = gsid = adminsid;
2510 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2513 newattrsz = ntfs_attr_size(newattr);
2514 securid = setsecurityattr(scx->vol,
2515 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
2518 /* update cache, for subsequent use */
2519 wanted.securid = securid;
2520 ntfs_enter_cache(scx->vol->securid_cache,
2522 (cache_compare)compare);
2527 * could not build new security attribute
2528 * errno set by ntfs_build_descr()
2539 * Apply Posix inheritance to a newly created file
2540 * (for NTFS 1.x only : no securid)
2543 int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
2544 ntfs_inode *ni, uid_t uid, gid_t gid,
2545 ntfs_inode *dir_ni, mode_t mode)
2547 struct POSIX_SECURITY *pxdesc;
2557 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2558 pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
2560 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2561 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2562 if (!usid || !gsid) {
2563 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2564 (int)uid, (int)gid);
2565 usid = gsid = adminsid;
2567 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2570 /* Adjust Windows read-only flag */
2571 res = update_secur_descr(scx->vol, newattr, ni);
2572 if (!res && !isdir) {
2574 ni->flags &= ~FILE_ATTR_READONLY;
2576 ni->flags |= FILE_ATTR_READONLY;
2578 #if CACHE_LEGACY_SIZE
2579 /* also invalidate legacy cache */
2580 if (isdir && !ni->security_id) {
2581 struct CACHED_PERMISSIONS_LEGACY legacy;
2583 legacy.mft_no = ni->mft_no;
2584 legacy.variable = pxdesc;
2585 legacy.varsize = sizeof(struct POSIX_SECURITY)
2586 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2587 ntfs_invalidate_cache(scx->vol->legacy_cache,
2589 (cache_compare)leg_compare,0);
2596 * could not build new security attribute
2597 * errno set by ntfs_build_descr()
2606 le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
2607 uid_t uid, gid_t gid, mode_t mode, BOOL isdir)
2609 #if !FORCE_FORMAT_v1x
2610 const struct CACHED_SECURID *cached;
2611 struct CACHED_SECURID wanted;
2621 securid = const_cpu_to_le32(0);
2623 #if !FORCE_FORMAT_v1x
2624 /* check whether target securid is known in cache */
2628 wanted.dmode = mode & 07777;
2629 if (isdir) wanted.dmode |= 0x10000;
2630 wanted.variable = (void*)NULL;
2632 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2633 scx->vol->securid_cache, GENERIC(&wanted),
2634 (cache_compare)compare);
2635 /* quite simple, if we are lucky */
2637 securid = cached->securid;
2639 /* not in cache : make sure we can create ids */
2641 if (!cached && (scx->vol->major_ver >= 3)) {
2642 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2643 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2644 if (!usid || !gsid) {
2645 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2646 (int)uid, (int)gid);
2647 usid = gsid = adminsid;
2649 newattr = ntfs_build_descr(mode, isdir, usid, gsid);
2651 newattrsz = ntfs_attr_size(newattr);
2652 securid = setsecurityattr(scx->vol,
2653 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
2656 /* update cache, for subsequent use */
2657 wanted.securid = securid;
2658 ntfs_enter_cache(scx->vol->securid_cache,
2660 (cache_compare)compare);
2665 * could not build new security attribute
2666 * errno set by ntfs_build_descr()
2677 * Update ownership and mode of a file, reusing an existing
2678 * security descriptor when possible
2680 * Returns zero if successful
2684 int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2685 uid_t uid, gid_t gid, mode_t mode,
2686 struct POSIX_SECURITY *pxdesc)
2688 int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2689 uid_t uid, gid_t gid, mode_t mode)
2693 const struct CACHED_SECURID *cached;
2694 struct CACHED_SECURID wanted;
2704 /* check whether target securid is known in cache */
2706 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2709 wanted.dmode = mode & 07777;
2710 if (isdir) wanted.dmode |= 0x10000;
2712 wanted.variable = (void*)pxdesc;
2714 wanted.varsize = sizeof(struct POSIX_SECURITY)
2715 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2719 wanted.variable = (void*)NULL;
2722 if (test_nino_flag(ni, v3_Extensions)) {
2723 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2724 scx->vol->securid_cache, GENERIC(&wanted),
2725 (cache_compare)compare);
2726 /* quite simple, if we are lucky */
2728 ni->security_id = cached->securid;
2731 } else cached = (struct CACHED_SECURID*)NULL;
2735 * Do not use usid and gsid from former attributes,
2736 * but recompute them to get repeatable results
2737 * which can be kept in cache.
2739 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2740 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2741 if (!usid || !gsid) {
2742 ntfs_log_error("File made owned by an unmapped user/group %d/%d\n",
2744 usid = gsid = adminsid;
2748 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2751 newattr = ntfs_build_descr(mode,
2754 newattr = ntfs_build_descr(mode,
2758 res = update_secur_descr(scx->vol, newattr, ni);
2760 /* adjust Windows read-only flag */
2763 ni->flags &= ~FILE_ATTR_READONLY;
2765 ni->flags |= FILE_ATTR_READONLY;
2766 NInoFileNameSetDirty(ni);
2768 /* update cache, for subsequent use */
2769 if (test_nino_flag(ni, v3_Extensions)) {
2770 wanted.securid = ni->security_id;
2771 ntfs_enter_cache(scx->vol->securid_cache,
2773 (cache_compare)compare);
2775 #if CACHE_LEGACY_SIZE
2776 /* also invalidate legacy cache */
2777 if (isdir && !ni->security_id) {
2778 struct CACHED_PERMISSIONS_LEGACY legacy;
2780 legacy.mft_no = ni->mft_no;
2782 legacy.variable = wanted.variable;
2783 legacy.varsize = wanted.varsize;
2785 legacy.variable = (void*)NULL;
2788 ntfs_invalidate_cache(scx->vol->legacy_cache,
2790 (cache_compare)leg_compare,0);
2797 * could not build new security attribute
2798 * errno set by ntfs_build_descr()
2807 * Check whether user has ownership rights on a file
2809 * Returns TRUE if allowed
2810 * if not, errno tells why
2813 BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni)
2815 const struct CACHED_PERMISSIONS *cached;
2823 processuid = scx->uid;
2824 /* TODO : use CAP_FOWNER process capability */
2826 * Always allow for root
2827 * Also always allow if no mapping has been defined
2829 if (!scx->mapping[MAPUSERS] || !processuid)
2832 gotowner = FALSE; /* default */
2833 /* get the owner, either from cache or from old attribute */
2834 cached = fetch_cache(scx, ni);
2839 oldattr = getsecurityattr(scx->vol, ni);
2842 usid = ntfs_acl_owner(oldattr);
2844 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2846 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2848 usid = (const SID*)&oldattr
2849 [le32_to_cpu(phead->owner)];
2851 uid = ntfs_find_user(scx->mapping[MAPUSERS],
2859 /* TODO : use CAP_FOWNER process capability */
2860 if (!processuid || (processuid == uid))
2869 #ifdef HAVE_SETXATTR /* extended attributes interface required */
2874 * Set a new access or default Posix ACL to a file
2875 * (or remove ACL if no input data)
2876 * Validity of input data is checked after merging
2878 * Returns 0, or -1 if there is a problem which errno describes
2881 int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2882 const char *name, const char *value, size_t size,
2885 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2886 const struct CACHED_PERMISSIONS *cached;
2898 struct POSIX_SECURITY *oldpxdesc;
2899 struct POSIX_SECURITY *newpxdesc;
2901 /* get the current pxsec, either from cache or from old attribute */
2903 deflt = !strcmp(name,"system.posix_acl_default");
2905 count = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE);
2908 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2909 newpxdesc = (struct POSIX_SECURITY*)NULL;
2911 || (((const struct POSIX_ACL*)value)->version == POSIX_VERSION))
2912 && (!deflt || isdir || (!size && !value))) {
2913 cached = fetch_cache(scx, ni);
2917 oldpxdesc = cached->pxdesc;
2919 newpxdesc = ntfs_replace_acl(oldpxdesc,
2920 (const struct POSIX_ACL*)value,count,deflt);
2923 oldattr = getsecurityattr(scx->vol, ni);
2925 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
2927 usid = ntfs_acl_owner(oldattr);
2929 usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
2931 gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
2932 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2933 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2934 oldpxdesc = ntfs_build_permissions_posix(scx->mapping,
2935 oldattr, usid, gsid, isdir);
2938 exist = oldpxdesc->defcnt > 0;
2940 exist = oldpxdesc->acccnt > 3;
2941 if ((exist && (flags & XATTR_CREATE))
2942 || (!exist && (flags & XATTR_REPLACE))) {
2943 errno = (exist ? EEXIST : ENODATA);
2945 newpxdesc = ntfs_replace_acl(oldpxdesc,
2946 (const struct POSIX_ACL*)value,count,deflt);
2957 processuid = scx->uid;
2958 /* TODO : use CAP_FOWNER process capability */
2959 if (!processuid || (uid == processuid)) {
2961 * clear setgid if file group does
2962 * not match process group
2964 if (processuid && (gid != scx->gid)
2965 && !groupmember(scx, scx->uid, gid)) {
2966 newpxdesc->mode &= ~S_ISGID;
2968 res = ntfs_set_owner_mode(scx, ni, uid, gid,
2969 newpxdesc->mode, newpxdesc);
2974 return (res ? -1 : 0);
2978 * Remove a default Posix ACL from a file
2980 * Returns 0, or -1 if there is a problem which errno describes
2983 int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2986 return (ntfs_set_posix_acl(scx, ni, name,
2987 (const char*)NULL, 0, 0));
2993 * Set a new NTFS ACL to a file
2995 * Returns 0, or -1 if there is a problem
2998 int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2999 const char *value, size_t size, int flags)
3006 && !(flags & XATTR_CREATE)
3007 && ntfs_valid_descr(value,size)
3008 && (ntfs_attr_size(value) == size)) {
3009 /* need copying in order to write */
3010 attr = (char*)ntfs_malloc(size);
3012 memcpy(attr,value,size);
3013 res = update_secur_descr(scx->vol, attr, ni);
3015 * No need to invalidate standard caches :
3016 * the relation between a securid and
3017 * the associated protection is unchanged,
3018 * only the relation between a file and
3019 * its securid and protection is changed.
3021 #if CACHE_LEGACY_SIZE
3023 * we must however invalidate the legacy
3024 * cache, which is based on inode numbers.
3025 * For safety, invalidate even if updating
3028 if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3029 && !ni->security_id) {
3030 struct CACHED_PERMISSIONS_LEGACY legacy;
3032 legacy.mft_no = ni->mft_no;
3033 legacy.variable = (char*)NULL;
3035 ntfs_invalidate_cache(scx->vol->legacy_cache,
3037 (cache_compare)leg_compare,0);
3045 return (res ? -1 : 0);
3048 #endif /* HAVE_SETXATTR */
3051 * Set new permissions to a file
3052 * Checks user mapping has been defined before request for setting
3054 * rejected if request is not originated by owner or root
3056 * returns 0 on success
3057 * -1 on failure, with errno = EIO
3060 int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode)
3062 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3063 const struct CACHED_PERMISSIONS *cached;
3074 const struct POSIX_SECURITY *oldpxdesc;
3075 struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
3078 /* get the current owner, either from cache or from old attribute */
3080 cached = fetch_cache(scx, ni);
3085 oldpxdesc = cached->pxdesc;
3087 /* must copy before merging */
3088 pxsize = sizeof(struct POSIX_SECURITY)
3089 + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
3090 newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
3092 memcpy(newpxdesc, oldpxdesc, pxsize);
3093 if (ntfs_merge_mode_posix(newpxdesc, mode))
3098 newpxdesc = (struct POSIX_SECURITY*)NULL;
3101 oldattr = getsecurityattr(scx->vol, ni);
3103 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
3105 usid = ntfs_acl_owner(oldattr);
3107 usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
3109 gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
3110 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3111 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3113 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
3114 newpxdesc = ntfs_build_permissions_posix(scx->mapping,
3115 oldattr, usid, gsid, isdir);
3116 if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
3125 processuid = scx->uid;
3126 /* TODO : use CAP_FOWNER process capability */
3127 if (!processuid || (uid == processuid)) {
3129 * clear setgid if file group does
3130 * not match process group
3132 if (processuid && (gid != scx->gid)
3133 && !groupmember(scx, scx->uid, gid))
3137 newpxdesc->mode = mode;
3138 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3141 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3144 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3148 res = -1; /* neither owner nor root */
3152 * Should not happen : a default descriptor is generated
3153 * by getsecurityattr() when there are none
3155 ntfs_log_error("File has no security descriptor\n");
3160 if (newpxdesc) free(newpxdesc);
3162 return (res ? -1 : 0);
3166 * Create a default security descriptor for files whose descriptor
3167 * cannot be inherited
3170 int ntfs_sd_add_everyone(ntfs_inode *ni)
3172 /* JPA SECURITY_DESCRIPTOR_ATTR *sd; */
3173 SECURITY_DESCRIPTOR_RELATIVE *sd;
3175 ACCESS_ALLOWED_ACE *ace;
3179 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
3181 * Calculate security descriptor length. We have 2 sub-authorities in
3182 * owner and group SIDs, but structure SID contain only one, so add
3183 * 4 bytes to every SID.
3185 sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
3186 sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
3187 sd = (SECURITY_DESCRIPTOR_RELATIVE*)ntfs_calloc(sd_len);
3191 sd->revision = SECURITY_DESCRIPTOR_REVISION;
3192 sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
3194 sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
3195 sid->revision = SID_REVISION;
3196 sid->sub_authority_count = 2;
3197 sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
3198 sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
3199 sid->identifier_authority.value[5] = 5;
3200 sd->owner = cpu_to_le32((u8*)sid - (u8*)sd);
3202 sid = (SID*)((u8*)sid + sizeof(SID) + 4);
3203 sid->revision = SID_REVISION;
3204 sid->sub_authority_count = 2;
3205 sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
3206 sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
3207 sid->identifier_authority.value[5] = 5;
3208 sd->group = cpu_to_le32((u8*)sid - (u8*)sd);
3210 acl = (ACL*)((u8*)sid + sizeof(SID) + 4);
3211 acl->revision = ACL_REVISION;
3212 acl->size = const_cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
3213 acl->ace_count = const_cpu_to_le16(1);
3214 sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd);
3216 ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL));
3217 ace->type = ACCESS_ALLOWED_ACE_TYPE;
3218 ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
3219 ace->size = const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
3220 ace->mask = const_cpu_to_le32(0x1f01ff); /* FIXME */
3221 ace->sid.revision = SID_REVISION;
3222 ace->sid.sub_authority_count = 1;
3223 ace->sid.sub_authority[0] = const_cpu_to_le32(0);
3224 ace->sid.identifier_authority.value[5] = 1;
3226 ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8*)sd,
3229 ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR");
3236 * Check whether user can access a file in a specific way
3238 * Returns 1 if access is allowed, including user is root or no
3239 * user mapping defined
3240 * 2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX
3241 * 0 and sets errno if there is a problem or if access
3244 * This is used for Posix ACL and checking creation of DOS file names
3247 int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
3249 int accesstype) /* access type required (S_Ixxx values) */
3257 * Always allow for root unless execution is requested.
3258 * (was checked by fuse until kernel 2.6.29)
3259 * Also always allow if no mapping has been defined
3261 if (!scx->mapping[MAPUSERS]
3263 && (!(accesstype & S_IEXEC)
3264 || (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY))))
3267 perm = ntfs_get_perm(scx, ni, accesstype);
3270 switch (accesstype) {
3272 allow = (perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
3275 allow = (perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0;
3277 case S_IWRITE + S_IEXEC:
3278 allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3279 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3282 allow = (perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0;
3284 case S_IREAD + S_IEXEC:
3285 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3286 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3288 case S_IREAD + S_IWRITE:
3289 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3290 && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0);
3292 case S_IWRITE + S_IEXEC + S_ISVTX:
3293 if (perm & S_ISVTX) {
3294 if ((ntfs_get_owner_mode(scx,ni,&stbuf) >= 0)
3295 && (stbuf.st_uid == scx->uid))
3300 allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3301 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3303 case S_IREAD + S_IWRITE + S_IEXEC:
3304 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3305 && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3306 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3321 #if 0 /* not needed any more */
3324 * Check whether user can access the parent directory
3325 * of a file in a specific way
3327 * Returns true if access is allowed, including user is root and
3328 * no user mapping defined
3330 * Sets errno if there is a problem or if not allowed
3332 * This is used for Posix ACL and checking creation of DOS file names
3335 BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
3336 const char *path, int accesstype)
3346 dirpath = strdup(path);
3348 /* the root of file system is seen as a parent of itself */
3349 /* is that correct ? */
3350 name = strrchr(dirpath, '/');
3352 dir_ni = ntfs_pathname_to_inode(scx->vol, NULL, dirpath);
3354 allow = ntfs_allowed_access(scx,
3355 dir_ni, accesstype);
3356 ntfs_inode_close(dir_ni);
3358 * for an not-owned sticky directory, have to
3359 * check whether file itself is owned
3361 if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX))
3363 ni = ntfs_pathname_to_inode(scx->vol, NULL,
3367 allow = (ntfs_get_owner_mode(scx,ni,&stbuf) >= 0)
3368 && (stbuf.st_uid == scx->uid);
3369 ntfs_inode_close(ni);
3375 return (allow); /* errno is set if not allowed */
3381 * Define a new owner/group to a file
3383 * returns zero if successful
3386 int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
3387 uid_t uid, gid_t gid)
3389 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3390 const struct CACHED_PERMISSIONS *cached;
3401 struct POSIX_SECURITY *pxdesc;
3402 BOOL pxdescbuilt = FALSE;
3406 /* get the current owner and mode from cache or security attributes */
3407 oldattr = (char*)NULL;
3408 cached = fetch_cache(scx,ni);
3410 fileuid = cached->uid;
3411 filegid = cached->gid;
3412 mode = cached->mode;
3414 pxdesc = cached->pxdesc;
3422 oldattr = getsecurityattr(scx->vol, ni);
3424 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3425 != const_cpu_to_le16(0);
3426 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
3429 &oldattr[le32_to_cpu(phead->group)];
3431 usid = ntfs_acl_owner(oldattr);
3434 &oldattr[le32_to_cpu(phead->owner)];
3437 pxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
3441 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3442 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3443 mode = perm = pxdesc->mode;
3447 mode = perm = ntfs_build_permissions(oldattr,
3450 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3451 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3460 /* check requested by root */
3461 /* or chgrp requested by owner to an owned group */
3463 || ((((int)uid < 0) || (uid == fileuid))
3464 && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
3465 && (fileuid == scx->uid))) {
3466 /* replace by the new usid and gsid */
3467 /* or reuse old gid and sid for cacheing */
3472 /* clear setuid and setgid if owner has changed */
3473 /* unless request originated by root */
3474 if (uid && (fileuid != uid))
3477 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3480 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3483 res = -1; /* neither owner nor root */
3492 * Should not happen : a default descriptor is generated
3493 * by getsecurityattr() when there are none
3495 ntfs_log_error("File has no security descriptor\n");
3499 return (res ? -1 : 0);
3503 * Define new owner/group and mode to a file
3505 * returns zero if successful
3508 int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
3509 uid_t uid, gid_t gid, const mode_t mode)
3511 const struct CACHED_PERMISSIONS *cached;
3517 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3521 const struct POSIX_SECURITY *oldpxdesc;
3522 struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
3527 /* get the current owner and mode from cache or security attributes */
3528 oldattr = (char*)NULL;
3529 cached = fetch_cache(scx,ni);
3531 fileuid = cached->uid;
3532 filegid = cached->gid;
3534 oldpxdesc = cached->pxdesc;
3536 /* must copy before merging */
3537 pxsize = sizeof(struct POSIX_SECURITY)
3538 + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
3539 newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
3541 memcpy(newpxdesc, oldpxdesc, pxsize);
3542 if (ntfs_merge_mode_posix(newpxdesc, mode))
3551 oldattr = getsecurityattr(scx->vol, ni);
3554 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3555 != const_cpu_to_le16(0);
3556 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
3559 &oldattr[le32_to_cpu(phead->group)];
3561 usid = ntfs_acl_owner(oldattr);
3564 &oldattr[le32_to_cpu(phead->owner)];
3566 newpxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
3568 if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
3571 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3572 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3580 /* check requested by root */
3581 /* or chgrp requested by owner to an owned group */
3583 || ((((int)uid < 0) || (uid == fileuid))
3584 && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
3585 && (fileuid == scx->uid))) {
3586 /* replace by the new usid and gsid */
3587 /* or reuse old gid and sid for cacheing */
3593 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3596 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3599 res = -1; /* neither owner nor root */
3604 * Should not happen : a default descriptor is generated
3605 * by getsecurityattr() when there are none
3607 ntfs_log_error("File has no security descriptor\n");
3614 return (res ? -1 : 0);
3618 * Build a security id for a descriptor inherited from
3619 * parent directory the Windows way
3622 static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
3623 const char *parentattr, BOOL fordir)
3625 const SECURITY_DESCRIPTOR_RELATIVE *pphead;
3634 SECURITY_DESCRIPTOR_RELATIVE *pnhead;
3645 parentattrsz = ntfs_attr_size(parentattr);
3646 pphead = (const SECURITY_DESCRIPTOR_RELATIVE*)parentattr;
3647 if (scx->mapping[MAPUSERS]) {
3648 usid = ntfs_find_usid(scx->mapping[MAPUSERS], scx->uid, (SID*)&defusid);
3649 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS], scx->gid, (SID*)&defgsid);
3656 * If there is no user mapping, we have to copy owner
3657 * and group from parent directory.
3658 * Windows never has to do that, because it can always
3659 * rely on a user mapping
3661 offowner = le32_to_cpu(pphead->owner);
3662 usid = (const SID*)&parentattr[offowner];
3663 offgroup = le32_to_cpu(pphead->group);
3664 gsid = (const SID*)&parentattr[offgroup];
3667 * new attribute is smaller than parent's
3668 * except for differences in SIDs which appear in
3669 * owner, group and possible grants and denials in
3670 * generic creator-owner and creator-group ACEs.
3671 * For directories, an ACE may be duplicated for
3672 * access and inheritance, so we double the count.
3674 usidsz = ntfs_sid_size(usid);
3675 gsidsz = ntfs_sid_size(gsid);
3676 newattrsz = parentattrsz + 3*usidsz + 3*gsidsz;
3679 newattr = (char*)ntfs_malloc(newattrsz);
3681 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr;
3682 pnhead->revision = SECURITY_DESCRIPTOR_REVISION;
3683 pnhead->alignment = 0;
3684 pnhead->control = SE_SELF_RELATIVE;
3685 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
3687 * locate and inherit DACL
3688 * do not test SE_DACL_PRESENT (wrong for "DR Watson")
3690 pnhead->dacl = const_cpu_to_le32(0);
3692 offpacl = le32_to_cpu(pphead->dacl);
3693 ppacl = (const ACL*)&parentattr[offpacl];
3694 pnacl = (ACL*)&newattr[pos];
3695 aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
3697 pnhead->dacl = cpu_to_le32(pos);
3699 pnhead->control |= SE_DACL_PRESENT;
3703 * locate and inherit SACL
3705 pnhead->sacl = const_cpu_to_le32(0);
3707 offpacl = le32_to_cpu(pphead->sacl);
3708 ppacl = (const ACL*)&parentattr[offpacl];
3709 pnacl = (ACL*)&newattr[pos];
3710 aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
3712 pnhead->sacl = cpu_to_le32(pos);
3714 pnhead->control |= SE_SACL_PRESENT;
3718 * inherit or redefine owner
3720 memcpy(&newattr[pos],usid,usidsz);
3721 pnhead->owner = cpu_to_le32(pos);
3724 * inherit or redefine group
3726 memcpy(&newattr[pos],gsid,gsidsz);
3727 pnhead->group = cpu_to_le32(pos);
3729 securid = setsecurityattr(scx->vol,
3730 (SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos);
3733 securid = const_cpu_to_le32(0);
3738 * Get an inherited security id
3740 * For Windows compatibility, the normal initial permission setting
3741 * may be inherited from the parent directory instead of being
3742 * defined by the creation arguments.
3744 * The following creates an inherited id for that purpose.
3746 * Note : the owner and group of parent directory are also
3747 * inherited (which is not the case on Windows) if no user mapping
3750 * Returns the inherited id, or zero if not possible (eg on NTFS 1.x)
3753 le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
3754 ntfs_inode *dir_ni, BOOL fordir)
3756 struct CACHED_PERMISSIONS *cached;
3760 securid = const_cpu_to_le32(0);
3761 cached = (struct CACHED_PERMISSIONS*)NULL;
3763 * Try to get inherited id from cache
3765 if (test_nino_flag(dir_ni, v3_Extensions)
3766 && dir_ni->security_id) {
3767 cached = fetch_cache(scx, dir_ni);
3769 securid = (fordir ? cached->inh_dirid
3770 : cached->inh_fileid);
3773 * Not cached or not available in cache, compute it all
3774 * Note : if parent directory has no id, it is not cacheable
3777 parentattr = getsecurityattr(scx->vol, dir_ni);
3779 securid = build_inherited_id(scx,
3780 parentattr, fordir);
3783 * Store the result into cache for further use
3786 cached = fetch_cache(scx, dir_ni);
3789 cached->inh_dirid = securid;
3791 cached->inh_fileid = securid;
3800 * Link a group to a member of group
3802 * Returns 0 if OK, -1 (and errno set) if error
3805 static int link_single_group(struct MAPPING *usermapping, struct passwd *user,
3808 struct group *group;
3815 group = getgrgid(gid);
3816 if (group && group->gr_mem) {
3817 grcnt = usermapping->grcnt;
3818 groups = usermapping->groups;
3819 grmem = group->gr_mem;
3820 while (*grmem && strcmp(user->pw_name, *grmem))
3824 groups = (gid_t*)malloc(sizeof(gid_t));
3826 groups = (gid_t*)realloc(groups,
3827 (grcnt+1)*sizeof(gid_t));
3829 groups[grcnt++] = gid;
3835 usermapping->grcnt = grcnt;
3836 usermapping->groups = groups;
3843 * Statically link group to users
3844 * This is based on groups defined in /etc/group and does not take
3845 * the groups dynamically set by setgroups() nor any changes in
3846 * /etc/group into account
3848 * Only mapped groups and root group are linked to mapped users
3850 * Returns 0 if OK, -1 (and errno set) if error
3854 static int link_group_members(struct SECURITY_CONTEXT *scx)
3856 struct MAPPING *usermapping;
3857 struct MAPPING *groupmapping;
3858 struct passwd *user;
3862 for (usermapping=scx->mapping[MAPUSERS]; usermapping && !res;
3863 usermapping=usermapping->next) {
3864 usermapping->grcnt = 0;
3865 usermapping->groups = (gid_t*)NULL;
3866 user = getpwuid(usermapping->xid);
3867 if (user && user->pw_name) {
3868 for (groupmapping=scx->mapping[MAPGROUPS];
3869 groupmapping && !res;
3870 groupmapping=groupmapping->next) {
3871 if (link_single_group(usermapping, user,
3875 if (!res && link_single_group(usermapping,
3884 * Apply default single user mapping
3885 * returns zero if successful
3888 static int ntfs_do_default_mapping(struct SECURITY_CONTEXT *scx,
3889 uid_t uid, gid_t gid, const SID *usid)
3891 struct MAPPING *usermapping;
3892 struct MAPPING *groupmapping;
3898 sidsz = ntfs_sid_size(usid);
3899 sid = (SID*)ntfs_malloc(sidsz);
3901 memcpy(sid,usid,sidsz);
3902 usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
3904 groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
3906 usermapping->sid = sid;
3907 usermapping->xid = uid;
3908 usermapping->next = (struct MAPPING*)NULL;
3909 groupmapping->sid = sid;
3910 groupmapping->xid = gid;
3911 groupmapping->next = (struct MAPPING*)NULL;
3912 scx->mapping[MAPUSERS] = usermapping;
3913 scx->mapping[MAPGROUPS] = groupmapping;
3922 * Make sure there are no ambiguous mapping
3923 * Ambiguous mapping may lead to undesired configurations and
3924 * we had rather be safe until the consequences are understood
3927 #if 0 /* not activated for now */
3929 static BOOL check_mapping(const struct MAPPING *usermapping,
3930 const struct MAPPING *groupmapping)
3932 const struct MAPPING *mapping1;
3933 const struct MAPPING *mapping2;
3937 for (mapping1=usermapping; mapping1; mapping1=mapping1->next)
3938 for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
3939 if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
3940 if (mapping1->xid != mapping2->xid)
3943 if (mapping1->xid == mapping2->xid)
3946 for (mapping1=groupmapping; mapping1; mapping1=mapping1->next)
3947 for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
3948 if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
3949 if (mapping1->xid != mapping2->xid)
3952 if (mapping1->xid == mapping2->xid)
3960 #if 0 /* not used any more */
3963 * Try and apply default single user mapping
3964 * returns zero if successful
3967 static int ntfs_default_mapping(struct SECURITY_CONTEXT *scx)
3969 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3976 ni = ntfs_pathname_to_inode(scx->vol, NULL, "/.");
3978 securattr = getsecurityattr(scx->vol, ni);
3980 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr;
3981 usid = (SID*)&securattr[le32_to_cpu(phead->owner)];
3982 if (ntfs_is_user_sid(usid))
3983 res = ntfs_do_default_mapping(scx,
3984 scx->uid, scx->gid, usid);
3987 ntfs_inode_close(ni);
3995 * Basic read from a user mapping file on another volume
3998 static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused)))
4000 return (read(*(int*)fileid, buf, size));
4005 * Read from a user mapping file on current NTFS partition
4008 static int localread(void *fileid, char *buf, size_t size, off_t offs)
4010 return (ntfs_attr_data_read((ntfs_inode*)fileid,
4011 AT_UNNAMED, 0, buf, size, offs));
4015 * Build the user mapping
4016 * - according to a mapping file if defined (or default present),
4017 * - or try default single user mapping if possible
4019 * The mapping is specific to a mounted device
4020 * No locking done, mounting assumed non multithreaded
4022 * returns zero if mapping is successful
4023 * (failure should not be interpreted as an error)
4026 int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
4029 struct MAPLIST *item;
4030 struct MAPLIST *firstitem;
4031 struct MAPPING *usermapping;
4032 struct MAPPING *groupmapping;
4046 1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5),
4047 const_cpu_to_le32(21),
4048 const_cpu_to_le32(DEFSECAUTH1), const_cpu_to_le32(DEFSECAUTH2),
4049 const_cpu_to_le32(DEFSECAUTH3), const_cpu_to_le32(DEFSECBASE)
4052 /* be sure not to map anything until done */
4053 scx->mapping[MAPUSERS] = (struct MAPPING*)NULL;
4054 scx->mapping[MAPGROUPS] = (struct MAPPING*)NULL;
4056 if (!usermap_path) usermap_path = MAPPINGFILE;
4057 if (usermap_path[0] == '/') {
4058 fd = open(usermap_path,O_RDONLY);
4060 firstitem = ntfs_read_mapping(basicread, (void*)&fd);
4063 firstitem = (struct MAPLIST*)NULL;
4065 ni = ntfs_pathname_to_inode(scx->vol, NULL, usermap_path);
4067 firstitem = ntfs_read_mapping(localread, ni);
4068 ntfs_inode_close(ni);
4070 firstitem = (struct MAPLIST*)NULL;
4075 usermapping = ntfs_do_user_mapping(firstitem);
4076 groupmapping = ntfs_do_group_mapping(firstitem);
4077 if (usermapping && groupmapping) {
4078 scx->mapping[MAPUSERS] = usermapping;
4079 scx->mapping[MAPGROUPS] = groupmapping;
4081 ntfs_log_error("There were no valid user or no valid group\n");
4082 /* now we can free the memory copy of input text */
4083 /* and rely on internal representation */
4085 item = firstitem->next;
4090 /* no mapping file, try a default mapping */
4092 if (!ntfs_do_default_mapping(scx,
4093 0, 0, (const SID*)&defmap))
4094 ntfs_log_info("Using default user mapping\n");
4097 return (!scx->mapping[MAPUSERS] || link_group_members(scx));
4100 #ifdef HAVE_SETXATTR /* extended attributes interface required */
4103 * Get the ntfs attribute into an extended attribute
4104 * The attribute is returned according to cpu endianness
4107 int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size)
4112 outsize = 0; /* default to no data and no error */
4114 attrib = le32_to_cpu(ni->flags);
4115 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
4116 attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4118 attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4120 attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
4121 outsize = sizeof(FILE_ATTR_FLAGS);
4122 if (size >= outsize) {
4124 memcpy(value,&attrib,outsize);
4129 return (outsize ? (int)outsize : -errno);
4133 * Get the ntfs attributes from an inode
4134 * The attributes are returned according to cpu endianness
4136 * Returns the attributes if successful (cannot be zero)
4137 * 0 if failed (errno to tell why)
4140 u32 ntfs_get_inode_attributes(ntfs_inode *ni)
4145 attrib = le32_to_cpu(ni->flags);
4146 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
4147 attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4149 attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4151 attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
4158 * Set the ntfs attributes on an inode
4159 * The attribute is expected according to cpu endianness
4161 * Returns 0 if successful
4162 * -1 if failed (errno to tell why)
4165 int ntfs_set_inode_attributes(ntfs_inode *ni, u32 attrib)
4168 ATTR_FLAGS dirflags;
4173 settable = FILE_ATTR_SETTABLE;
4175 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4177 * Accept changing compression for a directory
4178 * and set index root accordingly
4180 settable |= FILE_ATTR_COMPRESSED;
4181 if ((ni->flags ^ cpu_to_le32(attrib))
4182 & FILE_ATTR_COMPRESSED) {
4183 if (ni->flags & FILE_ATTR_COMPRESSED)
4184 dirflags = const_cpu_to_le16(0);
4186 dirflags = ATTR_IS_COMPRESSED;
4187 res = ntfs_attr_set_flags(ni, AT_INDEX_ROOT,
4188 NTFS_INDEX_I30, 4, dirflags,
4189 ATTR_COMPRESSION_MASK);
4193 ni->flags = (ni->flags & ~settable)
4194 | (cpu_to_le32(attrib) & settable);
4195 NInoFileNameSetDirty(ni);
4204 * Return the ntfs attribute into an extended attribute
4205 * The attribute is expected according to cpu endianness
4207 * Returns 0, or -1 if there is a problem
4210 int ntfs_set_ntfs_attrib(ntfs_inode *ni,
4211 const char *value, size_t size, int flags)
4217 if (ni && value && (size >= sizeof(FILE_ATTR_FLAGS))) {
4218 if (!(flags & XATTR_CREATE)) {
4219 /* copy to avoid alignment problems */
4220 memcpy(&attrib,value,sizeof(FILE_ATTR_FLAGS));
4221 res = ntfs_set_inode_attributes(ni, attrib);
4226 return (res ? -1 : 0);
4229 #endif /* HAVE_SETXATTR */
4232 * Open $Secure once for all
4233 * returns zero if it succeeds
4234 * non-zero if it fails. This is not an error (on NTFS v1.x)
4238 int ntfs_open_secure(ntfs_volume *vol)
4244 vol->secure_ni = (ntfs_inode*)NULL;
4245 vol->secure_xsii = (ntfs_index_context*)NULL;
4246 vol->secure_xsdh = (ntfs_index_context*)NULL;
4247 if (vol->major_ver >= 3) {
4248 /* make sure this is a genuine $Secure inode 9 */
4249 ni = ntfs_pathname_to_inode(vol, NULL, "$Secure");
4250 if (ni && (ni->mft_no == 9)) {
4251 vol->secure_reentry = 0;
4252 vol->secure_xsii = ntfs_index_ctx_get(ni,
4254 vol->secure_xsdh = ntfs_index_ctx_get(ni,
4256 if (ni && vol->secure_xsii && vol->secure_xsdh) {
4257 vol->secure_ni = ni;
4267 * Allocated memory is freed to facilitate the detection of memory leaks
4270 void ntfs_close_secure(struct SECURITY_CONTEXT *scx)
4275 if (vol->secure_ni) {
4276 ntfs_index_ctx_put(vol->secure_xsii);
4277 ntfs_index_ctx_put(vol->secure_xsdh);
4278 ntfs_inode_close(vol->secure_ni);
4281 ntfs_free_mapping(scx->mapping);
4286 * API for direct access to security descriptors
4287 * based on Win32 API
4292 * Selective feeding of a security descriptor into user buffer
4294 * Returns TRUE if successful
4297 static BOOL feedsecurityattr(const char *attr, u32 selection,
4298 char *buf, u32 buflen, u32 *psize)
4300 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4301 SECURITY_DESCRIPTOR_RELATIVE *pnhead;
4306 unsigned int offdacl;
4307 unsigned int offsacl;
4308 unsigned int offowner;
4309 unsigned int offgroup;
4310 unsigned int daclsz;
4311 unsigned int saclsz;
4312 unsigned int usidsz;
4313 unsigned int gsidsz;
4314 unsigned int size; /* size of requested attributes */
4321 control = SE_SELF_RELATIVE;
4322 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4323 size = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4325 /* locate DACL if requested and available */
4326 if (phead->dacl && (selection & DACL_SECURITY_INFORMATION)) {
4327 offdacl = le32_to_cpu(phead->dacl);
4328 pdacl = (const ACL*)&attr[offdacl];
4329 daclsz = le16_to_cpu(pdacl->size);
4331 avail |= DACL_SECURITY_INFORMATION;
4333 offdacl = daclsz = 0;
4335 /* locate owner if requested and available */
4336 offowner = le32_to_cpu(phead->owner);
4337 if (offowner && (selection & OWNER_SECURITY_INFORMATION)) {
4338 /* find end of USID */
4339 pusid = (const SID*)&attr[offowner];
4340 usidsz = ntfs_sid_size(pusid);
4342 avail |= OWNER_SECURITY_INFORMATION;
4344 offowner = usidsz = 0;
4346 /* locate group if requested and available */
4347 offgroup = le32_to_cpu(phead->group);
4348 if (offgroup && (selection & GROUP_SECURITY_INFORMATION)) {
4349 /* find end of GSID */
4350 pgsid = (const SID*)&attr[offgroup];
4351 gsidsz = ntfs_sid_size(pgsid);
4353 avail |= GROUP_SECURITY_INFORMATION;
4355 offgroup = gsidsz = 0;
4357 /* locate SACL if requested and available */
4358 if (phead->sacl && (selection & SACL_SECURITY_INFORMATION)) {
4359 /* find end of SACL */
4360 offsacl = le32_to_cpu(phead->sacl);
4361 psacl = (const ACL*)&attr[offsacl];
4362 saclsz = le16_to_cpu(psacl->size);
4364 avail |= SACL_SECURITY_INFORMATION;
4366 offsacl = saclsz = 0;
4369 * Check having enough size in destination buffer
4370 * (required size is returned nevertheless so that
4371 * the request can be reissued with adequate size)
4373 if (size > buflen) {
4378 if (selection & OWNER_SECURITY_INFORMATION)
4379 control |= phead->control & SE_OWNER_DEFAULTED;
4380 if (selection & GROUP_SECURITY_INFORMATION)
4381 control |= phead->control & SE_GROUP_DEFAULTED;
4382 if (selection & DACL_SECURITY_INFORMATION)
4383 control |= phead->control
4386 | SE_DACL_AUTO_INHERITED
4387 | SE_DACL_PROTECTED);
4388 if (selection & SACL_SECURITY_INFORMATION)
4389 control |= phead->control
4392 | SE_SACL_AUTO_INHERITED
4393 | SE_SACL_PROTECTED);
4395 * copy header and feed new flags, even if no detailed data
4397 memcpy(buf,attr,sizeof(SECURITY_DESCRIPTOR_RELATIVE));
4398 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)buf;
4399 pnhead->control = control;
4400 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4402 /* copy DACL if requested and available */
4403 if (selection & avail & DACL_SECURITY_INFORMATION) {
4404 pnhead->dacl = cpu_to_le32(pos);
4405 memcpy(&buf[pos],&attr[offdacl],daclsz);
4408 pnhead->dacl = const_cpu_to_le32(0);
4410 /* copy SACL if requested and available */
4411 if (selection & avail & SACL_SECURITY_INFORMATION) {
4412 pnhead->sacl = cpu_to_le32(pos);
4413 memcpy(&buf[pos],&attr[offsacl],saclsz);
4416 pnhead->sacl = const_cpu_to_le32(0);
4418 /* copy owner if requested and available */
4419 if (selection & avail & OWNER_SECURITY_INFORMATION) {
4420 pnhead->owner = cpu_to_le32(pos);
4421 memcpy(&buf[pos],&attr[offowner],usidsz);
4424 pnhead->owner = const_cpu_to_le32(0);
4426 /* copy group if requested and available */
4427 if (selection & avail & GROUP_SECURITY_INFORMATION) {
4428 pnhead->group = cpu_to_le32(pos);
4429 memcpy(&buf[pos],&attr[offgroup],gsidsz);
4432 pnhead->group = const_cpu_to_le32(0);
4434 ntfs_log_error("Error in security descriptor size\n");
4443 * Merge a new security descriptor into the old one
4444 * and assign to designated file
4446 * Returns TRUE if successful
4449 static BOOL mergesecurityattr(ntfs_volume *vol, const char *oldattr,
4450 const char *newattr, u32 selection, ntfs_inode *ni)
4452 const SECURITY_DESCRIPTOR_RELATIVE *oldhead;
4453 const SECURITY_DESCRIPTOR_RELATIVE *newhead;
4454 SECURITY_DESCRIPTOR_RELATIVE *targhead;
4471 ok = FALSE; /* default return */
4472 oldhead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
4473 newhead = (const SECURITY_DESCRIPTOR_RELATIVE*)newattr;
4474 oldattrsz = ntfs_attr_size(oldattr);
4475 newattrsz = ntfs_attr_size(newattr);
4476 target = (char*)ntfs_malloc(oldattrsz + newattrsz);
4478 targhead = (SECURITY_DESCRIPTOR_RELATIVE*)target;
4479 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4480 control = SE_SELF_RELATIVE;
4482 * copy new DACL if selected
4483 * or keep old DACL if any
4485 if ((selection & DACL_SECURITY_INFORMATION) ?
4486 newhead->dacl : oldhead->dacl) {
4487 if (selection & DACL_SECURITY_INFORMATION) {
4488 offdacl = le32_to_cpu(newhead->dacl);
4489 pdacl = (const ACL*)&newattr[offdacl];
4491 offdacl = le32_to_cpu(oldhead->dacl);
4492 pdacl = (const ACL*)&oldattr[offdacl];
4494 size = le16_to_cpu(pdacl->size);
4495 memcpy(&target[pos], pdacl, size);
4496 targhead->dacl = cpu_to_le32(pos);
4499 targhead->dacl = const_cpu_to_le32(0);
4500 if (selection & DACL_SECURITY_INFORMATION) {
4501 control |= newhead->control
4504 | SE_DACL_PROTECTED);
4505 if (newhead->control & SE_DACL_AUTO_INHERIT_REQ)
4506 control |= SE_DACL_AUTO_INHERITED;
4508 control |= oldhead->control
4511 | SE_DACL_AUTO_INHERITED
4512 | SE_DACL_PROTECTED);
4514 * copy new SACL if selected
4515 * or keep old SACL if any
4517 if ((selection & SACL_SECURITY_INFORMATION) ?
4518 newhead->sacl : oldhead->sacl) {
4519 if (selection & SACL_SECURITY_INFORMATION) {
4520 offsacl = le32_to_cpu(newhead->sacl);
4521 psacl = (const ACL*)&newattr[offsacl];
4523 offsacl = le32_to_cpu(oldhead->sacl);
4524 psacl = (const ACL*)&oldattr[offsacl];
4526 size = le16_to_cpu(psacl->size);
4527 memcpy(&target[pos], psacl, size);
4528 targhead->sacl = cpu_to_le32(pos);
4531 targhead->sacl = const_cpu_to_le32(0);
4532 if (selection & SACL_SECURITY_INFORMATION) {
4533 control |= newhead->control
4536 | SE_SACL_PROTECTED);
4537 if (newhead->control & SE_SACL_AUTO_INHERIT_REQ)
4538 control |= SE_SACL_AUTO_INHERITED;
4540 control |= oldhead->control
4543 | SE_SACL_AUTO_INHERITED
4544 | SE_SACL_PROTECTED);
4546 * copy new OWNER if selected
4547 * or keep old OWNER if any
4549 if ((selection & OWNER_SECURITY_INFORMATION) ?
4550 newhead->owner : oldhead->owner) {
4551 if (selection & OWNER_SECURITY_INFORMATION) {
4552 offowner = le32_to_cpu(newhead->owner);
4553 powner = (const SID*)&newattr[offowner];
4555 offowner = le32_to_cpu(oldhead->owner);
4556 powner = (const SID*)&oldattr[offowner];
4558 size = ntfs_sid_size(powner);
4559 memcpy(&target[pos], powner, size);
4560 targhead->owner = cpu_to_le32(pos);
4563 targhead->owner = const_cpu_to_le32(0);
4564 if (selection & OWNER_SECURITY_INFORMATION)
4565 control |= newhead->control & SE_OWNER_DEFAULTED;
4567 control |= oldhead->control & SE_OWNER_DEFAULTED;
4569 * copy new GROUP if selected
4570 * or keep old GROUP if any
4572 if ((selection & GROUP_SECURITY_INFORMATION) ?
4573 newhead->group : oldhead->group) {
4574 if (selection & GROUP_SECURITY_INFORMATION) {
4575 offgroup = le32_to_cpu(newhead->group);
4576 pgroup = (const SID*)&newattr[offgroup];
4577 control |= newhead->control
4578 & SE_GROUP_DEFAULTED;
4580 offgroup = le32_to_cpu(oldhead->group);
4581 pgroup = (const SID*)&oldattr[offgroup];
4582 control |= oldhead->control
4583 & SE_GROUP_DEFAULTED;
4585 size = ntfs_sid_size(pgroup);
4586 memcpy(&target[pos], pgroup, size);
4587 targhead->group = cpu_to_le32(pos);
4590 targhead->group = const_cpu_to_le32(0);
4591 if (selection & GROUP_SECURITY_INFORMATION)
4592 control |= newhead->control & SE_GROUP_DEFAULTED;
4594 control |= oldhead->control & SE_GROUP_DEFAULTED;
4595 targhead->revision = SECURITY_DESCRIPTOR_REVISION;
4596 targhead->alignment = 0;
4597 targhead->control = control;
4598 ok = !update_secur_descr(vol, target, ni);
4604 int ntfs_get_inode_security(ntfs_inode *ni, u32 selection,
4605 char *buf, u32 buflen, u32 *psize)
4612 attr = getsecurityattr(ni->vol, ni);
4614 if (feedsecurityattr(attr, selection,
4615 buf, buflen, psize)) {
4616 if (test_nino_flag(ni, v3_Extensions)
4630 int ntfs_set_inode_security(ntfs_inode *ni, u32 selection, const char *attr)
4632 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4638 res = -1; /* default return */
4640 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4641 attrsz = ntfs_attr_size(attr);
4642 /* if selected, owner and group must be present or defaulted */
4643 missing = ((selection & OWNER_SECURITY_INFORMATION)
4645 && !(phead->control & SE_OWNER_DEFAULTED))
4646 || ((selection & GROUP_SECURITY_INFORMATION)
4648 && !(phead->control & SE_GROUP_DEFAULTED));
4650 && (phead->control & SE_SELF_RELATIVE)
4651 && ntfs_valid_descr(attr, attrsz)) {
4652 oldattr = getsecurityattr(ni->vol, ni);
4654 if (mergesecurityattr(ni->vol, oldattr, attr,
4668 * Return the security descriptor of a file
4669 * This is intended to be similar to GetFileSecurity() from Win32
4670 * in order to facilitate the development of portable tools
4672 * returns zero if unsuccessful (following Win32 conventions)
4674 * the securid if any
4676 * The Win32 API is :
4678 * BOOL WINAPI GetFileSecurity(
4679 * __in LPCTSTR lpFileName,
4680 * __in SECURITY_INFORMATION RequestedInformation,
4681 * __out_opt PSECURITY_DESCRIPTOR pSecurityDescriptor,
4682 * __in DWORD nLength,
4683 * __out LPDWORD lpnLengthNeeded
4688 int ntfs_get_file_security(struct SECURITY_API *scapi,
4689 const char *path, u32 selection,
4690 char *buf, u32 buflen, u32 *psize)
4696 res = 0; /* default return */
4697 if (scapi && (scapi->magic == MAGIC_API)) {
4698 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4700 attr = getsecurityattr(scapi->security.vol, ni);
4702 if (feedsecurityattr(attr,selection,
4703 buf,buflen,psize)) {
4704 if (test_nino_flag(ni, v3_Extensions)
4713 ntfs_inode_close(ni);
4716 if (!res) *psize = 0;
4718 errno = EINVAL; /* do not clear *psize */
4724 * Set the security descriptor of a file or directory
4725 * This is intended to be similar to SetFileSecurity() from Win32
4726 * in order to facilitate the development of portable tools
4728 * returns zero if unsuccessful (following Win32 conventions)
4730 * the securid if any
4732 * The Win32 API is :
4734 * BOOL WINAPI SetFileSecurity(
4735 * __in LPCTSTR lpFileName,
4736 * __in SECURITY_INFORMATION SecurityInformation,
4737 * __in PSECURITY_DESCRIPTOR pSecurityDescriptor
4741 int ntfs_set_file_security(struct SECURITY_API *scapi,
4742 const char *path, u32 selection, const char *attr)
4744 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4751 res = 0; /* default return */
4752 if (scapi && (scapi->magic == MAGIC_API) && attr) {
4753 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4754 attrsz = ntfs_attr_size(attr);
4755 /* if selected, owner and group must be present or defaulted */
4756 missing = ((selection & OWNER_SECURITY_INFORMATION)
4758 && !(phead->control & SE_OWNER_DEFAULTED))
4759 || ((selection & GROUP_SECURITY_INFORMATION)
4761 && !(phead->control & SE_GROUP_DEFAULTED));
4763 && (phead->control & SE_SELF_RELATIVE)
4764 && ntfs_valid_descr(attr, attrsz)) {
4765 ni = ntfs_pathname_to_inode(scapi->security.vol,
4768 oldattr = getsecurityattr(scapi->security.vol,
4771 if (mergesecurityattr(
4772 scapi->security.vol,
4775 if (test_nino_flag(ni,
4784 ntfs_inode_close(ni);
4795 * Return the attributes of a file
4796 * This is intended to be similar to GetFileAttributes() from Win32
4797 * in order to facilitate the development of portable tools
4799 * returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES)
4801 * The Win32 API is :
4803 * DWORD WINAPI GetFileAttributes(
4804 * __in LPCTSTR lpFileName
4808 int ntfs_get_file_attributes(struct SECURITY_API *scapi, const char *path)
4813 attrib = -1; /* default return */
4814 if (scapi && (scapi->magic == MAGIC_API) && path) {
4815 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4817 attrib = ntfs_get_inode_attributes(ni);
4818 ntfs_inode_close(ni);
4822 errno = EINVAL; /* do not clear *psize */
4828 * Set attributes to a file or directory
4829 * This is intended to be similar to SetFileAttributes() from Win32
4830 * in order to facilitate the development of portable tools
4832 * Only a few flags can be set (same list as Win32)
4834 * returns zero if unsuccessful (following Win32 conventions)
4835 * nonzero if successful
4837 * The Win32 API is :
4839 * BOOL WINAPI SetFileAttributes(
4840 * __in LPCTSTR lpFileName,
4841 * __in DWORD dwFileAttributes
4845 BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi,
4846 const char *path, s32 attrib)
4851 res = 0; /* default return */
4852 if (scapi && (scapi->magic == MAGIC_API) && path) {
4853 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4855 /* Win32 convention here : -1 means successful */
4856 if (!ntfs_set_inode_attributes(ni, attrib))
4858 if (ntfs_inode_close(ni))
4867 BOOL ntfs_read_directory(struct SECURITY_API *scapi,
4868 const char *path, ntfs_filldir_t callback, void *context)
4874 ok = FALSE; /* default return */
4875 if (scapi && (scapi->magic == MAGIC_API) && callback) {
4876 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4878 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4880 ntfs_readdir(ni,&pos,context,callback);
4881 ok = !ntfs_inode_close(ni);
4883 ntfs_inode_close(ni);
4889 errno = EINVAL; /* do not clear *psize */
4894 * read $SDS (for auditing security data)
4896 * Returns the number or read bytes, or -1 if there is an error
4899 int ntfs_read_sds(struct SECURITY_API *scapi,
4900 char *buf, u32 size, u32 offset)
4904 got = -1; /* default return */
4905 if (scapi && (scapi->magic == MAGIC_API)) {
4906 if (scapi->security.vol->secure_ni)
4907 got = ntfs_attr_data_read(scapi->security.vol->secure_ni,
4908 STREAM_SDS, 4, buf, size, offset);
4917 * read $SII (for auditing security data)
4919 * Returns next entry, or NULL if there is an error
4922 INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
4928 ntfs_index_context *xsii;
4930 ret = (INDEX_ENTRY*)NULL; /* default return */
4931 if (scapi && (scapi->magic == MAGIC_API)) {
4932 xsii = scapi->security.vol->secure_xsii;
4935 key.security_id = const_cpu_to_le32(0);
4936 found = !ntfs_index_lookup((char*)&key,
4937 sizeof(SII_INDEX_KEY), xsii);
4938 /* not supposed to find */
4939 if (!found && (errno == ENOENT))
4942 ret = ntfs_index_next(entry,xsii);
4953 * read $SDH (for auditing security data)
4955 * Returns next entry, or NULL if there is an error
4958 INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
4964 ntfs_index_context *xsdh;
4966 ret = (INDEX_ENTRY*)NULL; /* default return */
4967 if (scapi && (scapi->magic == MAGIC_API)) {
4968 xsdh = scapi->security.vol->secure_xsdh;
4971 key.hash = const_cpu_to_le32(0);
4972 key.security_id = const_cpu_to_le32(0);
4973 found = !ntfs_index_lookup((char*)&key,
4974 sizeof(SDH_INDEX_KEY), xsdh);
4975 /* not supposed to find */
4976 if (!found && (errno == ENOENT))
4979 ret = ntfs_index_next(entry,xsdh);
4982 } else errno = ENOTSUP;
4989 * Get the mapped user SID
4990 * A buffer of 40 bytes has to be supplied
4992 * returns the size of the SID, or zero and errno set if not found
4995 int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf)
5002 if (scapi && (scapi->magic == MAGIC_API)) {
5003 usid = ntfs_find_usid(scapi->security.mapping[MAPUSERS], uid, (SID*)&defusid);
5005 size = ntfs_sid_size(usid);
5006 memcpy(buf,usid,size);
5015 * Get the mapped group SID
5016 * A buffer of 40 bytes has to be supplied
5018 * returns the size of the SID, or zero and errno set if not found
5021 int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf)
5028 if (scapi && (scapi->magic == MAGIC_API)) {
5029 gsid = ntfs_find_gsid(scapi->security.mapping[MAPGROUPS], gid, (SID*)&defgsid);
5031 size = ntfs_sid_size(gsid);
5032 memcpy(buf,gsid,size);
5041 * Get the user mapped to a SID
5043 * returns the uid, or -1 if not found
5046 int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid)
5051 if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(usid)) {
5052 if (ntfs_same_sid(usid,adminsid))
5055 uid = ntfs_find_user(scapi->security.mapping[MAPUSERS], usid);
5067 * Get the group mapped to a SID
5069 * returns the uid, or -1 if not found
5072 int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid)
5077 if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(gsid)) {
5078 if (ntfs_same_sid(gsid,adminsid))
5081 gid = ntfs_find_group(scapi->security.mapping[MAPGROUPS], gsid);
5093 * Initializations before calling ntfs_get_file_security()
5094 * ntfs_set_file_security() and ntfs_read_directory()
5096 * Only allowed for root
5098 * Returns an (obscured) struct SECURITY_API* needed for further calls
5099 * NULL if not root (EPERM) or device is mounted (EBUSY)
5102 struct SECURITY_API *ntfs_initialize_file_security(const char *device,
5103 unsigned long flags)
5106 unsigned long mntflag;
5108 struct SECURITY_API *scapi;
5109 struct SECURITY_CONTEXT *scx;
5111 scapi = (struct SECURITY_API*)NULL;
5112 mnt = ntfs_check_if_mounted(device, &mntflag);
5113 if (!mnt && !(mntflag & NTFS_MF_MOUNTED) && !getuid()) {
5114 vol = ntfs_mount(device, flags);
5116 scapi = (struct SECURITY_API*)
5117 ntfs_malloc(sizeof(struct SECURITY_API));
5118 if (!ntfs_volume_get_free_space(vol)
5120 scapi->magic = MAGIC_API;
5121 scapi->seccache = (struct PERMISSIONS_CACHE*)NULL;
5122 scx = &scapi->security;
5124 scx->uid = getuid();
5125 scx->gid = getgid();
5126 scx->pseccache = &scapi->seccache;
5127 scx->vol->secure_flags = 0;
5128 /* accept no mapping and no $Secure */
5129 ntfs_build_mapping(scx,(const char*)NULL,TRUE);
5130 ntfs_open_secure(vol);
5136 mnt = ntfs_umount(vol,FALSE);
5137 scapi = (struct SECURITY_API*)NULL;
5149 * Leaving after ntfs_initialize_file_security()
5151 * Returns FALSE if FAILED
5154 BOOL ntfs_leave_file_security(struct SECURITY_API *scapi)
5160 if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) {
5161 vol = scapi->security.vol;
5162 ntfs_close_secure(&scapi->security);
5164 if (!ntfs_umount(vol, 0))