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-2009 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
45 #include <sys/xattr.h>
47 #ifdef HAVE_SYS_STAT_H
68 * JPA NTFS constants or structs
69 * should be moved to layout.h
72 #define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */
73 #define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */
74 #define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */
75 #define FIRST_SECURITY_ID 0x100 /* Lowest security id */
77 /* Mask for attributes which can be forced */
78 #define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY \
82 | FILE_ATTR_TEMPORARY \
84 | FILE_ATTR_NOT_CONTENT_INDEXED )
86 struct SII
{ /* this is an image of an $SII index entry */
96 /* did not find official description for the following */
99 le32 dataoffsl
; /* documented as badly aligned */
104 struct SDH
{ /* this is an image of an $SDH index entry */
115 /* did not find official description for the following */
125 * A few useful constants
128 static ntfschar sii_stream
[] = { const_cpu_to_le16('$'),
129 const_cpu_to_le16('S'),
130 const_cpu_to_le16('I'),
131 const_cpu_to_le16('I'),
132 const_cpu_to_le16(0) };
133 static ntfschar sdh_stream
[] = { const_cpu_to_le16('$'),
134 const_cpu_to_le16('S'),
135 const_cpu_to_le16('D'),
136 const_cpu_to_le16('H'),
137 const_cpu_to_le16(0) };
143 extern const SID
*nullsid
;
149 static const GUID __zero_guid
= { const_cpu_to_le32(0), const_cpu_to_le16(0),
150 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
151 static const GUID
*const zero_guid
= &__zero_guid
;
154 * ntfs_guid_is_zero - check if a GUID is zero
155 * @guid: [IN] guid to check
157 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
158 * and FALSE otherwise.
160 BOOL
ntfs_guid_is_zero(const GUID
*guid
)
162 return (memcmp(guid
, zero_guid
, sizeof(*zero_guid
)));
166 * ntfs_guid_to_mbs - convert a GUID to a multi byte string
167 * @guid: [IN] guid to convert
168 * @guid_str: [OUT] string in which to return the GUID (optional)
170 * Convert the GUID pointed to by @guid to a multi byte string of the form
171 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
172 * needs to be able to store at least 37 bytes.
174 * If @guid_str is not NULL it will contain the converted GUID on return. If
175 * it is NULL a string will be allocated and this will be returned. The caller
176 * is responsible for free()ing the string in that case.
178 * On success return the converted string and on failure return NULL with errno
179 * set to the error code.
181 char *ntfs_guid_to_mbs(const GUID
*guid
, char *guid_str
)
190 _guid_str
= guid_str
;
192 _guid_str
= (char*)ntfs_malloc(37);
196 res
= snprintf(_guid_str
, 37,
197 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
198 (unsigned int)le32_to_cpu(guid
->data1
),
199 le16_to_cpu(guid
->data2
), le16_to_cpu(guid
->data3
),
200 guid
->data4
[0], guid
->data4
[1],
201 guid
->data4
[2], guid
->data4
[3], guid
->data4
[4],
202 guid
->data4
[5], guid
->data4
[6], guid
->data4
[7]);
212 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
213 * @sid: [IN] SID for which to determine the maximum string size
215 * Determine the maximum multi byte string size in bytes which is needed to
216 * store the standard textual representation of the SID pointed to by @sid.
217 * See ntfs_sid_to_mbs(), below.
219 * On success return the maximum number of bytes needed to store the multi byte
220 * string and on failure return -1 with errno set to the error code.
222 int ntfs_sid_to_mbs_size(const SID
*sid
)
226 if (!ntfs_sid_is_valid(sid
)) {
230 /* Start with "S-". */
233 * Add the SID_REVISION. Hopefully the compiler will optimize this
234 * away as SID_REVISION is a constant.
236 for (i
= SID_REVISION
; i
> 0; i
/= 10)
241 * Add the identifier authority. If it needs to be in decimal, the
242 * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
243 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
245 if (!sid
->identifier_authority
.high_part
)
250 * Finally, add the sub authorities. For each we have a "-" followed
251 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
253 size
+= (1 + 10) * sid
->sub_authority_count
;
254 /* We need the zero byte at the end, too. */
256 return size
* sizeof(char);
260 * ntfs_sid_to_mbs - convert a SID to a multi byte string
261 * @sid: [IN] SID to convert
262 * @sid_str: [OUT] string in which to return the SID (optional)
263 * @sid_str_size: [IN] size in bytes of @sid_str
265 * Convert the SID pointed to by @sid to its standard textual representation.
266 * @sid_str (if not NULL) needs to be able to store at least
267 * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
268 * @sid_str if @sid_str is not NULL.
270 * The standard textual representation of the SID is of the form:
273 * - The first "S" is the literal character 'S' identifying the following
275 * - R is the revision level of the SID expressed as a sequence of digits
277 * - I is the 48-bit identifier_authority, expressed as digits in decimal,
278 * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
279 * - S... is one or more sub_authority values, expressed as digits in
282 * If @sid_str is not NULL it will contain the converted SUID on return. If it
283 * is NULL a string will be allocated and this will be returned. The caller is
284 * responsible for free()ing the string in that case.
286 * On success return the converted string and on failure return NULL with errno
287 * set to the error code.
289 char *ntfs_sid_to_mbs(const SID
*sid
, char *sid_str
, size_t sid_str_size
)
297 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
298 * check @sid, too. 8 is the minimum SID string size.
300 if (sid_str
&& (sid_str_size
< 8 || !ntfs_sid_is_valid(sid
))) {
304 /* Allocate string if not provided. */
306 cnt
= ntfs_sid_to_mbs_size(sid
);
309 s
= (char*)ntfs_malloc(cnt
);
313 /* So we know we allocated it. */
319 /* Start with "S-R-". */
320 i
= snprintf(s
, cnt
, "S-%hhu-", (unsigned char)sid
->revision
);
321 if (i
< 0 || i
>= cnt
)
325 /* Add the identifier authority. */
326 for (u
= i
= 0, j
= 40; i
< 6; i
++, j
-= 8)
327 u
+= (u64
)sid
->identifier_authority
.value
[i
] << j
;
328 if (!sid
->identifier_authority
.high_part
)
329 i
= snprintf(s
, cnt
, "%lu", (unsigned long)u
);
331 i
= snprintf(s
, cnt
, "0x%llx", (unsigned long long)u
);
332 if (i
< 0 || i
>= cnt
)
336 /* Finally, add the sub authorities. */
337 for (j
= 0; j
< sid
->sub_authority_count
; j
++) {
338 leauth
= sid
->sub_authority
[j
];
339 i
= snprintf(s
, cnt
, "-%u", (unsigned int)
340 le32_to_cpu(leauth
));
341 if (i
< 0 || i
>= cnt
)
359 * ntfs_generate_guid - generatates a random current guid.
360 * @guid: [OUT] pointer to a GUID struct to hold the generated guid.
362 * perhaps not a very good random number generator though...
364 void ntfs_generate_guid(GUID
*guid
)
369 for (i
= 0; i
< sizeof(GUID
); i
++) {
370 p
[i
] = (u8
)(random() & 0xFF);
372 p
[7] = (p
[7] & 0x0F) | 0x40;
374 p
[8] = (p
[8] & 0x3F) | 0x80;
379 * ntfs_security_hash - calculate the hash of a security descriptor
380 * @sd: self-relative security descriptor whose hash to calculate
381 * @length: size in bytes of the security descritor @sd
383 * Calculate the hash of the self-relative security descriptor @sd of length
386 * This hash is used in the $Secure system file as the primary key for the $SDH
387 * index and is also stored in the header of each security descriptor in the
388 * $SDS data stream as well as in the index data of both the $SII and $SDH
389 * indexes. In all three cases it forms part of the SDS_ENTRY_HEADER
392 * Return the calculated security hash in little endian.
394 le32
ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE
*sd
, const u32 len
)
396 const le32
*pos
= (const le32
*)sd
;
397 const le32
*end
= pos
+ (len
>> 2);
401 hash
= le32_to_cpup(pos
) + ntfs_rol32(hash
, 3);
404 return cpu_to_le32(hash
);
409 * copied and pasted from ntfs_fuse_read() and made independent
413 static int ntfs_local_read(ntfs_inode
*ni
,
414 ntfschar
*stream_name
, int stream_name_len
,
415 char *buf
, size_t size
, off_t offset
)
417 ntfs_attr
*na
= NULL
;
420 na
= ntfs_attr_open(ni
, AT_DATA
, stream_name
, stream_name_len
);
425 if ((size_t)offset
< (size_t)na
->data_size
) {
426 if (offset
+ size
> (size_t)na
->data_size
)
427 size
= na
->data_size
- offset
;
429 res
= ntfs_attr_pread(na
, offset
, size
, buf
);
430 if ((off_t
)res
< (off_t
)size
)
431 ntfs_log_perror("ntfs_attr_pread partial read "
432 "(%lld : %lld <> %d)",
434 (long long)size
, res
);
454 * copied and pasted from ntfs_fuse_write() and made independent
458 static int ntfs_local_write(ntfs_inode
*ni
,
459 ntfschar
*stream_name
, int stream_name_len
,
460 char *buf
, size_t size
, off_t offset
)
462 ntfs_attr
*na
= NULL
;
465 na
= ntfs_attr_open(ni
, AT_DATA
, stream_name
, stream_name_len
);
471 res
= ntfs_attr_pwrite(na
, offset
, size
, buf
);
473 ntfs_log_perror("ntfs_attr_pwrite partial write (%lld: "
474 "%lld <> %d)", (long long)offset
,
475 (long long)size
, res
);
493 * Get the first entry of current index block
494 * cut and pasted form ntfs_ie_get_first() in index.c
497 static INDEX_ENTRY
*ntfs_ie_get_first(INDEX_HEADER
*ih
)
499 return (INDEX_ENTRY
*)((u8
*)ih
+ le32_to_cpu(ih
->entries_offset
));
503 * Stuff a 256KB block into $SDS before writing descriptors
506 * This prevents $SDS from being automatically declared as sparse
507 * when the second copy of the first security descriptor is written
508 * 256KB further ahead.
510 * Having $SDS declared as a sparse file is not wrong by itself
511 * and chkdsk leaves it as a sparse file. It does however complain
512 * and add a sparse flag (0x0200) into field file_attributes of
513 * STANDARD_INFORMATION of $Secure. This probably means that a
514 * sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse
515 * files (FILE_ATTR_SPARSE_FILE).
517 * Windows normally does not convert to sparse attribute or sparse
518 * file. Stuffing is just a way to get to the same result.
521 static int entersecurity_stuff(ntfs_volume
*vol
, off_t offs
)
530 stuff
= (char*)ntfs_malloc(STUFFSZ
);
532 memset(stuff
, 0, STUFFSZ
);
534 written
= ntfs_local_write(vol
->secure_ni
,
535 STREAM_SDS
, 4, stuff
, STUFFSZ
, offs
);
536 if (written
== STUFFSZ
) {
543 } while (!res
&& (total
< ALIGN_SDS_BLOCK
));
553 * Enter a new security descriptor into $Secure (data only)
554 * it has to be written twice with an offset of 256KB
556 * Should only be called by entersecurityattr() to ensure consistency
558 * Returns zero if sucessful
561 static int entersecurity_data(ntfs_volume
*vol
,
562 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
,
563 le32 hash
, le32 keyid
, off_t offs
, int gap
)
570 SECURITY_DESCRIPTOR_HEADER
*phsds
;
573 fullsz
= attrsz
+ gap
+ sizeof(SECURITY_DESCRIPTOR_HEADER
);
574 fullattr
= (char*)ntfs_malloc(fullsz
);
577 * Clear the gap from previous descriptor
578 * this could be useful for appending the second
579 * copy to the end of file. When creating a new
580 * 256K block, the gap is cleared while writing
584 memset(fullattr
,0,gap
);
585 memcpy(&fullattr
[gap
+ sizeof(SECURITY_DESCRIPTOR_HEADER
)],
587 phsds
= (SECURITY_DESCRIPTOR_HEADER
*)&fullattr
[gap
];
589 phsds
->security_id
= keyid
;
590 phsds
->offset
= cpu_to_le64(offs
);
591 phsds
->length
= cpu_to_le32(fullsz
- gap
);
592 written1
= ntfs_local_write(vol
->secure_ni
,
593 STREAM_SDS
, 4, fullattr
, fullsz
,
595 written2
= ntfs_local_write(vol
->secure_ni
,
596 STREAM_SDS
, 4, fullattr
, fullsz
,
597 offs
- gap
+ ALIGN_SDS_BLOCK
);
598 if ((written1
== fullsz
)
599 && (written2
== written1
))
610 * Enter a new security descriptor in $Secure (indexes only)
612 * Should only be called by entersecurityattr() to ensure consistency
614 * Returns zero if sucessful
617 static int entersecurity_indexes(ntfs_volume
*vol
, s64 attrsz
,
618 le32 hash
, le32 keyid
, off_t offs
)
628 ntfs_index_context
*xsii
;
629 ntfs_index_context
*xsdh
;
634 /* enter a new $SII record */
636 xsii
= vol
->secure_xsii
;
637 ntfs_index_ctx_reinit(xsii
);
638 newsii
.offs
= const_cpu_to_le16(20);
639 newsii
.size
= const_cpu_to_le16(sizeof(struct SII
) - 20);
640 newsii
.fill1
= const_cpu_to_le32(0);
641 newsii
.indexsz
= const_cpu_to_le16(sizeof(struct SII
));
642 newsii
.indexksz
= const_cpu_to_le16(sizeof(SII_INDEX_KEY
));
643 newsii
.flags
= const_cpu_to_le16(0);
644 newsii
.fill2
= const_cpu_to_le16(0);
645 newsii
.keysecurid
= keyid
;
647 newsii
.securid
= keyid
;
648 realign
.all
= cpu_to_le64(offs
);
649 newsii
.dataoffsh
= realign
.parts
.dataoffsh
;
650 newsii
.dataoffsl
= realign
.parts
.dataoffsl
;
651 newsii
.datasize
= cpu_to_le32(attrsz
652 + sizeof(SECURITY_DESCRIPTOR_HEADER
));
653 if (!ntfs_ie_add(xsii
,(INDEX_ENTRY
*)&newsii
)) {
655 /* enter a new $SDH record */
657 xsdh
= vol
->secure_xsdh
;
658 ntfs_index_ctx_reinit(xsdh
);
659 newsdh
.offs
= const_cpu_to_le16(24);
660 newsdh
.size
= const_cpu_to_le16(
661 sizeof(SECURITY_DESCRIPTOR_HEADER
));
662 newsdh
.fill1
= const_cpu_to_le32(0);
663 newsdh
.indexsz
= const_cpu_to_le16(
665 newsdh
.indexksz
= const_cpu_to_le16(
666 sizeof(SDH_INDEX_KEY
));
667 newsdh
.flags
= const_cpu_to_le16(0);
668 newsdh
.fill2
= const_cpu_to_le16(0);
669 newsdh
.keyhash
= hash
;
670 newsdh
.keysecurid
= keyid
;
672 newsdh
.securid
= keyid
;
673 newsdh
.dataoffsh
= realign
.parts
.dataoffsh
;
674 newsdh
.dataoffsl
= realign
.parts
.dataoffsl
;
675 newsdh
.datasize
= cpu_to_le32(attrsz
676 + sizeof(SECURITY_DESCRIPTOR_HEADER
));
677 /* special filler value, Windows generally */
678 /* fills with 0x00490049, sometimes with zero */
679 newsdh
.fill3
= const_cpu_to_le32(0x00490049);
680 if (!ntfs_ie_add(xsdh
,(INDEX_ENTRY
*)&newsdh
))
687 * Enter a new security descriptor in $Secure (data and indexes)
688 * Returns id of entry, or zero if there is a problem.
689 * (should not be called for NTFS version < 3.0)
691 * important : calls have to be serialized, however no locking is
692 * needed while fuse is not multithreaded
695 static le32
entersecurityattr(ntfs_volume
*vol
,
696 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
,
716 ntfs_index_context
*xsii
;
720 /* find the first available securid beyond the last key */
721 /* in $Secure:$SII. This also determines the first */
722 /* available location in $Secure:$SDS, as this stream */
723 /* is always appended to and the id's are allocated */
726 securid
= const_cpu_to_le32(0);
727 xsii
= vol
->secure_xsii
;
728 ntfs_index_ctx_reinit(xsii
);
730 keyid
= const_cpu_to_le32(-1);
732 found
= !ntfs_index_lookup((char*)&keyid
,
733 sizeof(SII_INDEX_KEY
), xsii
);
734 if (!found
&& (errno
!= ENOENT
)) {
735 ntfs_log_perror("Inconsistency in index $SII");
736 psii
= (struct SII
*)NULL
;
738 /* restore errno to avoid misinterpretation */
741 psii
= (struct SII
*)xsii
->entry
;
745 * Get last entry in block, but must get first one
746 * one first, as we should already be beyond the
747 * last one. For some reason the search for the last
748 * entry sometimes does not return the last block...
749 * we assume this can only happen in root block
751 if (xsii
->is_in_root
)
752 entry
= ntfs_ie_get_first
753 ((INDEX_HEADER
*)&xsii
->ir
->index
);
755 entry
= ntfs_ie_get_first
756 ((INDEX_HEADER
*)&xsii
->ib
->index
);
758 * All index blocks should be at least half full
759 * so there always is a last entry but one,
760 * except when creating the first entry in index root.
761 * A simplified version of next(), limited to
762 * current index node, could be used
764 keyid
= const_cpu_to_le32(0);
766 next
= ntfs_index_next(entry
,xsii
);
768 psii
= (struct SII
*)next
;
769 /* save last key and */
770 /* available position */
771 keyid
= psii
->keysecurid
;
772 realign
.parts
.dataoffsh
774 realign
.parts
.dataoffsl
776 offs
= le64_to_cpu(realign
.all
);
777 size
= le32_to_cpu(psii
->datasize
);
784 * could not find any entry, before creating the first
785 * entry, make a double check by making sure size of $SII
786 * is less than needed for one entry
788 securid
= const_cpu_to_le32(0);
789 na
= ntfs_attr_open(vol
->secure_ni
,AT_INDEX_ROOT
,sii_stream
,4);
791 if ((size_t)na
->data_size
< sizeof(struct SII
)) {
792 ntfs_log_error("Creating the first security_id\n");
793 securid
= const_cpu_to_le32(FIRST_SECURITY_ID
);
798 ntfs_log_error("Error creating a security_id\n");
802 newkey
= le32_to_cpu(keyid
) + 1;
803 securid
= cpu_to_le32(newkey
);
806 * The security attr has to be written twice 256KB
807 * apart. This implies that offsets like
808 * 0x40000*odd_integer must be left available for
809 * the second copy. So align to next block when
810 * the last byte overflows on a wrong block.
814 gap
= (-size
) & (ALIGN_SDS_ENTRY
- 1);
816 if ((offs
+ attrsz
+ sizeof(SECURITY_DESCRIPTOR_HEADER
) - 1)
818 offs
= ((offs
+ attrsz
819 + sizeof(SECURITY_DESCRIPTOR_HEADER
) - 1)
820 | (ALIGN_SDS_BLOCK
- 1)) + 1;
822 if (!(offs
& (ALIGN_SDS_BLOCK
- 1)))
823 entersecurity_stuff(vol
, offs
);
825 * now write the security attr to storage :
826 * first data, then SII, then SDH
827 * If failure occurs while writing SDS, data will never
828 * be accessed through indexes, and will be overwritten
829 * by the next allocated descriptor
830 * If failure occurs while writing SII, the id has not
831 * recorded and will be reallocated later
832 * If failure occurs while writing SDH, the space allocated
833 * in SDS or SII will not be reused, an inconsistency
834 * will persist with no significant consequence
836 if (entersecurity_data(vol
, attr
, attrsz
, hash
, securid
, offs
, gap
)
837 || entersecurity_indexes(vol
, attrsz
, hash
, securid
, offs
))
838 securid
= const_cpu_to_le32(0);
840 /* inode now is dirty, synchronize it all */
841 ntfs_index_entry_mark_dirty(vol
->secure_xsii
);
842 ntfs_index_ctx_reinit(vol
->secure_xsii
);
843 ntfs_index_entry_mark_dirty(vol
->secure_xsdh
);
844 ntfs_index_ctx_reinit(vol
->secure_xsdh
);
845 NInoSetDirty(vol
->secure_ni
);
846 if (ntfs_inode_sync(vol
->secure_ni
))
847 ntfs_log_perror("Could not sync $Secure\n");
852 * Find a matching security descriptor in $Secure,
853 * if none, allocate a new id and write the descriptor to storage
854 * Returns id of entry, or zero if there is a problem.
856 * important : calls have to be serialized, however no locking is
857 * needed while fuse is not multithreaded
860 static le32
setsecurityattr(ntfs_volume
*vol
,
861 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
)
863 struct SDH
*psdh
; /* this is an image of index (le) */
877 ntfs_index_context
*xsdh
;
885 hash
= ntfs_security_hash(attr
,attrsz
);
886 oldattr
= (char*)NULL
;
887 securid
= const_cpu_to_le32(0);
889 xsdh
= vol
->secure_xsdh
;
890 if (vol
->secure_ni
&& xsdh
&& !vol
->secure_reentry
++) {
891 ntfs_index_ctx_reinit(xsdh
);
893 * find the nearest key as (hash,0)
894 * (do not search for partial key : in case of collision,
895 * it could return a key which is not the first one which
899 key
.security_id
= const_cpu_to_le32(0);
901 found
= !ntfs_index_lookup((char*)&key
,
902 sizeof(SDH_INDEX_KEY
), xsdh
);
903 if (!found
&& (errno
!= ENOENT
))
904 ntfs_log_perror("Inconsistency in index $SDH");
906 /* restore errno to avoid misinterpretation */
911 * lookup() may return a node with no data,
914 if (entry
->ie_flags
& INDEX_ENTRY_END
)
915 entry
= ntfs_index_next(entry
,xsdh
);
918 psdh
= (struct SDH
*)entry
;
920 size
= (size_t) le32_to_cpu(psdh
->datasize
)
921 - sizeof(SECURITY_DESCRIPTOR_HEADER
);
923 /* if hash is not the same, the key is not present */
924 if (psdh
&& (size
> 0)
925 && (psdh
->keyhash
== hash
)) {
926 /* if hash is the same */
927 /* check the whole record */
928 realign
.parts
.dataoffsh
= psdh
->dataoffsh
;
929 realign
.parts
.dataoffsl
= psdh
->dataoffsl
;
930 offs
= le64_to_cpu(realign
.all
)
931 + sizeof(SECURITY_DESCRIPTOR_HEADER
);
932 oldattr
= (char*)ntfs_malloc(size
);
934 rdsize
= ntfs_local_read(
937 oldattr
, size
, offs
);
938 found
= (rdsize
== size
)
939 && !memcmp(oldattr
,attr
,size
);
941 /* if the records do not compare */
942 /* (hash collision), try next one */
944 entry
= ntfs_index_next(
951 } while (collision
&& entry
);
953 securid
= psdh
->keysecurid
;
957 securid
= const_cpu_to_le32(0);
961 * have to build a new one
963 securid
= entersecurityattr(vol
,
969 if (--vol
->secure_reentry
)
970 ntfs_log_perror("Reentry error, check no multithreading\n");
976 * Update the security descriptor of a file
977 * Either as an attribute (complying with pre v3.x NTFS version)
978 * or, when possible, as an entry in $Secure (for NTFS v3.x)
980 * returns 0 if success
983 static int update_secur_descr(ntfs_volume
*vol
,
984 char *newattr
, ntfs_inode
*ni
)
991 newattrsz
= ntfs_attr_size(newattr
);
993 #if !FORCE_FORMAT_v1x
994 if ((vol
->major_ver
< 3) || !vol
->secure_ni
) {
997 /* update for NTFS format v1.x */
999 /* update the old security attribute */
1000 na
= ntfs_attr_open(ni
, AT_SECURITY_DESCRIPTOR
, AT_UNNAMED
, 0);
1002 /* resize attribute */
1003 res
= ntfs_attr_truncate(na
, (s64
) newattrsz
);
1004 /* overwrite value */
1006 written
= (int)ntfs_attr_pwrite(na
, (s64
) 0,
1007 (s64
) newattrsz
, newattr
);
1008 if (written
!= newattrsz
) {
1009 ntfs_log_error("Failed to update "
1010 "a v1.x security descriptor\n");
1016 ntfs_attr_close(na
);
1017 /* if old security attribute was found, also */
1018 /* truncate standard information attribute to v1.x */
1019 /* this is needed when security data is wanted */
1020 /* as v1.x though volume is formatted for v3.x */
1021 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
1024 clear_nino_flag(ni
, v3_Extensions
);
1026 * Truncating the record does not sweep extensions
1027 * from copy in memory. Clear security_id to be safe
1029 ni
->security_id
= const_cpu_to_le32(0);
1030 res
= ntfs_attr_truncate(na
, (s64
)48);
1031 ntfs_attr_close(na
);
1032 clear_nino_flag(ni
, v3_Extensions
);
1036 * insert the new security attribute if there
1039 res
= ntfs_attr_add(ni
, AT_SECURITY_DESCRIPTOR
,
1040 AT_UNNAMED
, 0, (u8
*)newattr
,
1043 #if !FORCE_FORMAT_v1x
1046 /* update for NTFS format v3.x */
1050 securid
= setsecurityattr(vol
,
1051 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
1054 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
1058 if (!test_nino_flag(ni
, v3_Extensions
)) {
1059 /* expand standard information attribute to v3.x */
1060 res
= ntfs_attr_truncate(na
,
1061 (s64
)sizeof(STANDARD_INFORMATION
));
1062 ni
->owner_id
= const_cpu_to_le32(0);
1063 ni
->quota_charged
= const_cpu_to_le64(0);
1064 ni
->usn
= const_cpu_to_le64(0);
1065 ntfs_attr_remove(ni
,
1066 AT_SECURITY_DESCRIPTOR
,
1069 set_nino_flag(ni
, v3_Extensions
);
1070 ni
->security_id
= securid
;
1071 ntfs_attr_close(na
);
1073 ntfs_log_error("Failed to update "
1074 "standard informations\n");
1083 /* mark node as dirty */
1085 ntfs_inode_sync(ni
); /* useful ? */
1090 * Upgrade the security descriptor of a file
1091 * This is intended to allow graceful upgrades for files which
1092 * were created in previous versions, with a security attributes
1093 * and no security id.
1095 * It will allocate a security id and replace the individual
1096 * security attribute by a reference to the global one
1098 * Special files are not upgraded (currently / and files in
1101 * Though most code is similar to update_secur_desc() it has
1102 * been kept apart to facilitate the further processing of
1103 * special cases or even to remove it if found dangerous.
1105 * returns 0 if success,
1106 * 1 if not upgradable. This is not an error.
1107 * -1 if there is a problem
1110 static int upgrade_secur_desc(ntfs_volume
*vol
,
1111 const char *attr
, ntfs_inode
*ni
)
1119 * upgrade requires NTFS format v3.x
1120 * also refuse upgrading for special files
1121 * whose number is less than FILE_first_user
1124 if ((vol
->major_ver
>= 3)
1125 && (ni
->mft_no
< FILE_first_user
)) {
1126 attrsz
= ntfs_attr_size(attr
);
1127 securid
= setsecurityattr(vol
,
1128 (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
,
1131 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
1135 /* expand standard information attribute to v3.x */
1136 res
= ntfs_attr_truncate(na
,
1137 (s64
)sizeof(STANDARD_INFORMATION
));
1138 ni
->owner_id
= const_cpu_to_le32(0);
1139 ni
->quota_charged
= const_cpu_to_le64(0);
1140 ni
->usn
= const_cpu_to_le64(0);
1141 ntfs_attr_remove(ni
, AT_SECURITY_DESCRIPTOR
,
1143 set_nino_flag(ni
, v3_Extensions
);
1144 ni
->security_id
= securid
;
1145 ntfs_attr_close(na
);
1147 ntfs_log_error("Failed to upgrade "
1148 "standard informations\n");
1154 /* mark node as dirty */
1156 ntfs_inode_sync(ni
); /* useful ? */
1164 * Optional simplified checking of group membership
1166 * This only takes into account the groups defined in
1167 * /etc/group at initialization time.
1168 * It does not take into account the groups dynamically set by
1169 * setgroups() nor the changes in /etc/group since initialization
1171 * This optional method could be useful if standard checking
1172 * leads to a performance concern.
1174 * Should not be called for user root, however the group may be root
1178 static BOOL
staticgroupmember(struct SECURITY_CONTEXT
*scx
, uid_t uid
, gid_t gid
)
1183 struct MAPPING
*user
;
1187 user
= scx
->mapping
[MAPUSERS
];
1188 while (user
&& ((uid_t
)user
->xid
!= uid
))
1191 groups
= user
->groups
;
1192 grcnt
= user
->grcnt
;
1193 while ((--grcnt
>= 0) && (groups
[grcnt
] != gid
)) { }
1194 ingroup
= (grcnt
>= 0);
1202 * Check whether current thread owner is member of file group
1204 * Should not be called for user root, however the group may be root
1206 * As indicated by Miklos Szeredi :
1208 * The group list is available in
1210 * /proc/$PID/task/$TID/status
1212 * and fuse supplies TID in get_fuse_context()->pid. The only problem is
1213 * finding out PID, for which I have no good solution, except to iterate
1214 * through all processes. This is rather slow, but may be speeded up
1215 * with caching and heuristics (for single threaded programs PID = TID).
1217 * The following implementation gets the group list from
1218 * /proc/$TID/task/$TID/status which apparently exists and
1219 * contains the same data.
1222 static BOOL
groupmember(struct SECURITY_CONTEXT
*scx
, uid_t uid
, gid_t gid
)
1224 static char key
[] = "\nGroups:";
1227 enum { INKEY
, INSEP
, INNUM
, INEND
} state
;
1237 if (scx
->vol
->secure_flags
& (1 << SECURITY_STATICGRPS
))
1238 ismember
= staticgroupmember(scx
, uid
, gid
);
1240 ismember
= FALSE
; /* default return */
1242 sprintf(filename
,"/proc/%u/task/%u/status",tid
,tid
);
1243 fd
= open(filename
,O_RDONLY
);
1245 got
= read(fd
, buf
, BUFSZ
);
1252 * A simple automaton to process lines like
1253 * Groups: 14 500 513
1259 got
= read(fd
, buf
, BUFSZ
);
1262 c
= *p
++; /* 0 at end of file */
1266 if (key
[matched
] == c
) {
1267 if (!key
[++matched
])
1276 if ((c
>= '0') && (c
<= '9')) {
1280 if ((c
!= ' ') && (c
!= '\t'))
1284 if ((c
>= '0') && (c
<= '9'))
1285 grp
= grp
*10 + c
- '0';
1287 ismember
= (grp
== gid
);
1288 if ((c
!= ' ') && (c
!= '\t'))
1296 } while (!ismember
&& c
&& (state
!= INEND
));
1299 ntfs_log_error("No group record found in %s\n",filename
);
1301 ntfs_log_error("Could not open %s\n",filename
);
1307 * Cacheing is done two-way :
1308 * - from uid, gid and perm to securid (CACHED_SECURID)
1309 * - from a securid to uid, gid and perm (CACHED_PERMISSIONS)
1311 * CACHED_SECURID data is kept in a most-recent-first list
1312 * which should not be too long to be efficient. Its optimal
1313 * size is depends on usage and is hard to determine.
1315 * CACHED_PERMISSIONS data is kept in a two-level indexed array. It
1316 * is optimal at the expense of storage. Use of a most-recent-first
1317 * list would save memory and provide similar performances for
1318 * standard usage, but not for file servers with too many file
1321 * CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS
1322 * for legacy directories which were not allocated a security_id
1323 * it is organized in a most-recent-first list.
1325 * In main caches, data is never invalidated, as the meaning of
1326 * a security_id only changes when user mapping is changed, which
1327 * current implies remounting. However returned entries may be
1328 * overwritten at next update, so data has to be copied elsewhere
1329 * before another cache update is made.
1330 * In legacy cache, data has to be invalidated when protection is
1333 * Though the same data may be found in both list, they
1334 * must be kept separately : the interpretation of ACL
1335 * in both direction are approximations which could be non
1336 * reciprocal for some configuration of the user mapping data
1338 * During the process of recompiling ntfs-3g from a tgz archive,
1339 * security processing added 7.6% to the cpu time used by ntfs-3g
1340 * and 30% if the cache is disabled.
1343 static struct PERMISSIONS_CACHE
*create_caches(struct SECURITY_CONTEXT
*scx
,
1346 struct PERMISSIONS_CACHE
*cache
;
1347 unsigned int index1
;
1350 cache
= (struct PERMISSIONS_CACHE
*)NULL
;
1351 /* create the first permissions blocks */
1352 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1353 cache
= (struct PERMISSIONS_CACHE
*)
1354 ntfs_malloc(sizeof(struct PERMISSIONS_CACHE
)
1355 + index1
*sizeof(struct CACHED_PERMISSIONS
*));
1357 cache
->head
.last
= index1
;
1358 cache
->head
.p_reads
= 0;
1359 cache
->head
.p_hits
= 0;
1360 cache
->head
.p_writes
= 0;
1361 *scx
->pseccache
= cache
;
1362 for (i
=0; i
<=index1
; i
++)
1363 cache
->cachetable
[i
]
1364 = (struct CACHED_PERMISSIONS
*)NULL
;
1370 * Free memory used by caches
1371 * The only purpose is to facilitate the detection of memory leaks
1374 static void free_caches(struct SECURITY_CONTEXT
*scx
)
1376 unsigned int index1
;
1377 struct PERMISSIONS_CACHE
*pseccache
;
1379 pseccache
= *scx
->pseccache
;
1381 for (index1
=0; index1
<=pseccache
->head
.last
; index1
++)
1382 if (pseccache
->cachetable
[index1
]) {
1384 struct CACHED_PERMISSIONS
*cacheentry
;
1385 unsigned int index2
;
1387 for (index2
=0; index2
<(1<< CACHE_PERMISSIONS_BITS
); index2
++) {
1388 cacheentry
= &pseccache
->cachetable
[index1
][index2
];
1389 if (cacheentry
->valid
1390 && cacheentry
->pxdesc
)
1391 free(cacheentry
->pxdesc
);
1394 free(pseccache
->cachetable
[index1
]);
1400 static int compare(const struct CACHED_SECURID
*cached
,
1401 const struct CACHED_SECURID
*item
)
1407 /* only compare data and sizes */
1408 csize
= (cached
->variable
?
1409 sizeof(struct POSIX_ACL
)
1410 + (((struct POSIX_SECURITY
*)cached
->variable
)->acccnt
1411 + ((struct POSIX_SECURITY
*)cached
->variable
)->defcnt
)
1412 *sizeof(struct POSIX_ACE
) :
1414 isize
= (item
->variable
?
1415 sizeof(struct POSIX_ACL
)
1416 + (((struct POSIX_SECURITY
*)item
->variable
)->acccnt
1417 + ((struct POSIX_SECURITY
*)item
->variable
)->defcnt
)
1418 *sizeof(struct POSIX_ACE
) :
1420 return ((cached
->uid
!= item
->uid
)
1421 || (cached
->gid
!= item
->gid
)
1422 || (cached
->dmode
!= item
->dmode
)
1426 && memcmp(&((struct POSIX_SECURITY
*)cached
->variable
)->acl
,
1427 &((struct POSIX_SECURITY
*)item
->variable
)->acl
, csize
)));
1429 return ((cached
->uid
!= item
->uid
)
1430 || (cached
->gid
!= item
->gid
)
1431 || (cached
->dmode
!= item
->dmode
));
1435 static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY
*cached
,
1436 const struct CACHED_PERMISSIONS_LEGACY
*item
)
1438 return (cached
->mft_no
!= item
->mft_no
);
1442 * Resize permission cache table
1443 * do not call unless resizing is needed
1445 * If allocation fails, the cache size is not updated
1446 * Lack of memory is not considered as an error, the cache is left
1447 * consistent and errno is not set.
1450 static void resize_cache(struct SECURITY_CONTEXT
*scx
,
1453 struct PERMISSIONS_CACHE
*oldcache
;
1454 struct PERMISSIONS_CACHE
*newcache
;
1457 unsigned int index1
;
1460 oldcache
= *scx
->pseccache
;
1461 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1462 newcnt
= index1
+ 1;
1463 if (newcnt
<= ((CACHE_PERMISSIONS_SIZE
1464 + (1 << CACHE_PERMISSIONS_BITS
)
1465 - 1) >> CACHE_PERMISSIONS_BITS
)) {
1466 /* expand cache beyond current end, do not use realloc() */
1467 /* to avoid losing data when there is no more memory */
1468 oldcnt
= oldcache
->head
.last
+ 1;
1469 newcache
= (struct PERMISSIONS_CACHE
*)
1471 sizeof(struct PERMISSIONS_CACHE
)
1472 + (newcnt
- 1)*sizeof(struct CACHED_PERMISSIONS
*));
1474 memcpy(newcache
,oldcache
,
1475 sizeof(struct PERMISSIONS_CACHE
)
1476 + (oldcnt
- 1)*sizeof(struct CACHED_PERMISSIONS
*));
1478 /* mark new entries as not valid */
1479 for (i
=newcache
->head
.last
+1; i
<=index1
; i
++)
1480 newcache
->cachetable
[i
]
1481 = (struct CACHED_PERMISSIONS
*)NULL
;
1482 newcache
->head
.last
= index1
;
1483 *scx
->pseccache
= newcache
;
1489 * Enter uid, gid and mode into cache, if possible
1491 * returns the updated or created cache entry,
1492 * or NULL if not possible (typically if there is no
1493 * security id associated)
1497 static struct CACHED_PERMISSIONS
*enter_cache(struct SECURITY_CONTEXT
*scx
,
1498 ntfs_inode
*ni
, uid_t uid
, gid_t gid
,
1499 struct POSIX_SECURITY
*pxdesc
)
1501 static struct CACHED_PERMISSIONS
*enter_cache(struct SECURITY_CONTEXT
*scx
,
1502 ntfs_inode
*ni
, uid_t uid
, gid_t gid
, mode_t mode
)
1505 struct CACHED_PERMISSIONS
*cacheentry
;
1506 struct CACHED_PERMISSIONS
*cacheblock
;
1507 struct PERMISSIONS_CACHE
*pcache
;
1511 struct POSIX_SECURITY
*pxcached
;
1513 unsigned int index1
;
1514 unsigned int index2
;
1517 /* cacheing is only possible if a security_id has been defined */
1518 if (test_nino_flag(ni
, v3_Extensions
)
1519 && ni
->security_id
) {
1521 * Immediately test the most frequent situation
1522 * where the entry exists
1524 securindex
= le32_to_cpu(ni
->security_id
);
1525 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1526 index2
= securindex
& ((1 << CACHE_PERMISSIONS_BITS
) - 1);
1527 pcache
= *scx
->pseccache
;
1529 && (pcache
->head
.last
>= index1
)
1530 && pcache
->cachetable
[index1
]) {
1531 cacheentry
= &pcache
->cachetable
[index1
][index2
];
1532 cacheentry
->uid
= uid
;
1533 cacheentry
->gid
= gid
;
1535 if (cacheentry
->valid
&& cacheentry
->pxdesc
)
1536 free(cacheentry
->pxdesc
);
1538 pxsize
= sizeof(struct POSIX_SECURITY
)
1539 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1540 pxcached
= (struct POSIX_SECURITY
*)malloc(pxsize
);
1542 memcpy(pxcached
, pxdesc
, pxsize
);
1543 cacheentry
->pxdesc
= pxcached
;
1545 cacheentry
->valid
= 0;
1546 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1548 cacheentry
->mode
= pxdesc
->mode
& 07777;
1550 cacheentry
->pxdesc
= (struct POSIX_SECURITY
*)NULL
;
1552 cacheentry
->mode
= mode
& 07777;
1554 cacheentry
->inh_fileid
= const_cpu_to_le32(0);
1555 cacheentry
->inh_dirid
= const_cpu_to_le32(0);
1556 cacheentry
->valid
= 1;
1557 pcache
->head
.p_writes
++;
1560 /* create the first cache block */
1561 pcache
= create_caches(scx
, securindex
);
1563 if (index1
> pcache
->head
.last
) {
1564 resize_cache(scx
, securindex
);
1565 pcache
= *scx
->pseccache
;
1568 /* allocate block, if cache table was allocated */
1569 if (pcache
&& (index1
<= pcache
->head
.last
)) {
1570 cacheblock
= (struct CACHED_PERMISSIONS
*)
1571 malloc(sizeof(struct CACHED_PERMISSIONS
)
1572 << CACHE_PERMISSIONS_BITS
);
1573 pcache
->cachetable
[index1
] = cacheblock
;
1574 for (i
=0; i
<(1 << CACHE_PERMISSIONS_BITS
); i
++)
1575 cacheblock
[i
].valid
= 0;
1576 cacheentry
= &cacheblock
[index2
];
1578 cacheentry
->uid
= uid
;
1579 cacheentry
->gid
= gid
;
1582 pxsize
= sizeof(struct POSIX_SECURITY
)
1583 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1584 pxcached
= (struct POSIX_SECURITY
*)malloc(pxsize
);
1586 memcpy(pxcached
, pxdesc
, pxsize
);
1587 cacheentry
->pxdesc
= pxcached
;
1589 cacheentry
->valid
= 0;
1590 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1592 cacheentry
->mode
= pxdesc
->mode
& 07777;
1594 cacheentry
->pxdesc
= (struct POSIX_SECURITY
*)NULL
;
1596 cacheentry
->mode
= mode
& 07777;
1598 cacheentry
->inh_fileid
= const_cpu_to_le32(0);
1599 cacheentry
->inh_dirid
= const_cpu_to_le32(0);
1600 cacheentry
->valid
= 1;
1601 pcache
->head
.p_writes
++;
1604 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1607 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1608 #if CACHE_LEGACY_SIZE
1609 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
1610 struct CACHED_PERMISSIONS_LEGACY wanted
;
1611 struct CACHED_PERMISSIONS_LEGACY
*legacy
;
1613 wanted
.perm
.uid
= uid
;
1614 wanted
.perm
.gid
= gid
;
1616 wanted
.perm
.mode
= pxdesc
->mode
& 07777;
1617 wanted
.perm
.inh_fileid
= const_cpu_to_le32(0);
1618 wanted
.perm
.inh_dirid
= const_cpu_to_le32(0);
1619 wanted
.mft_no
= ni
->mft_no
;
1620 wanted
.variable
= (void*)pxdesc
;
1621 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
1622 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1624 wanted
.perm
.mode
= mode
& 07777;
1625 wanted
.perm
.inh_fileid
= const_cpu_to_le32(0);
1626 wanted
.perm
.inh_dirid
= const_cpu_to_le32(0);
1627 wanted
.mft_no
= ni
->mft_no
;
1628 wanted
.variable
= (void*)NULL
;
1631 legacy
= (struct CACHED_PERMISSIONS_LEGACY
*)ntfs_enter_cache(
1632 scx
->vol
->legacy_cache
, GENERIC(&wanted
),
1633 (cache_compare
)leg_compare
);
1635 cacheentry
= &legacy
->perm
;
1638 * give direct access to the cached pxdesc
1639 * in the permissions structure
1641 cacheentry
->pxdesc
= legacy
->variable
;
1647 return (cacheentry
);
1651 * Fetch owner, group and permission of a file, if cached
1653 * Beware : do not use the returned entry after a cache update :
1654 * the cache may be relocated making the returned entry meaningless
1656 * returns the cache entry, or NULL if not available
1659 static struct CACHED_PERMISSIONS
*fetch_cache(struct SECURITY_CONTEXT
*scx
,
1662 struct CACHED_PERMISSIONS
*cacheentry
;
1663 struct PERMISSIONS_CACHE
*pcache
;
1665 unsigned int index1
;
1666 unsigned int index2
;
1668 /* cacheing is only possible if a security_id has been defined */
1669 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1670 if (test_nino_flag(ni
, v3_Extensions
)
1671 && (ni
->security_id
)) {
1672 securindex
= le32_to_cpu(ni
->security_id
);
1673 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1674 index2
= securindex
& ((1 << CACHE_PERMISSIONS_BITS
) - 1);
1675 pcache
= *scx
->pseccache
;
1677 && (pcache
->head
.last
>= index1
)
1678 && pcache
->cachetable
[index1
]) {
1679 cacheentry
= &pcache
->cachetable
[index1
][index2
];
1680 /* reject if entry is not valid */
1681 if (!cacheentry
->valid
)
1682 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1684 pcache
->head
.p_hits
++;
1686 pcache
->head
.p_reads
++;
1689 #if CACHE_LEGACY_SIZE
1691 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1692 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
1693 struct CACHED_PERMISSIONS_LEGACY wanted
;
1694 struct CACHED_PERMISSIONS_LEGACY
*legacy
;
1696 wanted
.mft_no
= ni
->mft_no
;
1697 wanted
.variable
= (void*)NULL
;
1699 legacy
= (struct CACHED_PERMISSIONS_LEGACY
*)ntfs_fetch_cache(
1700 scx
->vol
->legacy_cache
, GENERIC(&wanted
),
1701 (cache_compare
)leg_compare
);
1702 if (legacy
) cacheentry
= &legacy
->perm
;
1707 if (cacheentry
&& !cacheentry
->pxdesc
) {
1708 ntfs_log_error("No Posix descriptor in cache\n");
1709 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1712 return (cacheentry
);
1716 * Retrieve a security attribute from $Secure
1719 static char *retrievesecurityattr(ntfs_volume
*vol
, SII_INDEX_KEY id
)
1734 ntfs_index_context
*xsii
;
1737 securattr
= (char*)NULL
;
1738 ni
= vol
->secure_ni
;
1739 xsii
= vol
->secure_xsii
;
1741 ntfs_index_ctx_reinit(xsii
);
1743 !ntfs_index_lookup((char*)&id
,
1744 sizeof(SII_INDEX_KEY
), xsii
);
1746 psii
= (struct SII
*)xsii
->entry
;
1748 (size_t) le32_to_cpu(psii
->datasize
)
1749 - sizeof(SECURITY_DESCRIPTOR_HEADER
);
1750 /* work around bad alignment problem */
1751 realign
.parts
.dataoffsh
= psii
->dataoffsh
;
1752 realign
.parts
.dataoffsl
= psii
->dataoffsl
;
1753 offs
= le64_to_cpu(realign
.all
)
1754 + sizeof(SECURITY_DESCRIPTOR_HEADER
);
1756 securattr
= (char*)ntfs_malloc(size
);
1758 rdsize
= ntfs_local_read(
1760 securattr
, size
, offs
);
1761 if ((rdsize
!= size
)
1762 || !ntfs_valid_descr(securattr
,
1764 /* error to be logged by caller */
1766 securattr
= (char*)NULL
;
1770 if (errno
!= ENOENT
)
1771 ntfs_log_perror("Inconsistency in index $SII");
1774 ntfs_log_error("Failed to retrieve a security descriptor\n");
1781 * Get the security descriptor associated to a file
1784 * - read the security descriptor attribute (v1.x format)
1785 * - or find the descriptor in $Secure:$SDS (v3.x format)
1787 * in both case, sanity checks are done on the attribute and
1788 * the descriptor can be assumed safe
1790 * The returned descriptor is dynamically allocated and has to be freed
1793 static char *getsecurityattr(ntfs_volume
*vol
, ntfs_inode
*ni
)
1795 SII_INDEX_KEY securid
;
1800 * Warning : in some situations, after fixing by chkdsk,
1801 * v3_Extensions are marked present (long standard informations)
1802 * with a default security descriptor inserted in an
1805 if (test_nino_flag(ni
, v3_Extensions
)
1806 && vol
->secure_ni
&& ni
->security_id
) {
1807 /* get v3.x descriptor in $Secure */
1808 securid
.security_id
= ni
->security_id
;
1809 securattr
= retrievesecurityattr(vol
,securid
);
1811 ntfs_log_error("Bad security descriptor for 0x%lx\n",
1812 (long)le32_to_cpu(ni
->security_id
));
1814 /* get v1.x security attribute */
1816 securattr
= ntfs_attr_readall(ni
, AT_SECURITY_DESCRIPTOR
,
1817 AT_UNNAMED
, 0, &readallsz
);
1818 if (securattr
&& !ntfs_valid_descr(securattr
, readallsz
)) {
1819 ntfs_log_error("Bad security descriptor for inode %lld\n",
1820 (long long)ni
->mft_no
);
1822 securattr
= (char*)NULL
;
1827 * in some situations, there is no security
1828 * descriptor, and chkdsk does not detect or fix
1829 * anything. This could be a normal situation.
1830 * When this happens, simulate a descriptor with
1831 * minimum rights, so that a real descriptor can
1832 * be created by chown or chmod
1834 ntfs_log_error("No security descriptor found for inode %lld\n",
1835 (long long)ni
->mft_no
);
1836 securattr
= ntfs_build_descr(0, 0, adminsid
, adminsid
);
1844 * Determine which access types to a file are allowed
1845 * according to the relation of current process to the file
1847 * Do not call if default_permissions is set
1850 static int access_check_posix(struct SECURITY_CONTEXT
*scx
,
1851 struct POSIX_SECURITY
*pxdesc
, mode_t request
,
1852 uid_t uid
, gid_t gid
)
1854 struct POSIX_ACE
*pxace
;
1863 perms
= pxdesc
->mode
;
1864 /* owner and root access */
1865 if (!scx
->uid
|| (uid
== scx
->uid
)) {
1867 /* root access if owner or other execution */
1871 /* root access if some group execution */
1874 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1875 pxace
= &pxdesc
->acl
.ace
[i
];
1876 switch (pxace
->tag
) {
1877 case POSIX_ACL_USER_OBJ
:
1878 case POSIX_ACL_GROUP_OBJ
:
1879 case POSIX_ACL_GROUP
:
1880 groupperms
|= pxace
->perms
;
1882 case POSIX_ACL_MASK
:
1883 mask
= pxace
->perms
& 7;
1889 perms
= (groupperms
& mask
& 1) | 6;
1895 * analyze designated users, get mask
1896 * and identify whether we need to check
1897 * the group memberships. The groups are
1898 * not needed when all groups have the
1899 * same permissions as other for the
1906 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1907 pxace
= &pxdesc
->acl
.ace
[i
];
1908 switch (pxace
->tag
) {
1909 case POSIX_ACL_USER
:
1910 if ((uid_t
)pxace
->id
== scx
->uid
)
1911 userperms
= pxace
->perms
;
1913 case POSIX_ACL_MASK
:
1914 mask
= pxace
->perms
& 7;
1916 case POSIX_ACL_GROUP_OBJ
:
1917 case POSIX_ACL_GROUP
:
1918 if (((pxace
->perms
& mask
) ^ perms
)
1919 & (request
>> 6) & 7)
1926 /* designated users */
1928 perms
= (perms
& 07000) + (userperms
& mask
);
1929 else if (!needgroups
)
1933 if (!(~(perms
>> 3) & request
& mask
)
1934 && ((gid
== scx
->gid
)
1935 || groupmember(scx
, scx
->uid
, gid
)))
1941 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1942 pxace
= &pxdesc
->acl
.ace
[i
];
1943 if ((pxace
->tag
== POSIX_ACL_GROUP
)
1944 && groupmember(scx
, uid
, pxace
->id
)) {
1945 if (!(~pxace
->perms
& request
& mask
))
1946 groupperms
= pxace
->perms
;
1950 if (groupperms
>= 0)
1951 perms
= (perms
& 07000) + (groupperms
& mask
);
1964 * Get permissions to access a file
1965 * Takes into account the relation of user to file (owner, group, ...)
1966 * Do no use as mode of the file
1967 * Do no call if default_permissions is set
1969 * returns -1 if there is a problem
1972 static int ntfs_get_perm(struct SECURITY_CONTEXT
*scx
,
1973 ntfs_inode
* ni
, mode_t request
)
1975 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
1976 const struct CACHED_PERMISSIONS
*cached
;
1978 const SID
*usid
; /* owner of file/directory */
1979 const SID
*gsid
; /* group of file/directory */
1984 struct POSIX_SECURITY
*pxdesc
;
1986 if (!scx
->mapping
[MAPUSERS
])
1989 /* check whether available in cache */
1990 cached
= fetch_cache(scx
,ni
);
1994 perm
= access_check_posix(scx
,cached
->pxdesc
,request
,uid
,gid
);
1996 perm
= 0; /* default to no permission */
1997 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
1998 != const_cpu_to_le16(0);
1999 securattr
= getsecurityattr(scx
->vol
, ni
);
2001 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2003 gsid
= (const SID
*)&
2004 securattr
[le32_to_cpu(phead
->group
)];
2005 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2007 usid
= ntfs_acl_owner(securattr
);
2008 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2011 perm
= pxdesc
->mode
& 07777;
2014 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2016 usid
= (const SID
*)&
2017 securattr
[le32_to_cpu(phead
->owner
)];
2018 pxdesc
= ntfs_build_permissions_posix(scx
,securattr
,
2021 perm
= pxdesc
->mode
& 07777;
2024 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2025 uid
= find_tenant(scx
, securattr
);
2029 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2032 * Create a security id if there were none
2033 * and upgrade option is selected
2035 if (!test_nino_flag(ni
, v3_Extensions
)
2037 && (scx
->vol
->secure_flags
2038 & (1 << SECURITY_ADDSECURIDS
))) {
2039 upgrade_secur_desc(scx
->vol
,
2042 * fetch owner and group for cacheing
2043 * if there is a securid
2046 if (test_nino_flag(ni
, v3_Extensions
)
2048 enter_cache(scx
, ni
, uid
,
2052 perm
= access_check_posix(scx
,pxdesc
,request
,uid
,gid
);
2068 * returns size or -errno if there is a problem
2069 * if size was too small, no copy is done and errno is not set,
2070 * the caller is expected to issue a new call
2073 int ntfs_get_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2074 const char *name
, char *value
, size_t size
)
2076 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2077 struct POSIX_SECURITY
*pxdesc
;
2078 const struct CACHED_PERMISSIONS
*cached
;
2080 const SID
*usid
; /* owner of file/directory */
2081 const SID
*gsid
; /* group of file/directory */
2088 outsize
= 0; /* default to error */
2089 if (!scx
->mapping
[MAPUSERS
])
2092 /* check whether available in cache */
2093 cached
= fetch_cache(scx
,ni
);
2095 pxdesc
= cached
->pxdesc
;
2097 securattr
= getsecurityattr(scx
->vol
, ni
);
2098 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2099 != const_cpu_to_le16(0);
2102 (const SECURITY_DESCRIPTOR_RELATIVE
*)
2104 gsid
= (const SID
*)&
2105 securattr
[le32_to_cpu(phead
->group
)];
2107 usid
= ntfs_acl_owner(securattr
);
2109 usid
= (const SID
*)&
2110 securattr
[le32_to_cpu(phead
->owner
)];
2112 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2116 * fetch owner and group for cacheing
2119 perm
= pxdesc
->mode
& 07777;
2121 * Create a security id if there were none
2122 * and upgrade option is selected
2124 if (!test_nino_flag(ni
, v3_Extensions
)
2125 && (scx
->vol
->secure_flags
2126 & (1 << SECURITY_ADDSECURIDS
))) {
2127 upgrade_secur_desc(scx
->vol
,
2131 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2133 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2134 uid
= find_tenant(scx
,
2139 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2141 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2142 if (pxdesc
->tagsset
& POSIX_ACL_EXTENSIONS
)
2143 enter_cache(scx
, ni
, uid
,
2148 pxdesc
= (struct POSIX_SECURITY
*)NULL
;
2152 if (ntfs_valid_posix(pxdesc
)) {
2153 if (!strcmp(name
,"system.posix_acl_default")) {
2155 & MFT_RECORD_IS_DIRECTORY
)
2156 outsize
= sizeof(struct POSIX_ACL
)
2157 + pxdesc
->defcnt
*sizeof(struct POSIX_ACE
);
2160 * getting default ACL from plain file :
2161 * return EACCES if size > 0 as
2162 * indicated in the man, but return ok
2163 * if size == 0, so that ls does not
2170 outsize
= sizeof(struct POSIX_ACL
);
2172 if (outsize
&& (outsize
<= size
)) {
2173 memcpy(value
,&pxdesc
->acl
,sizeof(struct POSIX_ACL
));
2174 memcpy(&value
[sizeof(struct POSIX_ACL
)],
2175 &pxdesc
->acl
.ace
[pxdesc
->firstdef
],
2176 outsize
-sizeof(struct POSIX_ACL
));
2179 outsize
= sizeof(struct POSIX_ACL
)
2180 + pxdesc
->acccnt
*sizeof(struct POSIX_ACE
);
2181 if (outsize
<= size
)
2182 memcpy(value
,&pxdesc
->acl
,outsize
);
2187 ntfs_log_error("Invalid Posix ACL built\n");
2194 return (outsize
? (int)outsize
: -errno
);
2197 #else /* POSIXACLS */
2201 * Get permissions to access a file
2202 * Takes into account the relation of user to file (owner, group, ...)
2203 * Do no use as mode of the file
2205 * returns -1 if there is a problem
2208 static int ntfs_get_perm(struct SECURITY_CONTEXT
*scx
,
2209 ntfs_inode
*ni
, mode_t request
)
2211 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2212 const struct CACHED_PERMISSIONS
*cached
;
2214 const SID
*usid
; /* owner of file/directory */
2215 const SID
*gsid
; /* group of file/directory */
2221 if (!scx
->mapping
[MAPUSERS
] || (!scx
->uid
&& !(request
& S_IEXEC
)))
2224 /* check whether available in cache */
2225 cached
= fetch_cache(scx
,ni
);
2227 perm
= cached
->mode
;
2231 perm
= 0; /* default to no permission */
2232 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2233 != const_cpu_to_le16(0);
2234 securattr
= getsecurityattr(scx
->vol
, ni
);
2236 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2238 gsid
= (const SID
*)&
2239 securattr
[le32_to_cpu(phead
->group
)];
2240 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2242 usid
= ntfs_acl_owner(securattr
);
2243 perm
= ntfs_build_permissions(securattr
,
2245 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2247 usid
= (const SID
*)&
2248 securattr
[le32_to_cpu(phead
->owner
)];
2249 perm
= ntfs_build_permissions(securattr
,
2251 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2252 uid
= find_tenant(scx
, securattr
);
2256 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2259 * Create a security id if there were none
2260 * and upgrade option is selected
2262 if (!test_nino_flag(ni
, v3_Extensions
)
2264 && (scx
->vol
->secure_flags
2265 & (1 << SECURITY_ADDSECURIDS
))) {
2266 upgrade_secur_desc(scx
->vol
,
2269 * fetch owner and group for cacheing
2270 * if there is a securid
2273 if (test_nino_flag(ni
, v3_Extensions
)
2275 enter_cache(scx
, ni
, uid
,
2286 /* root access and execution */
2292 if (uid
== scx
->uid
)
2296 * avoid checking group membership
2297 * when the requested perms for group
2298 * are the same as perms for other
2300 if ((gid
== scx
->gid
)
2301 || ((((perm
>> 3) ^ perm
)
2302 & (request
>> 6) & 7)
2303 && groupmember(scx
, scx
->uid
, gid
)))
2312 #endif /* POSIXACLS */
2317 * Returns size or -errno if there is a problem
2318 * if size was too small, no copy is done and errno is not set,
2319 * the caller is expected to issue a new call
2322 int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2323 char *value
, size_t size
)
2328 outsize
= 0; /* default to no data and no error */
2329 securattr
= getsecurityattr(scx
->vol
, ni
);
2331 outsize
= ntfs_attr_size(securattr
);
2332 if (outsize
<= size
) {
2333 memcpy(value
,securattr
,outsize
);
2337 return (outsize
? (int)outsize
: -errno
);
2341 * Get owner, group and permissions in an stat structure
2342 * returns permissions, or -1 if there is a problem
2345 int ntfs_get_owner_mode(struct SECURITY_CONTEXT
*scx
,
2346 ntfs_inode
* ni
, struct stat
*stbuf
)
2348 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2350 const SID
*usid
; /* owner of file/directory */
2351 const SID
*gsid
; /* group of file/directory */
2352 const struct CACHED_PERMISSIONS
*cached
;
2356 struct POSIX_SECURITY
*pxdesc
;
2359 if (!scx
->mapping
[MAPUSERS
])
2362 /* check whether available in cache */
2363 cached
= fetch_cache(scx
,ni
);
2365 perm
= cached
->mode
;
2366 stbuf
->st_uid
= cached
->uid
;
2367 stbuf
->st_gid
= cached
->gid
;
2368 stbuf
->st_mode
= (stbuf
->st_mode
& ~07777) + perm
;
2370 perm
= -1; /* default to error */
2371 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2372 != const_cpu_to_le16(0);
2373 securattr
= getsecurityattr(scx
->vol
, ni
);
2376 (const SECURITY_DESCRIPTOR_RELATIVE
*)
2378 gsid
= (const SID
*)&
2379 securattr
[le32_to_cpu(phead
->group
)];
2381 usid
= ntfs_acl_owner(securattr
);
2383 usid
= (const SID
*)&
2384 securattr
[le32_to_cpu(phead
->owner
)];
2387 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
, securattr
,
2390 perm
= pxdesc
->mode
& 07777;
2394 perm
= ntfs_build_permissions(securattr
,
2398 * fetch owner and group for cacheing
2402 * Create a security id if there were none
2403 * and upgrade option is selected
2405 if (!test_nino_flag(ni
, v3_Extensions
)
2406 && (scx
->vol
->secure_flags
2407 & (1 << SECURITY_ADDSECURIDS
))) {
2408 upgrade_secur_desc(scx
->vol
,
2412 stbuf
->st_uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2414 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2421 stbuf
->st_uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2423 stbuf
->st_gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2425 (stbuf
->st_mode
& ~07777) + perm
;
2427 enter_cache(scx
, ni
, stbuf
->st_uid
,
2428 stbuf
->st_gid
, pxdesc
);
2431 enter_cache(scx
, ni
, stbuf
->st_uid
,
2432 stbuf
->st_gid
, perm
);
2445 * Get the base for a Posix inheritance and
2446 * build an inherited Posix descriptor
2449 static struct POSIX_SECURITY
*inherit_posix(struct SECURITY_CONTEXT
*scx
,
2450 ntfs_inode
*dir_ni
, mode_t mode
, BOOL isdir
)
2452 const struct CACHED_PERMISSIONS
*cached
;
2453 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2454 struct POSIX_SECURITY
*pxdesc
;
2455 struct POSIX_SECURITY
*pydesc
;
2462 pydesc
= (struct POSIX_SECURITY
*)NULL
;
2463 /* check whether parent directory is available in cache */
2464 cached
= fetch_cache(scx
,dir_ni
);
2468 pxdesc
= cached
->pxdesc
;
2470 pydesc
= ntfs_build_inherited_posix(pxdesc
,mode
,
2474 securattr
= getsecurityattr(scx
->vol
, dir_ni
);
2476 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2478 gsid
= (const SID
*)&
2479 securattr
[le32_to_cpu(phead
->group
)];
2480 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2482 usid
= ntfs_acl_owner(securattr
);
2483 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2485 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2487 usid
= (const SID
*)&
2488 securattr
[le32_to_cpu(phead
->owner
)];
2489 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2491 if (pxdesc
&& ntfs_same_sid(usid
, adminsid
)) {
2492 uid
= find_tenant(scx
, securattr
);
2494 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2498 * Create a security id if there were none
2499 * and upgrade option is selected
2501 if (!test_nino_flag(dir_ni
, v3_Extensions
)
2502 && (scx
->vol
->secure_flags
2503 & (1 << SECURITY_ADDSECURIDS
))) {
2504 upgrade_secur_desc(scx
->vol
,
2507 * fetch owner and group for cacheing
2508 * if there is a securid
2511 if (test_nino_flag(dir_ni
, v3_Extensions
)) {
2512 enter_cache(scx
, dir_ni
, uid
,
2515 pydesc
= ntfs_build_inherited_posix(pxdesc
,
2516 mode
, scx
->umask
, isdir
);
2526 * Allocate a security_id for a file being created
2528 * Returns zero if not possible (NTFS v3.x required)
2531 le32
ntfs_alloc_securid(struct SECURITY_CONTEXT
*scx
,
2532 uid_t uid
, gid_t gid
, ntfs_inode
*dir_ni
,
2533 mode_t mode
, BOOL isdir
)
2535 #if !FORCE_FORMAT_v1x
2536 const struct CACHED_SECURID
*cached
;
2537 struct CACHED_SECURID wanted
;
2538 struct POSIX_SECURITY
*pxdesc
;
2548 securid
= const_cpu_to_le32(0);
2550 #if !FORCE_FORMAT_v1x
2552 pxdesc
= inherit_posix(scx
, dir_ni
, mode
, isdir
);
2554 /* check whether target securid is known in cache */
2558 wanted
.dmode
= pxdesc
->mode
& mode
& 07777;
2559 if (isdir
) wanted
.dmode
|= 0x10000;
2560 wanted
.variable
= (void*)pxdesc
;
2561 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
2562 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2563 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2564 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2565 (cache_compare
)compare
);
2566 /* quite simple, if we are lucky */
2568 securid
= cached
->securid
;
2570 /* not in cache : make sure we can create ids */
2572 if (!cached
&& (scx
->vol
->major_ver
>= 3)) {
2573 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2574 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2575 if (!usid
|| !gsid
) {
2576 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2577 (int)uid
, (int)gid
);
2578 usid
= gsid
= adminsid
;
2580 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2583 newattrsz
= ntfs_attr_size(newattr
);
2584 securid
= setsecurityattr(scx
->vol
,
2585 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
2588 /* update cache, for subsequent use */
2589 wanted
.securid
= securid
;
2590 ntfs_enter_cache(scx
->vol
->securid_cache
,
2592 (cache_compare
)compare
);
2597 * could not build new security attribute
2598 * errno set by ntfs_build_descr()
2609 * Apply Posix inheritance to a newly created file
2610 * (for NTFS 1.x only : no securid)
2613 int ntfs_set_inherited_posix(struct SECURITY_CONTEXT
*scx
,
2614 ntfs_inode
*ni
, uid_t uid
, gid_t gid
,
2615 ntfs_inode
*dir_ni
, mode_t mode
)
2617 struct POSIX_SECURITY
*pxdesc
;
2627 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2628 pxdesc
= inherit_posix(scx
, dir_ni
, mode
, isdir
);
2630 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2631 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2632 if (!usid
|| !gsid
) {
2633 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2634 (int)uid
, (int)gid
);
2635 usid
= gsid
= adminsid
;
2637 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2640 /* Adjust Windows read-only flag */
2641 res
= update_secur_descr(scx
->vol
, newattr
, ni
);
2644 ni
->flags
&= ~FILE_ATTR_READONLY
;
2646 ni
->flags
|= FILE_ATTR_READONLY
;
2648 #if CACHE_LEGACY_SIZE
2649 /* also invalidate legacy cache */
2650 if (isdir
&& !ni
->security_id
) {
2651 struct CACHED_PERMISSIONS_LEGACY legacy
;
2653 legacy
.mft_no
= ni
->mft_no
;
2654 legacy
.variable
= pxdesc
;
2655 legacy
.varsize
= sizeof(struct POSIX_SECURITY
)
2656 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2657 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
2659 (cache_compare
)leg_compare
,0);
2666 * could not build new security attribute
2667 * errno set by ntfs_build_descr()
2676 le32
ntfs_alloc_securid(struct SECURITY_CONTEXT
*scx
,
2677 uid_t uid
, gid_t gid
, mode_t mode
, BOOL isdir
)
2679 #if !FORCE_FORMAT_v1x
2680 const struct CACHED_SECURID
*cached
;
2681 struct CACHED_SECURID wanted
;
2691 securid
= const_cpu_to_le32(0);
2693 #if !FORCE_FORMAT_v1x
2694 /* check whether target securid is known in cache */
2698 wanted
.dmode
= mode
& 07777;
2699 if (isdir
) wanted
.dmode
|= 0x10000;
2700 wanted
.variable
= (void*)NULL
;
2702 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2703 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2704 (cache_compare
)compare
);
2705 /* quite simple, if we are lucky */
2707 securid
= cached
->securid
;
2709 /* not in cache : make sure we can create ids */
2711 if (!cached
&& (scx
->vol
->major_ver
>= 3)) {
2712 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2713 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2714 if (!usid
|| !gsid
) {
2715 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2716 (int)uid
, (int)gid
);
2717 usid
= gsid
= adminsid
;
2719 newattr
= ntfs_build_descr(mode
, isdir
, usid
, gsid
);
2721 newattrsz
= ntfs_attr_size(newattr
);
2722 securid
= setsecurityattr(scx
->vol
,
2723 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
2726 /* update cache, for subsequent use */
2727 wanted
.securid
= securid
;
2728 ntfs_enter_cache(scx
->vol
->securid_cache
,
2730 (cache_compare
)compare
);
2735 * could not build new security attribute
2736 * errno set by ntfs_build_descr()
2747 * Update ownership and mode of a file, reusing an existing
2748 * security descriptor when possible
2750 * Returns zero if successful
2754 int ntfs_set_owner_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2755 uid_t uid
, gid_t gid
, mode_t mode
,
2756 struct POSIX_SECURITY
*pxdesc
)
2758 int ntfs_set_owner_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2759 uid_t uid
, gid_t gid
, mode_t mode
)
2763 const struct CACHED_SECURID
*cached
;
2764 struct CACHED_SECURID wanted
;
2774 /* check whether target securid is known in cache */
2776 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2779 wanted
.dmode
= mode
& 07777;
2780 if (isdir
) wanted
.dmode
|= 0x10000;
2782 wanted
.variable
= (void*)pxdesc
;
2784 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
2785 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2789 wanted
.variable
= (void*)NULL
;
2792 if (test_nino_flag(ni
, v3_Extensions
)) {
2793 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2794 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2795 (cache_compare
)compare
);
2796 /* quite simple, if we are lucky */
2798 ni
->security_id
= cached
->securid
;
2801 } else cached
= (struct CACHED_SECURID
*)NULL
;
2805 * Do not use usid and gsid from former attributes,
2806 * but recompute them to get repeatable results
2807 * which can be kept in cache.
2809 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2810 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2811 if (!usid
|| !gsid
) {
2812 ntfs_log_error("File made owned by an unmapped user/group %d/%d\n",
2814 usid
= gsid
= adminsid
;
2818 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2821 newattr
= ntfs_build_descr(mode
,
2824 newattr
= ntfs_build_descr(mode
,
2828 res
= update_secur_descr(scx
->vol
, newattr
, ni
);
2830 /* adjust Windows read-only flag */
2832 ni
->flags
&= ~FILE_ATTR_READONLY
;
2834 ni
->flags
|= FILE_ATTR_READONLY
;
2835 /* update cache, for subsequent use */
2836 if (test_nino_flag(ni
, v3_Extensions
)) {
2837 wanted
.securid
= ni
->security_id
;
2838 ntfs_enter_cache(scx
->vol
->securid_cache
,
2840 (cache_compare
)compare
);
2842 #if CACHE_LEGACY_SIZE
2843 /* also invalidate legacy cache */
2844 if (isdir
&& !ni
->security_id
) {
2845 struct CACHED_PERMISSIONS_LEGACY legacy
;
2847 legacy
.mft_no
= ni
->mft_no
;
2849 legacy
.variable
= wanted
.variable
;
2850 legacy
.varsize
= wanted
.varsize
;
2852 legacy
.variable
= (void*)NULL
;
2855 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
2857 (cache_compare
)leg_compare
,0);
2864 * could not build new security attribute
2865 * errno set by ntfs_build_descr()
2874 * Check whether user has ownership rights on a file
2876 * Returns TRUE if allowed
2877 * if not, errno tells why
2880 BOOL
ntfs_allowed_as_owner(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
)
2882 const struct CACHED_PERMISSIONS
*cached
;
2890 processuid
= scx
->uid
;
2891 /* TODO : use CAP_FOWNER process capability */
2893 * Always allow for root
2894 * Also always allow if no mapping has been defined
2896 if (!scx
->mapping
[MAPUSERS
] || !processuid
)
2899 gotowner
= FALSE
; /* default */
2900 /* get the owner, either from cache or from old attribute */
2901 cached
= fetch_cache(scx
, ni
);
2906 oldattr
= getsecurityattr(scx
->vol
, ni
);
2909 usid
= ntfs_acl_owner(oldattr
);
2911 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2913 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2915 usid
= (const SID
*)&oldattr
2916 [le32_to_cpu(phead
->owner
)];
2918 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],
2926 /* TODO : use CAP_FOWNER process capability */
2927 if (!processuid
|| (processuid
== uid
))
2936 #ifdef HAVE_SETXATTR /* extended attributes interface required */
2941 * Set a new access or default Posix ACL to a file
2942 * (or remove ACL if no input data)
2943 * Validity of input data is checked after merging
2945 * Returns 0, or -1 if there is a problem which errno describes
2948 int ntfs_set_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2949 const char *name
, const char *value
, size_t size
,
2952 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2953 const struct CACHED_PERMISSIONS
*cached
;
2966 struct POSIX_SECURITY
*oldpxdesc
;
2967 struct POSIX_SECURITY
*newpxdesc
;
2969 /* get the current pxsec, either from cache or from old attribute */
2971 deflt
= !strcmp(name
,"system.posix_acl_default");
2973 count
= (size
- sizeof(struct POSIX_ACL
)) / sizeof(struct POSIX_ACE
);
2976 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2977 newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
2978 if (!deflt
|| isdir
|| !size
) {
2979 cached
= fetch_cache(scx
, ni
);
2983 oldpxdesc
= cached
->pxdesc
;
2985 mode
= oldpxdesc
->mode
;
2986 newpxdesc
= ntfs_replace_acl(oldpxdesc
,
2987 (const struct POSIX_ACL
*)value
,count
,deflt
);
2990 oldattr
= getsecurityattr(scx
->vol
, ni
);
2992 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
2994 usid
= ntfs_acl_owner(oldattr
);
2996 usid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->owner
)];
2998 gsid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->group
)];
2999 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3000 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3001 oldpxdesc
= ntfs_build_permissions_posix(scx
->mapping
,
3002 oldattr
, usid
, gsid
, isdir
);
3005 exist
= oldpxdesc
->defcnt
> 0;
3007 exist
= oldpxdesc
->acccnt
> 3;
3008 if ((exist
&& (flags
& XATTR_CREATE
))
3009 || (!exist
&& (flags
& XATTR_REPLACE
))) {
3010 errno
= (exist
? EEXIST
: ENODATA
);
3012 mode
= oldpxdesc
->mode
;
3013 newpxdesc
= ntfs_replace_acl(oldpxdesc
,
3014 (const struct POSIX_ACL
*)value
,count
,deflt
);
3025 processuid
= scx
->uid
;
3026 /* TODO : use CAP_FOWNER process capability */
3027 if (!processuid
|| (uid
== processuid
)) {
3029 * clear setgid if file group does
3030 * not match process group
3032 if (processuid
&& (gid
!= scx
->gid
)
3033 && !groupmember(scx
, scx
->uid
, gid
)) {
3034 newpxdesc
->mode
&= ~S_ISGID
;
3036 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3037 newpxdesc
->mode
, newpxdesc
);
3042 return (res
? -1 : 0);
3046 * Remove a default Posix ACL from a file
3048 * Returns 0, or -1 if there is a problem which errno describes
3051 int ntfs_remove_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3054 return (ntfs_set_posix_acl(scx
, ni
, name
,
3055 (const char*)NULL
, 0, 0));
3061 * Set a new NTFS ACL to a file
3063 * Returns 0, or -1 if there is a problem
3066 int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3067 const char *value
, size_t size
, int flags
)
3074 && !(flags
& XATTR_CREATE
)
3075 && ntfs_valid_descr(value
,size
)
3076 && (ntfs_attr_size(value
) == size
)) {
3077 /* need copying in order to write */
3078 attr
= (char*)ntfs_malloc(size
);
3080 memcpy(attr
,value
,size
);
3081 res
= update_secur_descr(scx
->vol
, attr
, ni
);
3083 * No need to invalidate standard caches :
3084 * the relation between a securid and
3085 * the associated protection is unchanged,
3086 * only the relation between a file and
3087 * its securid and protection is changed.
3089 #if CACHE_LEGACY_SIZE
3091 * we must however invalidate the legacy
3092 * cache, which is based on inode numbers.
3093 * For safety, invalidate even if updating
3096 if ((ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3097 && !ni
->security_id
) {
3098 struct CACHED_PERMISSIONS_LEGACY legacy
;
3100 legacy
.mft_no
= ni
->mft_no
;
3101 legacy
.variable
= (char*)NULL
;
3103 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
3105 (cache_compare
)leg_compare
,0);
3113 return (res
? -1 : 0);
3116 #endif /* HAVE_SETXATTR */
3119 * Set new permissions to a file
3120 * Checks user mapping has been defined before request for setting
3122 * rejected if request is not originated by owner or root
3124 * returns 0 on success
3125 * -1 on failure, with errno = EIO
3128 int ntfs_set_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
, mode_t mode
)
3130 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3131 const struct CACHED_PERMISSIONS
*cached
;
3142 const struct POSIX_SECURITY
*oldpxdesc
;
3143 struct POSIX_SECURITY
*newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3146 /* get the current owner, either from cache or from old attribute */
3148 cached
= fetch_cache(scx
, ni
);
3153 oldpxdesc
= cached
->pxdesc
;
3155 /* must copy before merging */
3156 pxsize
= sizeof(struct POSIX_SECURITY
)
3157 + (oldpxdesc
->acccnt
+ oldpxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
3158 newpxdesc
= (struct POSIX_SECURITY
*)malloc(pxsize
);
3160 memcpy(newpxdesc
, oldpxdesc
, pxsize
);
3161 if (ntfs_merge_mode_posix(newpxdesc
, mode
))
3166 newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3169 oldattr
= getsecurityattr(scx
->vol
, ni
);
3171 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
3173 usid
= ntfs_acl_owner(oldattr
);
3175 usid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->owner
)];
3177 gsid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->group
)];
3178 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3179 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3181 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
3182 newpxdesc
= ntfs_build_permissions_posix(scx
->mapping
,
3183 oldattr
, usid
, gsid
, isdir
);
3184 if (!newpxdesc
|| ntfs_merge_mode_posix(newpxdesc
, mode
))
3193 processuid
= scx
->uid
;
3194 /* TODO : use CAP_FOWNER process capability */
3195 if (!processuid
|| (uid
== processuid
)) {
3197 * clear setgid if file group does
3198 * not match process group
3200 if (processuid
&& (gid
!= scx
->gid
)
3201 && !groupmember(scx
, scx
->uid
, gid
))
3205 newpxdesc
->mode
= mode
;
3206 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3209 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3212 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3216 res
= -1; /* neither owner nor root */
3220 * Should not happen : a default descriptor is generated
3221 * by getsecurityattr() when there are none
3223 ntfs_log_error("File has no security descriptor\n");
3228 if (newpxdesc
) free(newpxdesc
);
3230 return (res
? -1 : 0);
3234 * Create a default security descriptor for files whose descriptor
3235 * cannot be inherited
3238 int ntfs_sd_add_everyone(ntfs_inode
*ni
)
3240 /* JPA SECURITY_DESCRIPTOR_ATTR *sd; */
3241 SECURITY_DESCRIPTOR_RELATIVE
*sd
;
3243 ACCESS_ALLOWED_ACE
*ace
;
3247 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
3249 * Calculate security descriptor length. We have 2 sub-authorities in
3250 * owner and group SIDs, but structure SID contain only one, so add
3251 * 4 bytes to every SID.
3253 sd_len
= sizeof(SECURITY_DESCRIPTOR_ATTR
) + 2 * (sizeof(SID
) + 4) +
3254 sizeof(ACL
) + sizeof(ACCESS_ALLOWED_ACE
);
3255 sd
= (SECURITY_DESCRIPTOR_RELATIVE
*)ntfs_calloc(sd_len
);
3259 sd
->revision
= SECURITY_DESCRIPTOR_REVISION
;
3260 sd
->control
= SE_DACL_PRESENT
| SE_SELF_RELATIVE
;
3262 sid
= (SID
*)((u8
*)sd
+ sizeof(SECURITY_DESCRIPTOR_ATTR
));
3263 sid
->revision
= SID_REVISION
;
3264 sid
->sub_authority_count
= 2;
3265 sid
->sub_authority
[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID
);
3266 sid
->sub_authority
[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS
);
3267 sid
->identifier_authority
.value
[5] = 5;
3268 sd
->owner
= cpu_to_le32((u8
*)sid
- (u8
*)sd
);
3270 sid
= (SID
*)((u8
*)sid
+ sizeof(SID
) + 4);
3271 sid
->revision
= SID_REVISION
;
3272 sid
->sub_authority_count
= 2;
3273 sid
->sub_authority
[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID
);
3274 sid
->sub_authority
[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS
);
3275 sid
->identifier_authority
.value
[5] = 5;
3276 sd
->group
= cpu_to_le32((u8
*)sid
- (u8
*)sd
);
3278 acl
= (ACL
*)((u8
*)sid
+ sizeof(SID
) + 4);
3279 acl
->revision
= ACL_REVISION
;
3280 acl
->size
= const_cpu_to_le16(sizeof(ACL
) + sizeof(ACCESS_ALLOWED_ACE
));
3281 acl
->ace_count
= const_cpu_to_le16(1);
3282 sd
->dacl
= cpu_to_le32((u8
*)acl
- (u8
*)sd
);
3284 ace
= (ACCESS_ALLOWED_ACE
*)((u8
*)acl
+ sizeof(ACL
));
3285 ace
->type
= ACCESS_ALLOWED_ACE_TYPE
;
3286 ace
->flags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
;
3287 ace
->size
= const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE
));
3288 ace
->mask
= const_cpu_to_le32(0x1f01ff); /* FIXME */
3289 ace
->sid
.revision
= SID_REVISION
;
3290 ace
->sid
.sub_authority_count
= 1;
3291 ace
->sid
.sub_authority
[0] = const_cpu_to_le32(0);
3292 ace
->sid
.identifier_authority
.value
[5] = 1;
3294 ret
= ntfs_attr_add(ni
, AT_SECURITY_DESCRIPTOR
, AT_UNNAMED
, 0, (u8
*)sd
,
3297 ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR");
3304 * Check whether user can access a file in a specific way
3306 * Returns 1 if access is allowed, including user is root or no
3307 * user mapping defined
3308 * 2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX
3309 * 0 and sets errno if there is a problem or if access
3312 * This is used for Posix ACL and checking creation of DOS file names
3315 int ntfs_allowed_access(struct SECURITY_CONTEXT
*scx
,
3317 int accesstype
) /* access type required (S_Ixxx values) */
3325 * Always allow for root unless execution is requested.
3326 * (was checked by fuse until kernel 2.6.29)
3327 * Also always allow if no mapping has been defined
3329 if (!scx
->mapping
[MAPUSERS
]
3331 && (!(accesstype
& S_IEXEC
)
3332 || (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
))))
3335 perm
= ntfs_get_perm(scx
, ni
, accesstype
);
3338 switch (accesstype
) {
3340 allow
= (perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0;
3343 allow
= (perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0;
3345 case S_IWRITE
+ S_IEXEC
:
3346 allow
= ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3347 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3350 allow
= (perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0;
3352 case S_IREAD
+ S_IEXEC
:
3353 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3354 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3356 case S_IREAD
+ S_IWRITE
:
3357 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3358 && ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0);
3360 case S_IWRITE
+ S_IEXEC
+ S_ISVTX
:
3361 if (perm
& S_ISVTX
) {
3362 if ((ntfs_get_owner_mode(scx
,ni
,&stbuf
) >= 0)
3363 && (stbuf
.st_uid
== scx
->uid
))
3368 allow
= ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3369 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3371 case S_IREAD
+ S_IWRITE
+ S_IEXEC
:
3372 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3373 && ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3374 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3389 #if 0 /* not needed any more */
3392 * Check whether user can access the parent directory
3393 * of a file in a specific way
3395 * Returns true if access is allowed, including user is root and
3396 * no user mapping defined
3398 * Sets errno if there is a problem or if not allowed
3400 * This is used for Posix ACL and checking creation of DOS file names
3403 BOOL
old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT
*scx
,
3404 const char *path
, int accesstype
)
3414 dirpath
= strdup(path
);
3416 /* the root of file system is seen as a parent of itself */
3417 /* is that correct ? */
3418 name
= strrchr(dirpath
, '/');
3420 dir_ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, dirpath
);
3422 allow
= ntfs_allowed_access(scx
,
3423 dir_ni
, accesstype
);
3424 ntfs_inode_close(dir_ni
);
3426 * for an not-owned sticky directory, have to
3427 * check whether file itself is owned
3429 if ((accesstype
== (S_IWRITE
+ S_IEXEC
+ S_ISVTX
))
3431 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
,
3435 allow
= (ntfs_get_owner_mode(scx
,ni
,&stbuf
) >= 0)
3436 && (stbuf
.st_uid
== scx
->uid
);
3437 ntfs_inode_close(ni
);
3443 return (allow
); /* errno is set if not allowed */
3449 * Define a new owner/group to a file
3451 * returns zero if successful
3454 int ntfs_set_owner(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3455 uid_t uid
, gid_t gid
)
3457 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3458 const struct CACHED_PERMISSIONS
*cached
;
3469 struct POSIX_SECURITY
*pxdesc
;
3470 BOOL pxdescbuilt
= FALSE
;
3474 /* get the current owner and mode from cache or security attributes */
3475 oldattr
= (char*)NULL
;
3476 cached
= fetch_cache(scx
,ni
);
3478 fileuid
= cached
->uid
;
3479 filegid
= cached
->gid
;
3480 mode
= cached
->mode
;
3482 pxdesc
= cached
->pxdesc
;
3490 oldattr
= getsecurityattr(scx
->vol
, ni
);
3492 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3493 != const_cpu_to_le16(0);
3494 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
3497 &oldattr
[le32_to_cpu(phead
->group
)];
3499 usid
= ntfs_acl_owner(oldattr
);
3502 &oldattr
[le32_to_cpu(phead
->owner
)];
3505 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
, oldattr
,
3509 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3510 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3511 mode
= perm
= pxdesc
->mode
;
3515 mode
= perm
= ntfs_build_permissions(oldattr
,
3518 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3519 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3528 /* check requested by root */
3529 /* or chgrp requested by owner to an owned group */
3531 || ((((int)uid
< 0) || (uid
== fileuid
))
3532 && ((gid
== scx
->gid
) || groupmember(scx
, scx
->uid
, gid
))
3533 && (fileuid
== scx
->uid
))) {
3534 /* replace by the new usid and gsid */
3535 /* or reuse old gid and sid for cacheing */
3540 /* clear setuid and setgid if owner has changed */
3541 /* unless request originated by root */
3542 if (uid
&& (fileuid
!= uid
))
3545 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3548 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3551 res
= -1; /* neither owner nor root */
3560 * Should not happen : a default descriptor is generated
3561 * by getsecurityattr() when there are none
3563 ntfs_log_error("File has no security descriptor\n");
3567 return (res
? -1 : 0);
3571 * Define new owner/group and mode to a file
3573 * returns zero if successful
3576 int ntfs_set_ownmod(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3577 uid_t uid
, gid_t gid
, const mode_t mode
)
3579 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3580 const struct CACHED_PERMISSIONS
*cached
;
3589 const struct POSIX_SECURITY
*oldpxdesc
;
3590 struct POSIX_SECURITY
*newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3595 /* get the current owner and mode from cache or security attributes */
3596 oldattr
= (char*)NULL
;
3597 cached
= fetch_cache(scx
,ni
);
3599 fileuid
= cached
->uid
;
3600 filegid
= cached
->gid
;
3602 oldpxdesc
= cached
->pxdesc
;
3604 /* must copy before merging */
3605 pxsize
= sizeof(struct POSIX_SECURITY
)
3606 + (oldpxdesc
->acccnt
+ oldpxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
3607 newpxdesc
= (struct POSIX_SECURITY
*)malloc(pxsize
);
3609 memcpy(newpxdesc
, oldpxdesc
, pxsize
);
3610 if (ntfs_merge_mode_posix(newpxdesc
, mode
))
3619 oldattr
= getsecurityattr(scx
->vol
, ni
);
3621 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3622 != const_cpu_to_le16(0);
3623 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
3626 &oldattr
[le32_to_cpu(phead
->group
)];
3628 usid
= ntfs_acl_owner(oldattr
);
3631 &oldattr
[le32_to_cpu(phead
->owner
)];
3634 newpxdesc
= ntfs_build_permissions_posix(scx
->mapping
, oldattr
,
3636 if (!newpxdesc
|| ntfs_merge_mode_posix(newpxdesc
, mode
))
3639 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3640 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3648 /* check requested by root */
3649 /* or chgrp requested by owner to an owned group */
3651 || ((((int)uid
< 0) || (uid
== fileuid
))
3652 && ((gid
== scx
->gid
) || groupmember(scx
, scx
->uid
, gid
))
3653 && (fileuid
== scx
->uid
))) {
3654 /* replace by the new usid and gsid */
3655 /* or reuse old gid and sid for cacheing */
3661 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3664 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3667 res
= -1; /* neither owner nor root */
3672 * Should not happen : a default descriptor is generated
3673 * by getsecurityattr() when there are none
3675 ntfs_log_error("File has no security descriptor\n");
3682 return (res
? -1 : 0);
3686 * Build a security id for a descriptor inherited from
3687 * parent directory the Windows way
3690 static le32
build_inherited_id(struct SECURITY_CONTEXT
*scx
,
3691 const char *parentattr
, BOOL fordir
)
3693 const SECURITY_DESCRIPTOR_RELATIVE
*pphead
;
3702 SECURITY_DESCRIPTOR_RELATIVE
*pnhead
;
3713 parentattrsz
= ntfs_attr_size(parentattr
);
3714 pphead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)parentattr
;
3715 if (scx
->mapping
[MAPUSERS
]) {
3716 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
], scx
->uid
, (SID
*)&defusid
);
3717 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
], scx
->gid
, (SID
*)&defgsid
);
3724 * If there is no user mapping, we have to copy owner
3725 * and group from parent directory.
3726 * Windows never has to do that, because it can always
3727 * rely on a user mapping
3729 offowner
= le32_to_cpu(pphead
->owner
);
3730 usid
= (const SID
*)&parentattr
[offowner
];
3731 offgroup
= le32_to_cpu(pphead
->group
);
3732 gsid
= (const SID
*)&parentattr
[offgroup
];
3735 * new attribute is smaller than parent's
3736 * except for differences in SIDs which appear in
3737 * owner, group and possible grants and denials in
3738 * generic creator-owner and creator-group ACEs.
3739 * For directories, an ACE may be duplicated for
3740 * access and inheritance, so we double the count.
3742 usidsz
= ntfs_sid_size(usid
);
3743 gsidsz
= ntfs_sid_size(gsid
);
3744 newattrsz
= parentattrsz
+ 3*usidsz
+ 3*gsidsz
;
3747 newattr
= (char*)ntfs_malloc(newattrsz
);
3749 pnhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)newattr
;
3750 pnhead
->revision
= SECURITY_DESCRIPTOR_REVISION
;
3751 pnhead
->alignment
= 0;
3752 pnhead
->control
= SE_SELF_RELATIVE
;
3753 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
3755 * locate and inherit DACL
3756 * do not test SE_DACL_PRESENT (wrong for "DR Watson")
3758 pnhead
->dacl
= const_cpu_to_le32(0);
3760 offpacl
= le32_to_cpu(pphead
->dacl
);
3761 ppacl
= (const ACL
*)&parentattr
[offpacl
];
3762 pnacl
= (ACL
*)&newattr
[pos
];
3763 aclsz
= ntfs_inherit_acl(ppacl
, pnacl
, usid
, gsid
, fordir
);
3765 pnhead
->dacl
= cpu_to_le32(pos
);
3767 pnhead
->control
|= SE_DACL_PRESENT
;
3771 * locate and inherit SACL
3773 pnhead
->sacl
= const_cpu_to_le32(0);
3775 offpacl
= le32_to_cpu(pphead
->sacl
);
3776 ppacl
= (const ACL
*)&parentattr
[offpacl
];
3777 pnacl
= (ACL
*)&newattr
[pos
];
3778 aclsz
= ntfs_inherit_acl(ppacl
, pnacl
, usid
, gsid
, fordir
);
3780 pnhead
->sacl
= cpu_to_le32(pos
);
3782 pnhead
->control
|= SE_SACL_PRESENT
;
3786 * inherit or redefine owner
3788 memcpy(&newattr
[pos
],usid
,usidsz
);
3789 pnhead
->owner
= cpu_to_le32(pos
);
3792 * inherit or redefine group
3794 memcpy(&newattr
[pos
],gsid
,gsidsz
);
3795 pnhead
->group
= cpu_to_le32(pos
);
3797 securid
= setsecurityattr(scx
->vol
,
3798 (SECURITY_DESCRIPTOR_RELATIVE
*)newattr
, pos
);
3801 securid
= const_cpu_to_le32(0);
3806 * Get an inherited security id
3808 * For Windows compatibility, the normal initial permission setting
3809 * may be inherited from the parent directory instead of being
3810 * defined by the creation arguments.
3812 * The following creates an inherited id for that purpose.
3814 * Note : the owner and group of parent directory are also
3815 * inherited (which is not the case on Windows) if no user mapping
3818 * Returns the inherited id, or zero if not possible (eg on NTFS 1.x)
3821 le32
ntfs_inherited_id(struct SECURITY_CONTEXT
*scx
,
3822 ntfs_inode
*dir_ni
, BOOL fordir
)
3824 struct CACHED_PERMISSIONS
*cached
;
3828 securid
= const_cpu_to_le32(0);
3829 cached
= (struct CACHED_PERMISSIONS
*)NULL
;
3831 * Try to get inherited id from cache
3833 if (test_nino_flag(dir_ni
, v3_Extensions
)
3834 && dir_ni
->security_id
) {
3835 cached
= fetch_cache(scx
, dir_ni
);
3837 securid
= (fordir
? cached
->inh_dirid
3838 : cached
->inh_fileid
);
3841 * Not cached or not available in cache, compute it all
3842 * Note : if parent directory has no id, it is not cacheable
3845 parentattr
= getsecurityattr(scx
->vol
, dir_ni
);
3847 securid
= build_inherited_id(scx
,
3848 parentattr
, fordir
);
3851 * Store the result into cache for further use
3854 cached
= fetch_cache(scx
, dir_ni
);
3857 cached
->inh_dirid
= securid
;
3859 cached
->inh_fileid
= securid
;
3868 * Link a group to a member of group
3870 * Returns 0 if OK, -1 (and errno set) if error
3873 static int link_single_group(struct MAPPING
*usermapping
, struct passwd
*user
,
3876 struct group
*group
;
3883 group
= getgrgid(gid
);
3884 if (group
&& group
->gr_mem
) {
3885 grcnt
= usermapping
->grcnt
;
3886 groups
= usermapping
->groups
;
3887 grmem
= group
->gr_mem
;
3888 while (*grmem
&& strcmp(user
->pw_name
, *grmem
))
3892 groups
= (gid_t
*)malloc(sizeof(gid_t
));
3894 groups
= (gid_t
*)realloc(groups
,
3895 (grcnt
+1)*sizeof(gid_t
));
3897 groups
[grcnt
++] = gid
;
3903 usermapping
->grcnt
= grcnt
;
3904 usermapping
->groups
= groups
;
3911 * Statically link group to users
3912 * This is based on groups defined in /etc/group and does not take
3913 * the groups dynamically set by setgroups() nor any changes in
3914 * /etc/group into account
3916 * Only mapped groups and root group are linked to mapped users
3918 * Returns 0 if OK, -1 (and errno set) if error
3922 static int link_group_members(struct SECURITY_CONTEXT
*scx
)
3924 struct MAPPING
*usermapping
;
3925 struct MAPPING
*groupmapping
;
3926 struct passwd
*user
;
3930 for (usermapping
=scx
->mapping
[MAPUSERS
]; usermapping
&& !res
;
3931 usermapping
=usermapping
->next
) {
3932 usermapping
->grcnt
= 0;
3933 usermapping
->groups
= (gid_t
*)NULL
;
3934 user
= getpwuid(usermapping
->xid
);
3935 if (user
&& user
->pw_name
) {
3936 for (groupmapping
=scx
->mapping
[MAPGROUPS
];
3937 groupmapping
&& !res
;
3938 groupmapping
=groupmapping
->next
) {
3939 if (link_single_group(usermapping
, user
,
3943 if (!res
&& link_single_group(usermapping
,
3953 * Apply default single user mapping
3954 * returns zero if successful
3957 static int ntfs_do_default_mapping(struct SECURITY_CONTEXT
*scx
,
3960 struct MAPPING
*usermapping
;
3961 struct MAPPING
*groupmapping
;
3967 sidsz
= ntfs_sid_size(usid
);
3968 sid
= (SID
*)ntfs_malloc(sidsz
);
3970 memcpy(sid
,usid
,sidsz
);
3971 usermapping
= (struct MAPPING
*)ntfs_malloc(sizeof(struct MAPPING
));
3973 groupmapping
= (struct MAPPING
*)ntfs_malloc(sizeof(struct MAPPING
));
3975 usermapping
->sid
= sid
;
3976 usermapping
->xid
= scx
->uid
;
3977 usermapping
->next
= (struct MAPPING
*)NULL
;
3978 groupmapping
->sid
= sid
;
3979 groupmapping
->xid
= scx
->uid
;
3980 groupmapping
->next
= (struct MAPPING
*)NULL
;
3981 scx
->mapping
[MAPUSERS
] = usermapping
;
3982 scx
->mapping
[MAPGROUPS
] = groupmapping
;
3992 * Make sure there are no ambiguous mapping
3993 * Ambiguous mapping may lead to undesired configurations and
3994 * we had rather be safe until the consequences are understood
3997 #if 0 /* not activated for now */
3999 static BOOL
check_mapping(const struct MAPPING
*usermapping
,
4000 const struct MAPPING
*groupmapping
)
4002 const struct MAPPING
*mapping1
;
4003 const struct MAPPING
*mapping2
;
4007 for (mapping1
=usermapping
; mapping1
; mapping1
=mapping1
->next
)
4008 for (mapping2
=mapping1
->next
; mapping2
; mapping1
=mapping2
->next
)
4009 if (ntfs_same_sid(mapping1
->sid
,mapping2
->sid
)) {
4010 if (mapping1
->xid
!= mapping2
->xid
)
4013 if (mapping1
->xid
== mapping2
->xid
)
4016 for (mapping1
=groupmapping
; mapping1
; mapping1
=mapping1
->next
)
4017 for (mapping2
=mapping1
->next
; mapping2
; mapping1
=mapping2
->next
)
4018 if (ntfs_same_sid(mapping1
->sid
,mapping2
->sid
)) {
4019 if (mapping1
->xid
!= mapping2
->xid
)
4022 if (mapping1
->xid
== mapping2
->xid
)
4031 * Try and apply default single user mapping
4032 * returns zero if successful
4035 static int ntfs_default_mapping(struct SECURITY_CONTEXT
*scx
)
4037 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4044 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, "/.");
4046 securattr
= getsecurityattr(scx
->vol
, ni
);
4048 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)securattr
;
4049 usid
= (SID
*)&securattr
[le32_to_cpu(phead
->owner
)];
4050 if (ntfs_is_user_sid(usid
))
4051 res
= ntfs_do_default_mapping(scx
,usid
);
4054 ntfs_inode_close(ni
);
4060 * Basic read from a user mapping file on another volume
4063 static int basicread(void *fileid
, char *buf
, size_t size
, off_t offs
__attribute__((unused
)))
4065 return (read(*(int*)fileid
, buf
, size
));
4070 * Read from a user mapping file on current NTFS partition
4073 static int localread(void *fileid
, char *buf
, size_t size
, off_t offs
)
4075 return (ntfs_local_read((ntfs_inode
*)fileid
,
4076 AT_UNNAMED
, 0, buf
, size
, offs
));
4080 * Build the user mapping
4081 * - according to a mapping file if defined (or default present),
4082 * - or try default single user mapping if possible
4084 * The mapping is specific to a mounted device
4085 * No locking done, mounting assumed non multithreaded
4087 * returns zero if mapping is successful
4088 * (failure should not be interpreted as an error)
4091 int ntfs_build_mapping(struct SECURITY_CONTEXT
*scx
, const char *usermap_path
)
4093 struct MAPLIST
*item
;
4094 struct MAPLIST
*firstitem
;
4095 struct MAPPING
*usermapping
;
4096 struct MAPPING
*groupmapping
;
4100 /* be sure not to map anything until done */
4101 scx
->mapping
[MAPUSERS
] = (struct MAPPING
*)NULL
;
4102 scx
->mapping
[MAPGROUPS
] = (struct MAPPING
*)NULL
;
4104 if (!usermap_path
) usermap_path
= MAPPINGFILE
;
4105 if (usermap_path
[0] == '/') {
4106 fd
= open(usermap_path
,O_RDONLY
);
4108 firstitem
= ntfs_read_mapping(basicread
, (void*)&fd
);
4111 firstitem
= (struct MAPLIST
*)NULL
;
4113 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, usermap_path
);
4115 firstitem
= ntfs_read_mapping(localread
, ni
);
4116 ntfs_inode_close(ni
);
4118 firstitem
= (struct MAPLIST
*)NULL
;
4123 usermapping
= ntfs_do_user_mapping(firstitem
);
4124 groupmapping
= ntfs_do_group_mapping(firstitem
);
4125 if (usermapping
&& groupmapping
) {
4126 scx
->mapping
[MAPUSERS
] = usermapping
;
4127 scx
->mapping
[MAPGROUPS
] = groupmapping
;
4129 ntfs_log_error("There were no valid user or no valid group\n");
4130 /* now we can free the memory copy of input text */
4131 /* and rely on internal representation */
4133 item
= firstitem
->next
;
4138 /* no mapping file, try default mapping */
4139 if (scx
->uid
&& scx
->gid
) {
4140 if (!ntfs_default_mapping(scx
))
4141 ntfs_log_info("Using default user mapping\n");
4144 return (!scx
->mapping
[MAPUSERS
] || link_group_members(scx
));
4147 #ifdef HAVE_SETXATTR /* extended attributes interface required */
4150 * Get the ntfs attribute into an extended attribute
4151 * The attribute is returned according to cpu endianness
4154 int ntfs_get_ntfs_attrib(ntfs_inode
*ni
, char *value
, size_t size
)
4159 outsize
= 0; /* default to no data and no error */
4161 attrib
= le32_to_cpu(ni
->flags
);
4162 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
4163 attrib
|= const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4165 attrib
&= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4167 attrib
|= const_le32_to_cpu(FILE_ATTR_NORMAL
);
4168 outsize
= sizeof(FILE_ATTR_FLAGS
);
4169 if (size
>= outsize
) {
4171 memcpy(value
,&attrib
,outsize
);
4176 return (outsize
? (int)outsize
: -errno
);
4180 * Return the ntfs attribute into an extended attribute
4181 * The attribute is expected according to cpu endianness
4183 * Returns 0, or -1 if there is a problem
4186 int ntfs_set_ntfs_attrib(ntfs_inode
*ni
,
4187 const char *value
, size_t size
, int flags
)
4191 ATTR_FLAGS dirflags
;
4195 if (ni
&& value
&& (size
>= sizeof(FILE_ATTR_FLAGS
))) {
4196 if (!(flags
& XATTR_CREATE
)) {
4197 /* copy to avoid alignment problems */
4198 memcpy(&attrib
,value
,sizeof(FILE_ATTR_FLAGS
));
4199 settable
= FILE_ATTR_SETTABLE
;
4201 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
4203 * Accept changing compression for a directory
4204 * and set index root accordingly
4206 settable
|= FILE_ATTR_COMPRESSED
;
4207 if ((ni
->flags
^ cpu_to_le32(attrib
))
4208 & FILE_ATTR_COMPRESSED
) {
4209 if (ni
->flags
& FILE_ATTR_COMPRESSED
)
4210 dirflags
= const_cpu_to_le16(0);
4212 dirflags
= ATTR_IS_COMPRESSED
;
4213 res
= ntfs_attr_set_flags(ni
,
4217 ATTR_COMPRESSION_MASK
);
4221 ni
->flags
= (ni
->flags
& ~settable
)
4222 | (cpu_to_le32(attrib
) & settable
);
4223 NInoFileNameSetDirty(ni
);
4230 return (res
? -1 : 0);
4233 #endif /* HAVE_SETXATTR */
4236 * Open $Secure once for all
4237 * returns zero if it succeeds
4238 * non-zero if it fails. This is not an error (on NTFS v1.x)
4242 int ntfs_open_secure(ntfs_volume
*vol
)
4248 vol
->secure_ni
= (ntfs_inode
*)NULL
;
4249 vol
->secure_xsii
= (ntfs_index_context
*)NULL
;
4250 vol
->secure_xsdh
= (ntfs_index_context
*)NULL
;
4251 if (vol
->major_ver
>= 3) {
4252 /* make sure this is a genuine $Secure inode 9 */
4253 ni
= ntfs_pathname_to_inode(vol
, NULL
, "$Secure");
4254 if (ni
&& (ni
->mft_no
== 9)) {
4255 vol
->secure_reentry
= 0;
4256 vol
->secure_xsii
= ntfs_index_ctx_get(ni
,
4258 vol
->secure_xsdh
= ntfs_index_ctx_get(ni
,
4260 if (ni
&& vol
->secure_xsii
&& vol
->secure_xsdh
) {
4261 vol
->secure_ni
= ni
;
4271 * Allocated memory is freed to facilitate the detection of memory leaks
4274 void ntfs_close_secure(struct SECURITY_CONTEXT
*scx
)
4279 if (vol
->secure_ni
) {
4280 ntfs_index_ctx_put(vol
->secure_xsii
);
4281 ntfs_index_ctx_put(vol
->secure_xsdh
);
4282 ntfs_inode_close(vol
->secure_ni
);
4285 ntfs_free_mapping(scx
->mapping
);
4290 * API for direct access to security descriptors
4291 * based on Win32 API
4296 * Selective feeding of a security descriptor into user buffer
4298 * Returns TRUE if successful
4301 static BOOL
feedsecurityattr(const char *attr
, u32 selection
,
4302 char *buf
, u32 buflen
, u32
*psize
)
4304 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4305 SECURITY_DESCRIPTOR_RELATIVE
*pnhead
;
4310 unsigned int offdacl
;
4311 unsigned int offsacl
;
4312 unsigned int offowner
;
4313 unsigned int offgroup
;
4314 unsigned int daclsz
;
4315 unsigned int saclsz
;
4316 unsigned int usidsz
;
4317 unsigned int gsidsz
;
4318 unsigned int size
; /* size of requested attributes */
4325 control
= SE_SELF_RELATIVE
;
4326 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
;
4327 size
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4329 /* locate DACL if requested and available */
4330 if (phead
->dacl
&& (selection
& DACL_SECURITY_INFORMATION
)) {
4331 offdacl
= le32_to_cpu(phead
->dacl
);
4332 pdacl
= (const ACL
*)&attr
[offdacl
];
4333 daclsz
= le16_to_cpu(pdacl
->size
);
4335 avail
|= DACL_SECURITY_INFORMATION
;
4337 offdacl
= daclsz
= 0;
4339 /* locate owner if requested and available */
4340 offowner
= le32_to_cpu(phead
->owner
);
4341 if (offowner
&& (selection
& OWNER_SECURITY_INFORMATION
)) {
4342 /* find end of USID */
4343 pusid
= (const SID
*)&attr
[offowner
];
4344 usidsz
= ntfs_sid_size(pusid
);
4346 avail
|= OWNER_SECURITY_INFORMATION
;
4348 offowner
= usidsz
= 0;
4350 /* locate group if requested and available */
4351 offgroup
= le32_to_cpu(phead
->group
);
4352 if (offgroup
&& (selection
& GROUP_SECURITY_INFORMATION
)) {
4353 /* find end of GSID */
4354 pgsid
= (const SID
*)&attr
[offgroup
];
4355 gsidsz
= ntfs_sid_size(pgsid
);
4357 avail
|= GROUP_SECURITY_INFORMATION
;
4359 offgroup
= gsidsz
= 0;
4361 /* locate SACL if requested and available */
4362 if (phead
->sacl
&& (selection
& SACL_SECURITY_INFORMATION
)) {
4363 /* find end of SACL */
4364 offsacl
= le32_to_cpu(phead
->sacl
);
4365 psacl
= (const ACL
*)&attr
[offsacl
];
4366 saclsz
= le16_to_cpu(psacl
->size
);
4368 avail
|= SACL_SECURITY_INFORMATION
;
4370 offsacl
= saclsz
= 0;
4373 * Check having enough size in destination buffer
4374 * (required size is returned nevertheless so that
4375 * the request can be reissued with adequate size)
4377 if (size
> buflen
) {
4382 if (selection
& OWNER_SECURITY_INFORMATION
)
4383 control
|= phead
->control
& SE_OWNER_DEFAULTED
;
4384 if (selection
& GROUP_SECURITY_INFORMATION
)
4385 control
|= phead
->control
& SE_GROUP_DEFAULTED
;
4386 if (selection
& DACL_SECURITY_INFORMATION
)
4387 control
|= phead
->control
4390 | SE_DACL_AUTO_INHERITED
4391 | SE_DACL_PROTECTED
);
4392 if (selection
& SACL_SECURITY_INFORMATION
)
4393 control
|= phead
->control
4396 | SE_SACL_AUTO_INHERITED
4397 | SE_SACL_PROTECTED
);
4399 * copy header and feed new flags, even if no detailed data
4401 memcpy(buf
,attr
,sizeof(SECURITY_DESCRIPTOR_RELATIVE
));
4402 pnhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)buf
;
4403 pnhead
->control
= control
;
4404 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4406 /* copy DACL if requested and available */
4407 if (selection
& avail
& DACL_SECURITY_INFORMATION
) {
4408 pnhead
->dacl
= cpu_to_le32(pos
);
4409 memcpy(&buf
[pos
],&attr
[offdacl
],daclsz
);
4412 pnhead
->dacl
= const_cpu_to_le32(0);
4414 /* copy SACL if requested and available */
4415 if (selection
& avail
& SACL_SECURITY_INFORMATION
) {
4416 pnhead
->sacl
= cpu_to_le32(pos
);
4417 memcpy(&buf
[pos
],&attr
[offsacl
],saclsz
);
4420 pnhead
->sacl
= const_cpu_to_le32(0);
4422 /* copy owner if requested and available */
4423 if (selection
& avail
& OWNER_SECURITY_INFORMATION
) {
4424 pnhead
->owner
= cpu_to_le32(pos
);
4425 memcpy(&buf
[pos
],&attr
[offowner
],usidsz
);
4428 pnhead
->owner
= const_cpu_to_le32(0);
4430 /* copy group if requested and available */
4431 if (selection
& avail
& GROUP_SECURITY_INFORMATION
) {
4432 pnhead
->group
= cpu_to_le32(pos
);
4433 memcpy(&buf
[pos
],&attr
[offgroup
],gsidsz
);
4436 pnhead
->group
= const_cpu_to_le32(0);
4438 ntfs_log_error("Error in security descriptor size\n");
4447 * Merge a new security descriptor into the old one
4448 * and assign to designated file
4450 * Returns TRUE if successful
4453 static BOOL
mergesecurityattr(ntfs_volume
*vol
, const char *oldattr
,
4454 const char *newattr
, u32 selection
, ntfs_inode
*ni
)
4456 const SECURITY_DESCRIPTOR_RELATIVE
*oldhead
;
4457 const SECURITY_DESCRIPTOR_RELATIVE
*newhead
;
4458 SECURITY_DESCRIPTOR_RELATIVE
*targhead
;
4475 ok
= FALSE
; /* default return */
4476 oldhead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
4477 newhead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
;
4478 oldattrsz
= ntfs_attr_size(oldattr
);
4479 newattrsz
= ntfs_attr_size(newattr
);
4480 target
= (char*)ntfs_malloc(oldattrsz
+ newattrsz
);
4482 targhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)target
;
4483 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4484 control
= SE_SELF_RELATIVE
;
4486 * copy new DACL if selected
4487 * or keep old DACL if any
4489 if ((selection
& DACL_SECURITY_INFORMATION
) ?
4490 newhead
->dacl
: oldhead
->dacl
) {
4491 if (selection
& DACL_SECURITY_INFORMATION
) {
4492 offdacl
= le32_to_cpu(newhead
->dacl
);
4493 pdacl
= (const ACL
*)&newattr
[offdacl
];
4495 offdacl
= le32_to_cpu(oldhead
->dacl
);
4496 pdacl
= (const ACL
*)&oldattr
[offdacl
];
4498 size
= le16_to_cpu(pdacl
->size
);
4499 memcpy(&target
[pos
], pdacl
, size
);
4500 targhead
->dacl
= cpu_to_le32(pos
);
4503 targhead
->dacl
= const_cpu_to_le32(0);
4504 if (selection
& DACL_SECURITY_INFORMATION
) {
4505 control
|= newhead
->control
4508 | SE_DACL_PROTECTED
);
4509 if (newhead
->control
& SE_DACL_AUTO_INHERIT_REQ
)
4510 control
|= SE_DACL_AUTO_INHERITED
;
4512 control
|= oldhead
->control
4515 | SE_DACL_AUTO_INHERITED
4516 | SE_DACL_PROTECTED
);
4518 * copy new SACL if selected
4519 * or keep old SACL if any
4521 if ((selection
& SACL_SECURITY_INFORMATION
) ?
4522 newhead
->sacl
: oldhead
->sacl
) {
4523 if (selection
& SACL_SECURITY_INFORMATION
) {
4524 offsacl
= le32_to_cpu(newhead
->sacl
);
4525 psacl
= (const ACL
*)&newattr
[offsacl
];
4527 offsacl
= le32_to_cpu(oldhead
->sacl
);
4528 psacl
= (const ACL
*)&oldattr
[offsacl
];
4530 size
= le16_to_cpu(psacl
->size
);
4531 memcpy(&target
[pos
], psacl
, size
);
4532 targhead
->sacl
= cpu_to_le32(pos
);
4535 targhead
->sacl
= const_cpu_to_le32(0);
4536 if (selection
& SACL_SECURITY_INFORMATION
) {
4537 control
|= newhead
->control
4540 | SE_SACL_PROTECTED
);
4541 if (newhead
->control
& SE_SACL_AUTO_INHERIT_REQ
)
4542 control
|= SE_SACL_AUTO_INHERITED
;
4544 control
|= oldhead
->control
4547 | SE_SACL_AUTO_INHERITED
4548 | SE_SACL_PROTECTED
);
4550 * copy new OWNER if selected
4551 * or keep old OWNER if any
4553 if ((selection
& OWNER_SECURITY_INFORMATION
) ?
4554 newhead
->owner
: oldhead
->owner
) {
4555 if (selection
& OWNER_SECURITY_INFORMATION
) {
4556 offowner
= le32_to_cpu(newhead
->owner
);
4557 powner
= (const SID
*)&newattr
[offowner
];
4559 offowner
= le32_to_cpu(oldhead
->owner
);
4560 powner
= (const SID
*)&oldattr
[offowner
];
4562 size
= ntfs_sid_size(powner
);
4563 memcpy(&target
[pos
], powner
, size
);
4564 targhead
->owner
= cpu_to_le32(pos
);
4567 targhead
->owner
= const_cpu_to_le32(0);
4568 if (selection
& OWNER_SECURITY_INFORMATION
)
4569 control
|= newhead
->control
& SE_OWNER_DEFAULTED
;
4571 control
|= oldhead
->control
& SE_OWNER_DEFAULTED
;
4573 * copy new GROUP if selected
4574 * or keep old GROUP if any
4576 if ((selection
& GROUP_SECURITY_INFORMATION
) ?
4577 newhead
->group
: oldhead
->group
) {
4578 if (selection
& GROUP_SECURITY_INFORMATION
) {
4579 offgroup
= le32_to_cpu(newhead
->group
);
4580 pgroup
= (const SID
*)&newattr
[offgroup
];
4581 control
|= newhead
->control
4582 & SE_GROUP_DEFAULTED
;
4584 offgroup
= le32_to_cpu(oldhead
->group
);
4585 pgroup
= (const SID
*)&oldattr
[offgroup
];
4586 control
|= oldhead
->control
4587 & SE_GROUP_DEFAULTED
;
4589 size
= ntfs_sid_size(pgroup
);
4590 memcpy(&target
[pos
], pgroup
, size
);
4591 targhead
->group
= cpu_to_le32(pos
);
4594 targhead
->group
= const_cpu_to_le32(0);
4595 if (selection
& GROUP_SECURITY_INFORMATION
)
4596 control
|= newhead
->control
& SE_GROUP_DEFAULTED
;
4598 control
|= oldhead
->control
& SE_GROUP_DEFAULTED
;
4599 targhead
->revision
= SECURITY_DESCRIPTOR_REVISION
;
4600 targhead
->alignment
= 0;
4601 targhead
->control
= control
;
4602 ok
= !update_secur_descr(vol
, target
, ni
);
4609 * Return the security descriptor of a file
4610 * This is intended to be similar to GetFileSecurity() from Win32
4611 * in order to facilitate the development of portable tools
4613 * returns zero if unsuccessful (following Win32 conventions)
4615 * the securid if any
4617 * The Win32 API is :
4619 * BOOL WINAPI GetFileSecurity(
4620 * __in LPCTSTR lpFileName,
4621 * __in SECURITY_INFORMATION RequestedInformation,
4622 * __out_opt PSECURITY_DESCRIPTOR pSecurityDescriptor,
4623 * __in DWORD nLength,
4624 * __out LPDWORD lpnLengthNeeded
4629 int ntfs_get_file_security(struct SECURITY_API
*scapi
,
4630 const char *path
, u32 selection
,
4631 char *buf
, u32 buflen
, u32
*psize
)
4637 res
= 0; /* default return */
4638 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4639 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4641 attr
= getsecurityattr(scapi
->security
.vol
, ni
);
4643 if (feedsecurityattr(attr
,selection
,
4644 buf
,buflen
,psize
)) {
4645 if (test_nino_flag(ni
, v3_Extensions
)
4654 ntfs_inode_close(ni
);
4657 if (!res
) *psize
= 0;
4659 errno
= EINVAL
; /* do not clear *psize */
4665 * Set the security descriptor of a file or directory
4666 * This is intended to be similar to SetFileSecurity() from Win32
4667 * in order to facilitate the development of portable tools
4669 * returns zero if unsuccessful (following Win32 conventions)
4671 * the securid if any
4673 * The Win32 API is :
4675 * BOOL WINAPI SetFileSecurity(
4676 * __in LPCTSTR lpFileName,
4677 * __in SECURITY_INFORMATION SecurityInformation,
4678 * __in PSECURITY_DESCRIPTOR pSecurityDescriptor
4682 int ntfs_set_file_security(struct SECURITY_API
*scapi
,
4683 const char *path
, u32 selection
, const char *attr
)
4685 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4692 res
= 0; /* default return */
4693 if (scapi
&& (scapi
->magic
== MAGIC_API
) && attr
) {
4694 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
;
4695 attrsz
= ntfs_attr_size(attr
);
4696 /* if selected, owner and group must be present or defaulted */
4697 missing
= ((selection
& OWNER_SECURITY_INFORMATION
)
4699 && !(phead
->control
& SE_OWNER_DEFAULTED
))
4700 || ((selection
& GROUP_SECURITY_INFORMATION
)
4702 && !(phead
->control
& SE_GROUP_DEFAULTED
));
4704 && (phead
->control
& SE_SELF_RELATIVE
)
4705 && ntfs_valid_descr(attr
, attrsz
)) {
4706 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
,
4709 oldattr
= getsecurityattr(scapi
->security
.vol
,
4712 if (mergesecurityattr(
4713 scapi
->security
.vol
,
4716 if (test_nino_flag(ni
,
4725 ntfs_inode_close(ni
);
4736 * Return the attributes of a file
4737 * This is intended to be similar to GetFileAttributes() from Win32
4738 * in order to facilitate the development of portable tools
4740 * returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES)
4742 * The Win32 API is :
4744 * DWORD WINAPI GetFileAttributes(
4745 * __in LPCTSTR lpFileName
4749 int ntfs_get_file_attributes(struct SECURITY_API
*scapi
, const char *path
)
4754 attrib
= -1; /* default return */
4755 if (scapi
&& (scapi
->magic
== MAGIC_API
) && path
) {
4756 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4758 attrib
= le32_to_cpu(ni
->flags
);
4759 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
4760 attrib
|= const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4762 attrib
&= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4764 attrib
|= const_le32_to_cpu(FILE_ATTR_NORMAL
);
4766 ntfs_inode_close(ni
);
4770 errno
= EINVAL
; /* do not clear *psize */
4776 * Set attributes to a file or directory
4777 * This is intended to be similar to SetFileAttributes() from Win32
4778 * in order to facilitate the development of portable tools
4780 * Only a few flags can be set (same list as Win32)
4782 * returns zero if unsuccessful (following Win32 conventions)
4783 * nonzero if successful
4785 * The Win32 API is :
4787 * BOOL WINAPI SetFileAttributes(
4788 * __in LPCTSTR lpFileName,
4789 * __in DWORD dwFileAttributes
4793 BOOL
ntfs_set_file_attributes(struct SECURITY_API
*scapi
,
4794 const char *path
, s32 attrib
)
4798 ATTR_FLAGS dirflags
;
4801 res
= 0; /* default return */
4802 if (scapi
&& (scapi
->magic
== MAGIC_API
) && path
) {
4803 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4805 settable
= FILE_ATTR_SETTABLE
;
4806 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
4808 * Accept changing compression for a directory
4809 * and set index root accordingly
4811 settable
|= FILE_ATTR_COMPRESSED
;
4812 if ((ni
->flags
^ cpu_to_le32(attrib
))
4813 & FILE_ATTR_COMPRESSED
) {
4814 if (ni
->flags
& FILE_ATTR_COMPRESSED
)
4815 dirflags
= const_cpu_to_le16(0);
4817 dirflags
= ATTR_IS_COMPRESSED
;
4818 res
= ntfs_attr_set_flags(ni
,
4822 ATTR_COMPRESSION_MASK
);
4826 ni
->flags
= (ni
->flags
& ~settable
)
4827 | (cpu_to_le32(attrib
) & settable
);
4830 if (!ntfs_inode_close(ni
))
4839 BOOL
ntfs_read_directory(struct SECURITY_API
*scapi
,
4840 const char *path
, ntfs_filldir_t callback
, void *context
)
4846 ok
= FALSE
; /* default return */
4847 if (scapi
&& (scapi
->magic
== MAGIC_API
) && callback
) {
4848 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4850 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
4852 ntfs_readdir(ni
,&pos
,context
,callback
);
4853 ok
= !ntfs_inode_close(ni
);
4855 ntfs_inode_close(ni
);
4861 errno
= EINVAL
; /* do not clear *psize */
4866 * read $SDS (for auditing security data)
4868 * Returns the number or read bytes, or -1 if there is an error
4871 int ntfs_read_sds(struct SECURITY_API
*scapi
,
4872 char *buf
, u32 size
, u32 offset
)
4876 got
= -1; /* default return */
4877 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4878 if (scapi
->security
.vol
->secure_ni
)
4879 got
= ntfs_local_read(scapi
->security
.vol
->secure_ni
,
4880 STREAM_SDS
, 4, buf
, size
, offset
);
4889 * read $SII (for auditing security data)
4891 * Returns next entry, or NULL if there is an error
4894 INDEX_ENTRY
*ntfs_read_sii(struct SECURITY_API
*scapi
,
4900 ntfs_index_context
*xsii
;
4902 ret
= (INDEX_ENTRY
*)NULL
; /* default return */
4903 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4904 xsii
= scapi
->security
.vol
->secure_xsii
;
4907 key
.security_id
= const_cpu_to_le32(0);
4908 found
= !ntfs_index_lookup((char*)&key
,
4909 sizeof(SII_INDEX_KEY
), xsii
);
4910 /* not supposed to find */
4911 if (!found
&& (errno
== ENOENT
))
4914 ret
= ntfs_index_next(entry
,xsii
);
4925 * read $SDH (for auditing security data)
4927 * Returns next entry, or NULL if there is an error
4930 INDEX_ENTRY
*ntfs_read_sdh(struct SECURITY_API
*scapi
,
4936 ntfs_index_context
*xsdh
;
4938 ret
= (INDEX_ENTRY
*)NULL
; /* default return */
4939 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4940 xsdh
= scapi
->security
.vol
->secure_xsdh
;
4943 key
.hash
= const_cpu_to_le32(0);
4944 key
.security_id
= const_cpu_to_le32(0);
4945 found
= !ntfs_index_lookup((char*)&key
,
4946 sizeof(SDH_INDEX_KEY
), xsdh
);
4947 /* not supposed to find */
4948 if (!found
&& (errno
== ENOENT
))
4951 ret
= ntfs_index_next(entry
,xsdh
);
4954 } else errno
= ENOTSUP
;
4961 * Get the mapped user SID
4962 * A buffer of 40 bytes has to be supplied
4964 * returns the size of the SID, or zero and errno set if not found
4967 int ntfs_get_usid(struct SECURITY_API
*scapi
, uid_t uid
, char *buf
)
4974 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4975 usid
= ntfs_find_usid(scapi
->security
.mapping
[MAPUSERS
], uid
, (SID
*)&defusid
);
4977 size
= ntfs_sid_size(usid
);
4978 memcpy(buf
,usid
,size
);
4987 * Get the mapped group SID
4988 * A buffer of 40 bytes has to be supplied
4990 * returns the size of the SID, or zero and errno set if not found
4993 int ntfs_get_gsid(struct SECURITY_API
*scapi
, gid_t gid
, char *buf
)
5000 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
5001 gsid
= ntfs_find_gsid(scapi
->security
.mapping
[MAPGROUPS
], gid
, (SID
*)&defgsid
);
5003 size
= ntfs_sid_size(gsid
);
5004 memcpy(buf
,gsid
,size
);
5013 * Get the user mapped to a SID
5015 * returns the uid, or -1 if not found
5018 int ntfs_get_user(struct SECURITY_API
*scapi
, const SID
*usid
)
5023 if (scapi
&& (scapi
->magic
== MAGIC_API
) && ntfs_valid_sid(usid
)) {
5024 if (ntfs_same_sid(usid
,adminsid
))
5027 uid
= ntfs_find_user(scapi
->security
.mapping
[MAPUSERS
], usid
);
5039 * Get the group mapped to a SID
5041 * returns the uid, or -1 if not found
5044 int ntfs_get_group(struct SECURITY_API
*scapi
, const SID
*gsid
)
5049 if (scapi
&& (scapi
->magic
== MAGIC_API
) && ntfs_valid_sid(gsid
)) {
5050 if (ntfs_same_sid(gsid
,adminsid
))
5053 gid
= ntfs_find_group(scapi
->security
.mapping
[MAPGROUPS
], gsid
);
5065 * Initializations before calling ntfs_get_file_security()
5066 * ntfs_set_file_security() and ntfs_read_directory()
5068 * Only allowed for root
5070 * Returns an (obscured) struct SECURITY_API* needed for further calls
5071 * NULL if not root (EPERM) or device is mounted (EBUSY)
5074 struct SECURITY_API
*ntfs_initialize_file_security(const char *device
,
5078 unsigned long mntflag
;
5080 struct SECURITY_API
*scapi
;
5081 struct SECURITY_CONTEXT
*scx
;
5083 scapi
= (struct SECURITY_API
*)NULL
;
5084 mnt
= ntfs_check_if_mounted(device
, &mntflag
);
5085 if (!mnt
&& !(mntflag
& NTFS_MF_MOUNTED
) && !getuid()) {
5086 vol
= ntfs_mount(device
, flags
);
5088 scapi
= (struct SECURITY_API
*)
5089 ntfs_malloc(sizeof(struct SECURITY_API
));
5090 if (!ntfs_volume_get_free_space(vol
)
5092 scapi
->magic
= MAGIC_API
;
5093 scapi
->seccache
= (struct PERMISSIONS_CACHE
*)NULL
;
5094 scx
= &scapi
->security
;
5096 scx
->uid
= getuid();
5097 scx
->gid
= getgid();
5098 scx
->pseccache
= &scapi
->seccache
;
5099 scx
->vol
->secure_flags
= 0;
5100 /* accept no mapping and no $Secure */
5101 ntfs_build_mapping(scx
,(const char*)NULL
);
5102 ntfs_open_secure(vol
);
5108 mnt
= ntfs_umount(vol
,FALSE
);
5109 scapi
= (struct SECURITY_API
*)NULL
;
5121 * Leaving after ntfs_initialize_file_security()
5123 * Returns FALSE if FAILED
5126 BOOL
ntfs_leave_file_security(struct SECURITY_API
*scapi
)
5132 if (scapi
&& (scapi
->magic
== MAGIC_API
) && scapi
->security
.vol
) {
5133 vol
= scapi
->security
.vol
;
5134 ntfs_close_secure(&scapi
->security
);
5136 if (!ntfs_umount(vol
, 0))