2 * security.c - Handling security/ACLs in NTFS. Originated from the Linux-NTFS project.
4 * Copyright (c) 2004 Anton Altaparmakov
5 * Copyright (c) 2005-2006 Szabolcs Szakacsits
6 * Copyright (c) 2006 Yura Pakhuchiy
7 * Copyright (c) 2007-2010 Jean-Pierre Andre
9 * This program/include file is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program/include file is distributed in the hope that it will be
15 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (in the main directory of the NTFS-3G
21 * distribution in the file COPYING); if not, write to the Free Software
22 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
);
408 * Get the first entry of current index block
409 * cut and pasted form ntfs_ie_get_first() in index.c
412 static INDEX_ENTRY
*ntfs_ie_get_first(INDEX_HEADER
*ih
)
414 return (INDEX_ENTRY
*)((u8
*)ih
+ le32_to_cpu(ih
->entries_offset
));
418 * Stuff a 256KB block into $SDS before writing descriptors
421 * This prevents $SDS from being automatically declared as sparse
422 * when the second copy of the first security descriptor is written
423 * 256KB further ahead.
425 * Having $SDS declared as a sparse file is not wrong by itself
426 * and chkdsk leaves it as a sparse file. It does however complain
427 * and add a sparse flag (0x0200) into field file_attributes of
428 * STANDARD_INFORMATION of $Secure. This probably means that a
429 * sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse
430 * files (FILE_ATTR_SPARSE_FILE).
432 * Windows normally does not convert to sparse attribute or sparse
433 * file. Stuffing is just a way to get to the same result.
436 static int entersecurity_stuff(ntfs_volume
*vol
, off_t offs
)
445 stuff
= (char*)ntfs_malloc(STUFFSZ
);
447 memset(stuff
, 0, STUFFSZ
);
449 written
= ntfs_attr_data_write(vol
->secure_ni
,
450 STREAM_SDS
, 4, stuff
, STUFFSZ
, offs
);
451 if (written
== STUFFSZ
) {
458 } while (!res
&& (total
< ALIGN_SDS_BLOCK
));
468 * Enter a new security descriptor into $Secure (data only)
469 * it has to be written twice with an offset of 256KB
471 * Should only be called by entersecurityattr() to ensure consistency
473 * Returns zero if sucessful
476 static int entersecurity_data(ntfs_volume
*vol
,
477 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
,
478 le32 hash
, le32 keyid
, off_t offs
, int gap
)
485 SECURITY_DESCRIPTOR_HEADER
*phsds
;
488 fullsz
= attrsz
+ gap
+ sizeof(SECURITY_DESCRIPTOR_HEADER
);
489 fullattr
= (char*)ntfs_malloc(fullsz
);
492 * Clear the gap from previous descriptor
493 * this could be useful for appending the second
494 * copy to the end of file. When creating a new
495 * 256K block, the gap is cleared while writing
499 memset(fullattr
,0,gap
);
500 memcpy(&fullattr
[gap
+ sizeof(SECURITY_DESCRIPTOR_HEADER
)],
502 phsds
= (SECURITY_DESCRIPTOR_HEADER
*)&fullattr
[gap
];
504 phsds
->security_id
= keyid
;
505 phsds
->offset
= cpu_to_le64(offs
);
506 phsds
->length
= cpu_to_le32(fullsz
- gap
);
507 written1
= ntfs_attr_data_write(vol
->secure_ni
,
508 STREAM_SDS
, 4, fullattr
, fullsz
,
510 written2
= ntfs_attr_data_write(vol
->secure_ni
,
511 STREAM_SDS
, 4, fullattr
, fullsz
,
512 offs
- gap
+ ALIGN_SDS_BLOCK
);
513 if ((written1
== fullsz
)
514 && (written2
== written1
))
525 * Enter a new security descriptor in $Secure (indexes only)
527 * Should only be called by entersecurityattr() to ensure consistency
529 * Returns zero if sucessful
532 static int entersecurity_indexes(ntfs_volume
*vol
, s64 attrsz
,
533 le32 hash
, le32 keyid
, off_t offs
)
543 ntfs_index_context
*xsii
;
544 ntfs_index_context
*xsdh
;
549 /* enter a new $SII record */
551 xsii
= vol
->secure_xsii
;
552 ntfs_index_ctx_reinit(xsii
);
553 newsii
.offs
= const_cpu_to_le16(20);
554 newsii
.size
= const_cpu_to_le16(sizeof(struct SII
) - 20);
555 newsii
.fill1
= const_cpu_to_le32(0);
556 newsii
.indexsz
= const_cpu_to_le16(sizeof(struct SII
));
557 newsii
.indexksz
= const_cpu_to_le16(sizeof(SII_INDEX_KEY
));
558 newsii
.flags
= const_cpu_to_le16(0);
559 newsii
.fill2
= const_cpu_to_le16(0);
560 newsii
.keysecurid
= keyid
;
562 newsii
.securid
= keyid
;
563 realign
.all
= cpu_to_le64(offs
);
564 newsii
.dataoffsh
= realign
.parts
.dataoffsh
;
565 newsii
.dataoffsl
= realign
.parts
.dataoffsl
;
566 newsii
.datasize
= cpu_to_le32(attrsz
567 + sizeof(SECURITY_DESCRIPTOR_HEADER
));
568 if (!ntfs_ie_add(xsii
,(INDEX_ENTRY
*)&newsii
)) {
570 /* enter a new $SDH record */
572 xsdh
= vol
->secure_xsdh
;
573 ntfs_index_ctx_reinit(xsdh
);
574 newsdh
.offs
= const_cpu_to_le16(24);
575 newsdh
.size
= const_cpu_to_le16(
576 sizeof(SECURITY_DESCRIPTOR_HEADER
));
577 newsdh
.fill1
= const_cpu_to_le32(0);
578 newsdh
.indexsz
= const_cpu_to_le16(
580 newsdh
.indexksz
= const_cpu_to_le16(
581 sizeof(SDH_INDEX_KEY
));
582 newsdh
.flags
= const_cpu_to_le16(0);
583 newsdh
.fill2
= const_cpu_to_le16(0);
584 newsdh
.keyhash
= hash
;
585 newsdh
.keysecurid
= keyid
;
587 newsdh
.securid
= keyid
;
588 newsdh
.dataoffsh
= realign
.parts
.dataoffsh
;
589 newsdh
.dataoffsl
= realign
.parts
.dataoffsl
;
590 newsdh
.datasize
= cpu_to_le32(attrsz
591 + sizeof(SECURITY_DESCRIPTOR_HEADER
));
592 /* special filler value, Windows generally */
593 /* fills with 0x00490049, sometimes with zero */
594 newsdh
.fill3
= const_cpu_to_le32(0x00490049);
595 if (!ntfs_ie_add(xsdh
,(INDEX_ENTRY
*)&newsdh
))
602 * Enter a new security descriptor in $Secure (data and indexes)
603 * Returns id of entry, or zero if there is a problem.
604 * (should not be called for NTFS version < 3.0)
606 * important : calls have to be serialized, however no locking is
607 * needed while fuse is not multithreaded
610 static le32
entersecurityattr(ntfs_volume
*vol
,
611 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
,
631 ntfs_index_context
*xsii
;
636 /* find the first available securid beyond the last key */
637 /* in $Secure:$SII. This also determines the first */
638 /* available location in $Secure:$SDS, as this stream */
639 /* is always appended to and the id's are allocated */
642 securid
= const_cpu_to_le32(0);
643 xsii
= vol
->secure_xsii
;
644 ntfs_index_ctx_reinit(xsii
);
646 keyid
= const_cpu_to_le32(-1);
648 found
= !ntfs_index_lookup((char*)&keyid
,
649 sizeof(SII_INDEX_KEY
), xsii
);
650 if (!found
&& (errno
!= ENOENT
)) {
651 ntfs_log_perror("Inconsistency in index $SII");
652 psii
= (struct SII
*)NULL
;
654 /* restore errno to avoid misinterpretation */
657 psii
= (struct SII
*)xsii
->entry
;
661 * Get last entry in block, but must get first one
662 * one first, as we should already be beyond the
663 * last one. For some reason the search for the last
664 * entry sometimes does not return the last block...
665 * we assume this can only happen in root block
667 if (xsii
->is_in_root
)
668 entry
= ntfs_ie_get_first
669 ((INDEX_HEADER
*)&xsii
->ir
->index
);
671 entry
= ntfs_ie_get_first
672 ((INDEX_HEADER
*)&xsii
->ib
->index
);
674 * All index blocks should be at least half full
675 * so there always is a last entry but one,
676 * except when creating the first entry in index root.
677 * This was however found not to be true : chkdsk
678 * sometimes deletes all the (unused) keys in the last
679 * index block without rebalancing the tree.
680 * When this happens, a new search is restarted from
683 keyid
= const_cpu_to_le32(0);
686 next
= ntfs_index_next(entry
,xsii
);
688 psii
= (struct SII
*)next
;
689 /* save last key and */
690 /* available position */
691 keyid
= psii
->keysecurid
;
692 realign
.parts
.dataoffsh
694 realign
.parts
.dataoffsl
696 offs
= le64_to_cpu(realign
.all
);
697 size
= le32_to_cpu(psii
->datasize
);
700 if (!entry
&& !keyid
&& !retries
) {
701 /* search failed, retry from smallest key */
702 ntfs_index_ctx_reinit(xsii
);
703 found
= !ntfs_index_lookup((char*)&keyid
,
704 sizeof(SII_INDEX_KEY
), xsii
);
705 if (!found
&& (errno
!= ENOENT
)) {
706 ntfs_log_perror("Index $SII is broken");
718 * could not find any entry, before creating the first
719 * entry, make a double check by making sure size of $SII
720 * is less than needed for one entry
722 securid
= const_cpu_to_le32(0);
723 na
= ntfs_attr_open(vol
->secure_ni
,AT_INDEX_ROOT
,sii_stream
,4);
725 if ((size_t)na
->data_size
< sizeof(struct SII
)) {
726 ntfs_log_error("Creating the first security_id\n");
727 securid
= const_cpu_to_le32(FIRST_SECURITY_ID
);
732 ntfs_log_error("Error creating a security_id\n");
736 newkey
= le32_to_cpu(keyid
) + 1;
737 securid
= cpu_to_le32(newkey
);
740 * The security attr has to be written twice 256KB
741 * apart. This implies that offsets like
742 * 0x40000*odd_integer must be left available for
743 * the second copy. So align to next block when
744 * the last byte overflows on a wrong block.
748 gap
= (-size
) & (ALIGN_SDS_ENTRY
- 1);
750 if ((offs
+ attrsz
+ sizeof(SECURITY_DESCRIPTOR_HEADER
) - 1)
752 offs
= ((offs
+ attrsz
753 + sizeof(SECURITY_DESCRIPTOR_HEADER
) - 1)
754 | (ALIGN_SDS_BLOCK
- 1)) + 1;
756 if (!(offs
& (ALIGN_SDS_BLOCK
- 1)))
757 entersecurity_stuff(vol
, offs
);
759 * now write the security attr to storage :
760 * first data, then SII, then SDH
761 * If failure occurs while writing SDS, data will never
762 * be accessed through indexes, and will be overwritten
763 * by the next allocated descriptor
764 * If failure occurs while writing SII, the id has not
765 * recorded and will be reallocated later
766 * If failure occurs while writing SDH, the space allocated
767 * in SDS or SII will not be reused, an inconsistency
768 * will persist with no significant consequence
770 if (entersecurity_data(vol
, attr
, attrsz
, hash
, securid
, offs
, gap
)
771 || entersecurity_indexes(vol
, attrsz
, hash
, securid
, offs
))
772 securid
= const_cpu_to_le32(0);
774 /* inode now is dirty, synchronize it all */
775 ntfs_index_entry_mark_dirty(vol
->secure_xsii
);
776 ntfs_index_ctx_reinit(vol
->secure_xsii
);
777 ntfs_index_entry_mark_dirty(vol
->secure_xsdh
);
778 ntfs_index_ctx_reinit(vol
->secure_xsdh
);
779 NInoSetDirty(vol
->secure_ni
);
780 if (ntfs_inode_sync(vol
->secure_ni
))
781 ntfs_log_perror("Could not sync $Secure\n");
786 * Find a matching security descriptor in $Secure,
787 * if none, allocate a new id and write the descriptor to storage
788 * Returns id of entry, or zero if there is a problem.
790 * important : calls have to be serialized, however no locking is
791 * needed while fuse is not multithreaded
794 static le32
setsecurityattr(ntfs_volume
*vol
,
795 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
)
797 struct SDH
*psdh
; /* this is an image of index (le) */
811 ntfs_index_context
*xsdh
;
819 hash
= ntfs_security_hash(attr
,attrsz
);
820 oldattr
= (char*)NULL
;
821 securid
= const_cpu_to_le32(0);
823 xsdh
= vol
->secure_xsdh
;
824 if (vol
->secure_ni
&& xsdh
&& !vol
->secure_reentry
++) {
825 ntfs_index_ctx_reinit(xsdh
);
827 * find the nearest key as (hash,0)
828 * (do not search for partial key : in case of collision,
829 * it could return a key which is not the first one which
833 key
.security_id
= const_cpu_to_le32(0);
835 found
= !ntfs_index_lookup((char*)&key
,
836 sizeof(SDH_INDEX_KEY
), xsdh
);
837 if (!found
&& (errno
!= ENOENT
))
838 ntfs_log_perror("Inconsistency in index $SDH");
840 /* restore errno to avoid misinterpretation */
845 * lookup() may return a node with no data,
848 if (entry
->ie_flags
& INDEX_ENTRY_END
)
849 entry
= ntfs_index_next(entry
,xsdh
);
852 psdh
= (struct SDH
*)entry
;
854 size
= (size_t) le32_to_cpu(psdh
->datasize
)
855 - sizeof(SECURITY_DESCRIPTOR_HEADER
);
857 /* if hash is not the same, the key is not present */
858 if (psdh
&& (size
> 0)
859 && (psdh
->keyhash
== hash
)) {
860 /* if hash is the same */
861 /* check the whole record */
862 realign
.parts
.dataoffsh
= psdh
->dataoffsh
;
863 realign
.parts
.dataoffsl
= psdh
->dataoffsl
;
864 offs
= le64_to_cpu(realign
.all
)
865 + sizeof(SECURITY_DESCRIPTOR_HEADER
);
866 oldattr
= (char*)ntfs_malloc(size
);
868 rdsize
= ntfs_attr_data_read(
871 oldattr
, size
, offs
);
872 found
= (rdsize
== size
)
873 && !memcmp(oldattr
,attr
,size
);
875 /* if the records do not compare */
876 /* (hash collision), try next one */
878 entry
= ntfs_index_next(
885 } while (collision
&& entry
);
887 securid
= psdh
->keysecurid
;
891 securid
= const_cpu_to_le32(0);
895 * have to build a new one
897 securid
= entersecurityattr(vol
,
903 if (--vol
->secure_reentry
)
904 ntfs_log_perror("Reentry error, check no multithreading\n");
910 * Update the security descriptor of a file
911 * Either as an attribute (complying with pre v3.x NTFS version)
912 * or, when possible, as an entry in $Secure (for NTFS v3.x)
914 * returns 0 if success
917 static int update_secur_descr(ntfs_volume
*vol
,
918 char *newattr
, ntfs_inode
*ni
)
925 newattrsz
= ntfs_attr_size(newattr
);
927 #if !FORCE_FORMAT_v1x
928 if ((vol
->major_ver
< 3) || !vol
->secure_ni
) {
931 /* update for NTFS format v1.x */
933 /* update the old security attribute */
934 na
= ntfs_attr_open(ni
, AT_SECURITY_DESCRIPTOR
, AT_UNNAMED
, 0);
936 /* resize attribute */
937 res
= ntfs_attr_truncate(na
, (s64
) newattrsz
);
938 /* overwrite value */
940 written
= (int)ntfs_attr_pwrite(na
, (s64
) 0,
941 (s64
) newattrsz
, newattr
);
942 if (written
!= newattrsz
) {
943 ntfs_log_error("Failed to update "
944 "a v1.x security descriptor\n");
951 /* if old security attribute was found, also */
952 /* truncate standard information attribute to v1.x */
953 /* this is needed when security data is wanted */
954 /* as v1.x though volume is formatted for v3.x */
955 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
958 clear_nino_flag(ni
, v3_Extensions
);
960 * Truncating the record does not sweep extensions
961 * from copy in memory. Clear security_id to be safe
963 ni
->security_id
= const_cpu_to_le32(0);
964 res
= ntfs_attr_truncate(na
, (s64
)48);
966 clear_nino_flag(ni
, v3_Extensions
);
970 * insert the new security attribute if there
973 res
= ntfs_attr_add(ni
, AT_SECURITY_DESCRIPTOR
,
974 AT_UNNAMED
, 0, (u8
*)newattr
,
977 #if !FORCE_FORMAT_v1x
980 /* update for NTFS format v3.x */
984 securid
= setsecurityattr(vol
,
985 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
988 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
992 if (!test_nino_flag(ni
, v3_Extensions
)) {
993 /* expand standard information attribute to v3.x */
994 res
= ntfs_attr_truncate(na
,
995 (s64
)sizeof(STANDARD_INFORMATION
));
996 ni
->owner_id
= const_cpu_to_le32(0);
997 ni
->quota_charged
= const_cpu_to_le64(0);
998 ni
->usn
= const_cpu_to_le64(0);
1000 AT_SECURITY_DESCRIPTOR
,
1003 set_nino_flag(ni
, v3_Extensions
);
1004 ni
->security_id
= securid
;
1005 ntfs_attr_close(na
);
1007 ntfs_log_error("Failed to update "
1008 "standard informations\n");
1017 /* mark node as dirty */
1023 * Upgrade the security descriptor of a file
1024 * This is intended to allow graceful upgrades for files which
1025 * were created in previous versions, with a security attributes
1026 * and no security id.
1028 * It will allocate a security id and replace the individual
1029 * security attribute by a reference to the global one
1031 * Special files are not upgraded (currently / and files in
1034 * Though most code is similar to update_secur_desc() it has
1035 * been kept apart to facilitate the further processing of
1036 * special cases or even to remove it if found dangerous.
1038 * returns 0 if success,
1039 * 1 if not upgradable. This is not an error.
1040 * -1 if there is a problem
1043 static int upgrade_secur_desc(ntfs_volume
*vol
,
1044 const char *attr
, ntfs_inode
*ni
)
1052 * upgrade requires NTFS format v3.x
1053 * also refuse upgrading for special files
1054 * whose number is less than FILE_first_user
1057 if ((vol
->major_ver
>= 3)
1058 && (ni
->mft_no
>= FILE_first_user
)) {
1059 attrsz
= ntfs_attr_size(attr
);
1060 securid
= setsecurityattr(vol
,
1061 (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
,
1064 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
1068 /* expand standard information attribute to v3.x */
1069 res
= ntfs_attr_truncate(na
,
1070 (s64
)sizeof(STANDARD_INFORMATION
));
1071 ni
->owner_id
= const_cpu_to_le32(0);
1072 ni
->quota_charged
= const_cpu_to_le64(0);
1073 ni
->usn
= const_cpu_to_le64(0);
1074 ntfs_attr_remove(ni
, AT_SECURITY_DESCRIPTOR
,
1076 set_nino_flag(ni
, v3_Extensions
);
1077 ni
->security_id
= securid
;
1078 ntfs_attr_close(na
);
1080 ntfs_log_error("Failed to upgrade "
1081 "standard informations\n");
1087 /* mark node as dirty */
1096 * Optional simplified checking of group membership
1098 * This only takes into account the groups defined in
1099 * /etc/group at initialization time.
1100 * It does not take into account the groups dynamically set by
1101 * setgroups() nor the changes in /etc/group since initialization
1103 * This optional method could be useful if standard checking
1104 * leads to a performance concern.
1106 * Should not be called for user root, however the group may be root
1110 static BOOL
staticgroupmember(struct SECURITY_CONTEXT
*scx
, uid_t uid
, gid_t gid
)
1115 struct MAPPING
*user
;
1119 user
= scx
->mapping
[MAPUSERS
];
1120 while (user
&& ((uid_t
)user
->xid
!= uid
))
1123 groups
= user
->groups
;
1124 grcnt
= user
->grcnt
;
1125 while ((--grcnt
>= 0) && (groups
[grcnt
] != gid
)) { }
1126 ingroup
= (grcnt
>= 0);
1134 * Check whether current thread owner is member of file group
1136 * Should not be called for user root, however the group may be root
1138 * As indicated by Miklos Szeredi :
1140 * The group list is available in
1142 * /proc/$PID/task/$TID/status
1144 * and fuse supplies TID in get_fuse_context()->pid. The only problem is
1145 * finding out PID, for which I have no good solution, except to iterate
1146 * through all processes. This is rather slow, but may be speeded up
1147 * with caching and heuristics (for single threaded programs PID = TID).
1149 * The following implementation gets the group list from
1150 * /proc/$TID/task/$TID/status which apparently exists and
1151 * contains the same data.
1154 static BOOL
groupmember(struct SECURITY_CONTEXT
*scx
, uid_t uid
, gid_t gid
)
1156 static char key
[] = "\nGroups:";
1159 enum { INKEY
, INSEP
, INNUM
, INEND
} state
;
1169 if (scx
->vol
->secure_flags
& (1 << SECURITY_STATICGRPS
))
1170 ismember
= staticgroupmember(scx
, uid
, gid
);
1172 ismember
= FALSE
; /* default return */
1174 sprintf(filename
,"/proc/%u/task/%u/status",tid
,tid
);
1175 fd
= open(filename
,O_RDONLY
);
1177 got
= read(fd
, buf
, BUFSZ
);
1184 * A simple automaton to process lines like
1185 * Groups: 14 500 513
1191 got
= read(fd
, buf
, BUFSZ
);
1194 c
= *p
++; /* 0 at end of file */
1198 if (key
[matched
] == c
) {
1199 if (!key
[++matched
])
1208 if ((c
>= '0') && (c
<= '9')) {
1212 if ((c
!= ' ') && (c
!= '\t'))
1216 if ((c
>= '0') && (c
<= '9'))
1217 grp
= grp
*10 + c
- '0';
1219 ismember
= (grp
== gid
);
1220 if ((c
!= ' ') && (c
!= '\t'))
1228 } while (!ismember
&& c
&& (state
!= INEND
));
1231 ntfs_log_error("No group record found in %s\n",filename
);
1233 ntfs_log_error("Could not open %s\n",filename
);
1239 * Cacheing is done two-way :
1240 * - from uid, gid and perm to securid (CACHED_SECURID)
1241 * - from a securid to uid, gid and perm (CACHED_PERMISSIONS)
1243 * CACHED_SECURID data is kept in a most-recent-first list
1244 * which should not be too long to be efficient. Its optimal
1245 * size is depends on usage and is hard to determine.
1247 * CACHED_PERMISSIONS data is kept in a two-level indexed array. It
1248 * is optimal at the expense of storage. Use of a most-recent-first
1249 * list would save memory and provide similar performances for
1250 * standard usage, but not for file servers with too many file
1253 * CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS
1254 * for legacy directories which were not allocated a security_id
1255 * it is organized in a most-recent-first list.
1257 * In main caches, data is never invalidated, as the meaning of
1258 * a security_id only changes when user mapping is changed, which
1259 * current implies remounting. However returned entries may be
1260 * overwritten at next update, so data has to be copied elsewhere
1261 * before another cache update is made.
1262 * In legacy cache, data has to be invalidated when protection is
1265 * Though the same data may be found in both list, they
1266 * must be kept separately : the interpretation of ACL
1267 * in both direction are approximations which could be non
1268 * reciprocal for some configuration of the user mapping data
1270 * During the process of recompiling ntfs-3g from a tgz archive,
1271 * security processing added 7.6% to the cpu time used by ntfs-3g
1272 * and 30% if the cache is disabled.
1275 static struct PERMISSIONS_CACHE
*create_caches(struct SECURITY_CONTEXT
*scx
,
1278 struct PERMISSIONS_CACHE
*cache
;
1279 unsigned int index1
;
1282 cache
= (struct PERMISSIONS_CACHE
*)NULL
;
1283 /* create the first permissions blocks */
1284 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1285 cache
= (struct PERMISSIONS_CACHE
*)
1286 ntfs_malloc(sizeof(struct PERMISSIONS_CACHE
)
1287 + index1
*sizeof(struct CACHED_PERMISSIONS
*));
1289 cache
->head
.last
= index1
;
1290 cache
->head
.p_reads
= 0;
1291 cache
->head
.p_hits
= 0;
1292 cache
->head
.p_writes
= 0;
1293 *scx
->pseccache
= cache
;
1294 for (i
=0; i
<=index1
; i
++)
1295 cache
->cachetable
[i
]
1296 = (struct CACHED_PERMISSIONS
*)NULL
;
1302 * Free memory used by caches
1303 * The only purpose is to facilitate the detection of memory leaks
1306 static void free_caches(struct SECURITY_CONTEXT
*scx
)
1308 unsigned int index1
;
1309 struct PERMISSIONS_CACHE
*pseccache
;
1311 pseccache
= *scx
->pseccache
;
1313 for (index1
=0; index1
<=pseccache
->head
.last
; index1
++)
1314 if (pseccache
->cachetable
[index1
]) {
1316 struct CACHED_PERMISSIONS
*cacheentry
;
1317 unsigned int index2
;
1319 for (index2
=0; index2
<(1<< CACHE_PERMISSIONS_BITS
); index2
++) {
1320 cacheentry
= &pseccache
->cachetable
[index1
][index2
];
1321 if (cacheentry
->valid
1322 && cacheentry
->pxdesc
)
1323 free(cacheentry
->pxdesc
);
1326 free(pseccache
->cachetable
[index1
]);
1332 static int compare(const struct CACHED_SECURID
*cached
,
1333 const struct CACHED_SECURID
*item
)
1339 /* only compare data and sizes */
1340 csize
= (cached
->variable
?
1341 sizeof(struct POSIX_ACL
)
1342 + (((struct POSIX_SECURITY
*)cached
->variable
)->acccnt
1343 + ((struct POSIX_SECURITY
*)cached
->variable
)->defcnt
)
1344 *sizeof(struct POSIX_ACE
) :
1346 isize
= (item
->variable
?
1347 sizeof(struct POSIX_ACL
)
1348 + (((struct POSIX_SECURITY
*)item
->variable
)->acccnt
1349 + ((struct POSIX_SECURITY
*)item
->variable
)->defcnt
)
1350 *sizeof(struct POSIX_ACE
) :
1352 return ((cached
->uid
!= item
->uid
)
1353 || (cached
->gid
!= item
->gid
)
1354 || (cached
->dmode
!= item
->dmode
)
1358 && memcmp(&((struct POSIX_SECURITY
*)cached
->variable
)->acl
,
1359 &((struct POSIX_SECURITY
*)item
->variable
)->acl
, csize
)));
1361 return ((cached
->uid
!= item
->uid
)
1362 || (cached
->gid
!= item
->gid
)
1363 || (cached
->dmode
!= item
->dmode
));
1367 static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY
*cached
,
1368 const struct CACHED_PERMISSIONS_LEGACY
*item
)
1370 return (cached
->mft_no
!= item
->mft_no
);
1374 * Resize permission cache table
1375 * do not call unless resizing is needed
1377 * If allocation fails, the cache size is not updated
1378 * Lack of memory is not considered as an error, the cache is left
1379 * consistent and errno is not set.
1382 static void resize_cache(struct SECURITY_CONTEXT
*scx
,
1385 struct PERMISSIONS_CACHE
*oldcache
;
1386 struct PERMISSIONS_CACHE
*newcache
;
1389 unsigned int index1
;
1392 oldcache
= *scx
->pseccache
;
1393 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1394 newcnt
= index1
+ 1;
1395 if (newcnt
<= ((CACHE_PERMISSIONS_SIZE
1396 + (1 << CACHE_PERMISSIONS_BITS
)
1397 - 1) >> CACHE_PERMISSIONS_BITS
)) {
1398 /* expand cache beyond current end, do not use realloc() */
1399 /* to avoid losing data when there is no more memory */
1400 oldcnt
= oldcache
->head
.last
+ 1;
1401 newcache
= (struct PERMISSIONS_CACHE
*)
1403 sizeof(struct PERMISSIONS_CACHE
)
1404 + (newcnt
- 1)*sizeof(struct CACHED_PERMISSIONS
*));
1406 memcpy(newcache
,oldcache
,
1407 sizeof(struct PERMISSIONS_CACHE
)
1408 + (oldcnt
- 1)*sizeof(struct CACHED_PERMISSIONS
*));
1410 /* mark new entries as not valid */
1411 for (i
=newcache
->head
.last
+1; i
<=index1
; i
++)
1412 newcache
->cachetable
[i
]
1413 = (struct CACHED_PERMISSIONS
*)NULL
;
1414 newcache
->head
.last
= index1
;
1415 *scx
->pseccache
= newcache
;
1421 * Enter uid, gid and mode into cache, if possible
1423 * returns the updated or created cache entry,
1424 * or NULL if not possible (typically if there is no
1425 * security id associated)
1429 static struct CACHED_PERMISSIONS
*enter_cache(struct SECURITY_CONTEXT
*scx
,
1430 ntfs_inode
*ni
, uid_t uid
, gid_t gid
,
1431 struct POSIX_SECURITY
*pxdesc
)
1433 static struct CACHED_PERMISSIONS
*enter_cache(struct SECURITY_CONTEXT
*scx
,
1434 ntfs_inode
*ni
, uid_t uid
, gid_t gid
, mode_t mode
)
1437 struct CACHED_PERMISSIONS
*cacheentry
;
1438 struct CACHED_PERMISSIONS
*cacheblock
;
1439 struct PERMISSIONS_CACHE
*pcache
;
1443 struct POSIX_SECURITY
*pxcached
;
1445 unsigned int index1
;
1446 unsigned int index2
;
1449 /* cacheing is only possible if a security_id has been defined */
1450 if (test_nino_flag(ni
, v3_Extensions
)
1451 && ni
->security_id
) {
1453 * Immediately test the most frequent situation
1454 * where the entry exists
1456 securindex
= le32_to_cpu(ni
->security_id
);
1457 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1458 index2
= securindex
& ((1 << CACHE_PERMISSIONS_BITS
) - 1);
1459 pcache
= *scx
->pseccache
;
1461 && (pcache
->head
.last
>= index1
)
1462 && pcache
->cachetable
[index1
]) {
1463 cacheentry
= &pcache
->cachetable
[index1
][index2
];
1464 cacheentry
->uid
= uid
;
1465 cacheentry
->gid
= gid
;
1467 if (cacheentry
->valid
&& cacheentry
->pxdesc
)
1468 free(cacheentry
->pxdesc
);
1470 pxsize
= sizeof(struct POSIX_SECURITY
)
1471 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1472 pxcached
= (struct POSIX_SECURITY
*)malloc(pxsize
);
1474 memcpy(pxcached
, pxdesc
, pxsize
);
1475 cacheentry
->pxdesc
= pxcached
;
1477 cacheentry
->valid
= 0;
1478 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1480 cacheentry
->mode
= pxdesc
->mode
& 07777;
1482 cacheentry
->pxdesc
= (struct POSIX_SECURITY
*)NULL
;
1484 cacheentry
->mode
= mode
& 07777;
1486 cacheentry
->inh_fileid
= const_cpu_to_le32(0);
1487 cacheentry
->inh_dirid
= const_cpu_to_le32(0);
1488 cacheentry
->valid
= 1;
1489 pcache
->head
.p_writes
++;
1492 /* create the first cache block */
1493 pcache
= create_caches(scx
, securindex
);
1495 if (index1
> pcache
->head
.last
) {
1496 resize_cache(scx
, securindex
);
1497 pcache
= *scx
->pseccache
;
1500 /* allocate block, if cache table was allocated */
1501 if (pcache
&& (index1
<= pcache
->head
.last
)) {
1502 cacheblock
= (struct CACHED_PERMISSIONS
*)
1503 malloc(sizeof(struct CACHED_PERMISSIONS
)
1504 << CACHE_PERMISSIONS_BITS
);
1505 pcache
->cachetable
[index1
] = cacheblock
;
1506 for (i
=0; i
<(1 << CACHE_PERMISSIONS_BITS
); i
++)
1507 cacheblock
[i
].valid
= 0;
1508 cacheentry
= &cacheblock
[index2
];
1510 cacheentry
->uid
= uid
;
1511 cacheentry
->gid
= gid
;
1514 pxsize
= sizeof(struct POSIX_SECURITY
)
1515 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1516 pxcached
= (struct POSIX_SECURITY
*)malloc(pxsize
);
1518 memcpy(pxcached
, pxdesc
, pxsize
);
1519 cacheentry
->pxdesc
= pxcached
;
1521 cacheentry
->valid
= 0;
1522 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1524 cacheentry
->mode
= pxdesc
->mode
& 07777;
1526 cacheentry
->pxdesc
= (struct POSIX_SECURITY
*)NULL
;
1528 cacheentry
->mode
= mode
& 07777;
1530 cacheentry
->inh_fileid
= const_cpu_to_le32(0);
1531 cacheentry
->inh_dirid
= const_cpu_to_le32(0);
1532 cacheentry
->valid
= 1;
1533 pcache
->head
.p_writes
++;
1536 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1539 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1540 #if CACHE_LEGACY_SIZE
1541 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
1542 struct CACHED_PERMISSIONS_LEGACY wanted
;
1543 struct CACHED_PERMISSIONS_LEGACY
*legacy
;
1545 wanted
.perm
.uid
= uid
;
1546 wanted
.perm
.gid
= gid
;
1548 wanted
.perm
.mode
= pxdesc
->mode
& 07777;
1549 wanted
.perm
.inh_fileid
= const_cpu_to_le32(0);
1550 wanted
.perm
.inh_dirid
= const_cpu_to_le32(0);
1551 wanted
.mft_no
= ni
->mft_no
;
1552 wanted
.variable
= (void*)pxdesc
;
1553 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
1554 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1556 wanted
.perm
.mode
= mode
& 07777;
1557 wanted
.perm
.inh_fileid
= const_cpu_to_le32(0);
1558 wanted
.perm
.inh_dirid
= const_cpu_to_le32(0);
1559 wanted
.mft_no
= ni
->mft_no
;
1560 wanted
.variable
= (void*)NULL
;
1563 legacy
= (struct CACHED_PERMISSIONS_LEGACY
*)ntfs_enter_cache(
1564 scx
->vol
->legacy_cache
, GENERIC(&wanted
),
1565 (cache_compare
)leg_compare
);
1567 cacheentry
= &legacy
->perm
;
1570 * give direct access to the cached pxdesc
1571 * in the permissions structure
1573 cacheentry
->pxdesc
= legacy
->variable
;
1579 return (cacheentry
);
1583 * Fetch owner, group and permission of a file, if cached
1585 * Beware : do not use the returned entry after a cache update :
1586 * the cache may be relocated making the returned entry meaningless
1588 * returns the cache entry, or NULL if not available
1591 static struct CACHED_PERMISSIONS
*fetch_cache(struct SECURITY_CONTEXT
*scx
,
1594 struct CACHED_PERMISSIONS
*cacheentry
;
1595 struct PERMISSIONS_CACHE
*pcache
;
1597 unsigned int index1
;
1598 unsigned int index2
;
1600 /* cacheing is only possible if a security_id has been defined */
1601 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1602 if (test_nino_flag(ni
, v3_Extensions
)
1603 && (ni
->security_id
)) {
1604 securindex
= le32_to_cpu(ni
->security_id
);
1605 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1606 index2
= securindex
& ((1 << CACHE_PERMISSIONS_BITS
) - 1);
1607 pcache
= *scx
->pseccache
;
1609 && (pcache
->head
.last
>= index1
)
1610 && pcache
->cachetable
[index1
]) {
1611 cacheentry
= &pcache
->cachetable
[index1
][index2
];
1612 /* reject if entry is not valid */
1613 if (!cacheentry
->valid
)
1614 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1616 pcache
->head
.p_hits
++;
1618 pcache
->head
.p_reads
++;
1621 #if CACHE_LEGACY_SIZE
1623 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1624 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
1625 struct CACHED_PERMISSIONS_LEGACY wanted
;
1626 struct CACHED_PERMISSIONS_LEGACY
*legacy
;
1628 wanted
.mft_no
= ni
->mft_no
;
1629 wanted
.variable
= (void*)NULL
;
1631 legacy
= (struct CACHED_PERMISSIONS_LEGACY
*)ntfs_fetch_cache(
1632 scx
->vol
->legacy_cache
, GENERIC(&wanted
),
1633 (cache_compare
)leg_compare
);
1634 if (legacy
) cacheentry
= &legacy
->perm
;
1639 if (cacheentry
&& !cacheentry
->pxdesc
) {
1640 ntfs_log_error("No Posix descriptor in cache\n");
1641 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1644 return (cacheentry
);
1648 * Retrieve a security attribute from $Secure
1651 static char *retrievesecurityattr(ntfs_volume
*vol
, SII_INDEX_KEY id
)
1666 ntfs_index_context
*xsii
;
1669 securattr
= (char*)NULL
;
1670 ni
= vol
->secure_ni
;
1671 xsii
= vol
->secure_xsii
;
1673 ntfs_index_ctx_reinit(xsii
);
1675 !ntfs_index_lookup((char*)&id
,
1676 sizeof(SII_INDEX_KEY
), xsii
);
1678 psii
= (struct SII
*)xsii
->entry
;
1680 (size_t) le32_to_cpu(psii
->datasize
)
1681 - sizeof(SECURITY_DESCRIPTOR_HEADER
);
1682 /* work around bad alignment problem */
1683 realign
.parts
.dataoffsh
= psii
->dataoffsh
;
1684 realign
.parts
.dataoffsl
= psii
->dataoffsl
;
1685 offs
= le64_to_cpu(realign
.all
)
1686 + sizeof(SECURITY_DESCRIPTOR_HEADER
);
1688 securattr
= (char*)ntfs_malloc(size
);
1690 rdsize
= ntfs_attr_data_read(
1692 securattr
, size
, offs
);
1693 if ((rdsize
!= size
)
1694 || !ntfs_valid_descr(securattr
,
1696 /* error to be logged by caller */
1698 securattr
= (char*)NULL
;
1702 if (errno
!= ENOENT
)
1703 ntfs_log_perror("Inconsistency in index $SII");
1706 ntfs_log_error("Failed to retrieve a security descriptor\n");
1713 * Get the security descriptor associated to a file
1716 * - read the security descriptor attribute (v1.x format)
1717 * - or find the descriptor in $Secure:$SDS (v3.x format)
1719 * in both case, sanity checks are done on the attribute and
1720 * the descriptor can be assumed safe
1722 * The returned descriptor is dynamically allocated and has to be freed
1725 static char *getsecurityattr(ntfs_volume
*vol
, ntfs_inode
*ni
)
1727 SII_INDEX_KEY securid
;
1732 * Warning : in some situations, after fixing by chkdsk,
1733 * v3_Extensions are marked present (long standard informations)
1734 * with a default security descriptor inserted in an
1737 if (test_nino_flag(ni
, v3_Extensions
)
1738 && vol
->secure_ni
&& ni
->security_id
) {
1739 /* get v3.x descriptor in $Secure */
1740 securid
.security_id
= ni
->security_id
;
1741 securattr
= retrievesecurityattr(vol
,securid
);
1743 ntfs_log_error("Bad security descriptor for 0x%lx\n",
1744 (long)le32_to_cpu(ni
->security_id
));
1746 /* get v1.x security attribute */
1748 securattr
= ntfs_attr_readall(ni
, AT_SECURITY_DESCRIPTOR
,
1749 AT_UNNAMED
, 0, &readallsz
);
1750 if (securattr
&& !ntfs_valid_descr(securattr
, readallsz
)) {
1751 ntfs_log_error("Bad security descriptor for inode %lld\n",
1752 (long long)ni
->mft_no
);
1754 securattr
= (char*)NULL
;
1759 * in some situations, there is no security
1760 * descriptor, and chkdsk does not detect or fix
1761 * anything. This could be a normal situation.
1762 * When this happens, simulate a descriptor with
1763 * minimum rights, so that a real descriptor can
1764 * be created by chown or chmod
1766 ntfs_log_error("No security descriptor found for inode %lld\n",
1767 (long long)ni
->mft_no
);
1768 securattr
= ntfs_build_descr(0, 0, adminsid
, adminsid
);
1776 * Determine which access types to a file are allowed
1777 * according to the relation of current process to the file
1779 * Do not call if default_permissions is set
1782 static int access_check_posix(struct SECURITY_CONTEXT
*scx
,
1783 struct POSIX_SECURITY
*pxdesc
, mode_t request
,
1784 uid_t uid
, gid_t gid
)
1786 struct POSIX_ACE
*pxace
;
1795 perms
= pxdesc
->mode
;
1796 /* owner and root access */
1797 if (!scx
->uid
|| (uid
== scx
->uid
)) {
1799 /* root access if owner or other execution */
1803 /* root access if some group execution */
1806 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1807 pxace
= &pxdesc
->acl
.ace
[i
];
1808 switch (pxace
->tag
) {
1809 case POSIX_ACL_USER_OBJ
:
1810 case POSIX_ACL_GROUP_OBJ
:
1811 case POSIX_ACL_GROUP
:
1812 groupperms
|= pxace
->perms
;
1814 case POSIX_ACL_MASK
:
1815 mask
= pxace
->perms
& 7;
1821 perms
= (groupperms
& mask
& 1) | 6;
1827 * analyze designated users, get mask
1828 * and identify whether we need to check
1829 * the group memberships. The groups are
1830 * not needed when all groups have the
1831 * same permissions as other for the
1838 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1839 pxace
= &pxdesc
->acl
.ace
[i
];
1840 switch (pxace
->tag
) {
1841 case POSIX_ACL_USER
:
1842 if ((uid_t
)pxace
->id
== scx
->uid
)
1843 userperms
= pxace
->perms
;
1845 case POSIX_ACL_MASK
:
1846 mask
= pxace
->perms
& 7;
1848 case POSIX_ACL_GROUP_OBJ
:
1849 case POSIX_ACL_GROUP
:
1850 if (((pxace
->perms
& mask
) ^ perms
)
1851 & (request
>> 6) & 7)
1858 /* designated users */
1860 perms
= (perms
& 07000) + (userperms
& mask
);
1861 else if (!needgroups
)
1865 if (!(~(perms
>> 3) & request
& mask
)
1866 && ((gid
== scx
->gid
)
1867 || groupmember(scx
, scx
->uid
, gid
)))
1873 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1874 pxace
= &pxdesc
->acl
.ace
[i
];
1875 if ((pxace
->tag
== POSIX_ACL_GROUP
)
1876 && groupmember(scx
, uid
, pxace
->id
)) {
1877 if (!(~pxace
->perms
& request
& mask
))
1878 groupperms
= pxace
->perms
;
1882 if (groupperms
>= 0)
1883 perms
= (perms
& 07000) + (groupperms
& mask
);
1896 * Get permissions to access a file
1897 * Takes into account the relation of user to file (owner, group, ...)
1898 * Do no use as mode of the file
1899 * Do no call if default_permissions is set
1901 * returns -1 if there is a problem
1904 static int ntfs_get_perm(struct SECURITY_CONTEXT
*scx
,
1905 ntfs_inode
* ni
, mode_t request
)
1907 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
1908 const struct CACHED_PERMISSIONS
*cached
;
1910 const SID
*usid
; /* owner of file/directory */
1911 const SID
*gsid
; /* group of file/directory */
1916 struct POSIX_SECURITY
*pxdesc
;
1918 if (!scx
->mapping
[MAPUSERS
])
1921 /* check whether available in cache */
1922 cached
= fetch_cache(scx
,ni
);
1926 perm
= access_check_posix(scx
,cached
->pxdesc
,request
,uid
,gid
);
1928 perm
= 0; /* default to no permission */
1929 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
1930 != const_cpu_to_le16(0);
1931 securattr
= getsecurityattr(scx
->vol
, ni
);
1933 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
1935 gsid
= (const SID
*)&
1936 securattr
[le32_to_cpu(phead
->group
)];
1937 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
1939 usid
= ntfs_acl_owner(securattr
);
1940 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
1943 perm
= pxdesc
->mode
& 07777;
1946 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
1948 usid
= (const SID
*)&
1949 securattr
[le32_to_cpu(phead
->owner
)];
1950 pxdesc
= ntfs_build_permissions_posix(scx
,securattr
,
1953 perm
= pxdesc
->mode
& 07777;
1956 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
1957 uid
= find_tenant(scx
, securattr
);
1961 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
1964 * Create a security id if there were none
1965 * and upgrade option is selected
1967 if (!test_nino_flag(ni
, v3_Extensions
)
1969 && (scx
->vol
->secure_flags
1970 & (1 << SECURITY_ADDSECURIDS
))) {
1971 upgrade_secur_desc(scx
->vol
,
1974 * fetch owner and group for cacheing
1975 * if there is a securid
1978 if (test_nino_flag(ni
, v3_Extensions
)
1980 enter_cache(scx
, ni
, uid
,
1984 perm
= access_check_posix(scx
,pxdesc
,request
,uid
,gid
);
2000 * returns size or -errno if there is a problem
2001 * if size was too small, no copy is done and errno is not set,
2002 * the caller is expected to issue a new call
2005 int ntfs_get_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2006 const char *name
, char *value
, size_t size
)
2008 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2009 struct POSIX_SECURITY
*pxdesc
;
2010 const struct CACHED_PERMISSIONS
*cached
;
2012 const SID
*usid
; /* owner of file/directory */
2013 const SID
*gsid
; /* group of file/directory */
2020 outsize
= 0; /* default to error */
2021 if (!scx
->mapping
[MAPUSERS
])
2024 /* check whether available in cache */
2025 cached
= fetch_cache(scx
,ni
);
2027 pxdesc
= cached
->pxdesc
;
2029 securattr
= getsecurityattr(scx
->vol
, ni
);
2030 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2031 != const_cpu_to_le16(0);
2034 (const SECURITY_DESCRIPTOR_RELATIVE
*)
2036 gsid
= (const SID
*)&
2037 securattr
[le32_to_cpu(phead
->group
)];
2039 usid
= ntfs_acl_owner(securattr
);
2041 usid
= (const SID
*)&
2042 securattr
[le32_to_cpu(phead
->owner
)];
2044 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2048 * fetch owner and group for cacheing
2051 perm
= pxdesc
->mode
& 07777;
2053 * Create a security id if there were none
2054 * and upgrade option is selected
2056 if (!test_nino_flag(ni
, v3_Extensions
)
2057 && (scx
->vol
->secure_flags
2058 & (1 << SECURITY_ADDSECURIDS
))) {
2059 upgrade_secur_desc(scx
->vol
,
2063 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2065 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2066 uid
= find_tenant(scx
,
2071 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2073 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2074 if (pxdesc
->tagsset
& POSIX_ACL_EXTENSIONS
)
2075 enter_cache(scx
, ni
, uid
,
2080 pxdesc
= (struct POSIX_SECURITY
*)NULL
;
2084 if (ntfs_valid_posix(pxdesc
)) {
2085 if (!strcmp(name
,"system.posix_acl_default")) {
2087 & MFT_RECORD_IS_DIRECTORY
)
2088 outsize
= sizeof(struct POSIX_ACL
)
2089 + pxdesc
->defcnt
*sizeof(struct POSIX_ACE
);
2092 * getting default ACL from plain file :
2093 * return EACCES if size > 0 as
2094 * indicated in the man, but return ok
2095 * if size == 0, so that ls does not
2102 outsize
= sizeof(struct POSIX_ACL
);
2104 if (outsize
&& (outsize
<= size
)) {
2105 memcpy(value
,&pxdesc
->acl
,sizeof(struct POSIX_ACL
));
2106 memcpy(&value
[sizeof(struct POSIX_ACL
)],
2107 &pxdesc
->acl
.ace
[pxdesc
->firstdef
],
2108 outsize
-sizeof(struct POSIX_ACL
));
2111 outsize
= sizeof(struct POSIX_ACL
)
2112 + pxdesc
->acccnt
*sizeof(struct POSIX_ACE
);
2113 if (outsize
<= size
)
2114 memcpy(value
,&pxdesc
->acl
,outsize
);
2119 ntfs_log_error("Invalid Posix ACL built\n");
2126 return (outsize
? (int)outsize
: -errno
);
2129 #else /* POSIXACLS */
2133 * Get permissions to access a file
2134 * Takes into account the relation of user to file (owner, group, ...)
2135 * Do no use as mode of the file
2137 * returns -1 if there is a problem
2140 static int ntfs_get_perm(struct SECURITY_CONTEXT
*scx
,
2141 ntfs_inode
*ni
, mode_t request
)
2143 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2144 const struct CACHED_PERMISSIONS
*cached
;
2146 const SID
*usid
; /* owner of file/directory */
2147 const SID
*gsid
; /* group of file/directory */
2153 if (!scx
->mapping
[MAPUSERS
] || (!scx
->uid
&& !(request
& S_IEXEC
)))
2156 /* check whether available in cache */
2157 cached
= fetch_cache(scx
,ni
);
2159 perm
= cached
->mode
;
2163 perm
= 0; /* default to no permission */
2164 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2165 != const_cpu_to_le16(0);
2166 securattr
= getsecurityattr(scx
->vol
, ni
);
2168 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2170 gsid
= (const SID
*)&
2171 securattr
[le32_to_cpu(phead
->group
)];
2172 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2174 usid
= ntfs_acl_owner(securattr
);
2175 perm
= ntfs_build_permissions(securattr
,
2177 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2179 usid
= (const SID
*)&
2180 securattr
[le32_to_cpu(phead
->owner
)];
2181 perm
= ntfs_build_permissions(securattr
,
2183 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2184 uid
= find_tenant(scx
, securattr
);
2188 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2191 * Create a security id if there were none
2192 * and upgrade option is selected
2194 if (!test_nino_flag(ni
, v3_Extensions
)
2196 && (scx
->vol
->secure_flags
2197 & (1 << SECURITY_ADDSECURIDS
))) {
2198 upgrade_secur_desc(scx
->vol
,
2201 * fetch owner and group for cacheing
2202 * if there is a securid
2205 if (test_nino_flag(ni
, v3_Extensions
)
2207 enter_cache(scx
, ni
, uid
,
2218 /* root access and execution */
2224 if (uid
== scx
->uid
)
2228 * avoid checking group membership
2229 * when the requested perms for group
2230 * are the same as perms for other
2232 if ((gid
== scx
->gid
)
2233 || ((((perm
>> 3) ^ perm
)
2234 & (request
>> 6) & 7)
2235 && groupmember(scx
, scx
->uid
, gid
)))
2244 #endif /* POSIXACLS */
2249 * Returns size or -errno if there is a problem
2250 * if size was too small, no copy is done and errno is not set,
2251 * the caller is expected to issue a new call
2254 int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2255 char *value
, size_t size
)
2260 outsize
= 0; /* default to no data and no error */
2261 securattr
= getsecurityattr(scx
->vol
, ni
);
2263 outsize
= ntfs_attr_size(securattr
);
2264 if (outsize
<= size
) {
2265 memcpy(value
,securattr
,outsize
);
2269 return (outsize
? (int)outsize
: -errno
);
2273 * Get owner, group and permissions in an stat structure
2274 * returns permissions, or -1 if there is a problem
2277 int ntfs_get_owner_mode(struct SECURITY_CONTEXT
*scx
,
2278 ntfs_inode
* ni
, struct stat
*stbuf
)
2280 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2282 const SID
*usid
; /* owner of file/directory */
2283 const SID
*gsid
; /* group of file/directory */
2284 const struct CACHED_PERMISSIONS
*cached
;
2288 struct POSIX_SECURITY
*pxdesc
;
2291 if (!scx
->mapping
[MAPUSERS
])
2294 /* check whether available in cache */
2295 cached
= fetch_cache(scx
,ni
);
2297 perm
= cached
->mode
;
2298 stbuf
->st_uid
= cached
->uid
;
2299 stbuf
->st_gid
= cached
->gid
;
2300 stbuf
->st_mode
= (stbuf
->st_mode
& ~07777) + perm
;
2302 perm
= -1; /* default to error */
2303 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2304 != const_cpu_to_le16(0);
2305 securattr
= getsecurityattr(scx
->vol
, ni
);
2308 (const SECURITY_DESCRIPTOR_RELATIVE
*)
2310 gsid
= (const SID
*)&
2311 securattr
[le32_to_cpu(phead
->group
)];
2313 usid
= ntfs_acl_owner(securattr
);
2315 usid
= (const SID
*)&
2316 securattr
[le32_to_cpu(phead
->owner
)];
2319 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
, securattr
,
2322 perm
= pxdesc
->mode
& 07777;
2326 perm
= ntfs_build_permissions(securattr
,
2330 * fetch owner and group for cacheing
2334 * Create a security id if there were none
2335 * and upgrade option is selected
2337 if (!test_nino_flag(ni
, v3_Extensions
)
2338 && (scx
->vol
->secure_flags
2339 & (1 << SECURITY_ADDSECURIDS
))) {
2340 upgrade_secur_desc(scx
->vol
,
2344 stbuf
->st_uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2346 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2353 stbuf
->st_uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2355 stbuf
->st_gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2357 (stbuf
->st_mode
& ~07777) + perm
;
2359 enter_cache(scx
, ni
, stbuf
->st_uid
,
2360 stbuf
->st_gid
, pxdesc
);
2363 enter_cache(scx
, ni
, stbuf
->st_uid
,
2364 stbuf
->st_gid
, perm
);
2377 * Get the base for a Posix inheritance and
2378 * build an inherited Posix descriptor
2381 static struct POSIX_SECURITY
*inherit_posix(struct SECURITY_CONTEXT
*scx
,
2382 ntfs_inode
*dir_ni
, mode_t mode
, BOOL isdir
)
2384 const struct CACHED_PERMISSIONS
*cached
;
2385 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2386 struct POSIX_SECURITY
*pxdesc
;
2387 struct POSIX_SECURITY
*pydesc
;
2394 pydesc
= (struct POSIX_SECURITY
*)NULL
;
2395 /* check whether parent directory is available in cache */
2396 cached
= fetch_cache(scx
,dir_ni
);
2400 pxdesc
= cached
->pxdesc
;
2402 pydesc
= ntfs_build_inherited_posix(pxdesc
,mode
,
2406 securattr
= getsecurityattr(scx
->vol
, dir_ni
);
2408 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2410 gsid
= (const SID
*)&
2411 securattr
[le32_to_cpu(phead
->group
)];
2412 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2414 usid
= ntfs_acl_owner(securattr
);
2415 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2417 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2419 usid
= (const SID
*)&
2420 securattr
[le32_to_cpu(phead
->owner
)];
2421 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2423 if (pxdesc
&& ntfs_same_sid(usid
, adminsid
)) {
2424 uid
= find_tenant(scx
, securattr
);
2426 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2430 * Create a security id if there were none
2431 * and upgrade option is selected
2433 if (!test_nino_flag(dir_ni
, v3_Extensions
)
2434 && (scx
->vol
->secure_flags
2435 & (1 << SECURITY_ADDSECURIDS
))) {
2436 upgrade_secur_desc(scx
->vol
,
2439 * fetch owner and group for cacheing
2440 * if there is a securid
2443 if (test_nino_flag(dir_ni
, v3_Extensions
)) {
2444 enter_cache(scx
, dir_ni
, uid
,
2447 pydesc
= ntfs_build_inherited_posix(pxdesc
,
2448 mode
, scx
->umask
, isdir
);
2458 * Allocate a security_id for a file being created
2460 * Returns zero if not possible (NTFS v3.x required)
2463 le32
ntfs_alloc_securid(struct SECURITY_CONTEXT
*scx
,
2464 uid_t uid
, gid_t gid
, ntfs_inode
*dir_ni
,
2465 mode_t mode
, BOOL isdir
)
2467 #if !FORCE_FORMAT_v1x
2468 const struct CACHED_SECURID
*cached
;
2469 struct CACHED_SECURID wanted
;
2470 struct POSIX_SECURITY
*pxdesc
;
2480 securid
= const_cpu_to_le32(0);
2482 #if !FORCE_FORMAT_v1x
2484 pxdesc
= inherit_posix(scx
, dir_ni
, mode
, isdir
);
2486 /* check whether target securid is known in cache */
2490 wanted
.dmode
= pxdesc
->mode
& mode
& 07777;
2491 if (isdir
) wanted
.dmode
|= 0x10000;
2492 wanted
.variable
= (void*)pxdesc
;
2493 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
2494 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2495 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2496 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2497 (cache_compare
)compare
);
2498 /* quite simple, if we are lucky */
2500 securid
= cached
->securid
;
2502 /* not in cache : make sure we can create ids */
2504 if (!cached
&& (scx
->vol
->major_ver
>= 3)) {
2505 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2506 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2507 if (!usid
|| !gsid
) {
2508 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2509 (int)uid
, (int)gid
);
2510 usid
= gsid
= adminsid
;
2512 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2515 newattrsz
= ntfs_attr_size(newattr
);
2516 securid
= setsecurityattr(scx
->vol
,
2517 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
2520 /* update cache, for subsequent use */
2521 wanted
.securid
= securid
;
2522 ntfs_enter_cache(scx
->vol
->securid_cache
,
2524 (cache_compare
)compare
);
2529 * could not build new security attribute
2530 * errno set by ntfs_build_descr()
2541 * Apply Posix inheritance to a newly created file
2542 * (for NTFS 1.x only : no securid)
2545 int ntfs_set_inherited_posix(struct SECURITY_CONTEXT
*scx
,
2546 ntfs_inode
*ni
, uid_t uid
, gid_t gid
,
2547 ntfs_inode
*dir_ni
, mode_t mode
)
2549 struct POSIX_SECURITY
*pxdesc
;
2559 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2560 pxdesc
= inherit_posix(scx
, dir_ni
, mode
, isdir
);
2562 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2563 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2564 if (!usid
|| !gsid
) {
2565 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2566 (int)uid
, (int)gid
);
2567 usid
= gsid
= adminsid
;
2569 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2572 /* Adjust Windows read-only flag */
2573 res
= update_secur_descr(scx
->vol
, newattr
, ni
);
2574 if (!res
&& !isdir
) {
2576 ni
->flags
&= ~FILE_ATTR_READONLY
;
2578 ni
->flags
|= FILE_ATTR_READONLY
;
2580 #if CACHE_LEGACY_SIZE
2581 /* also invalidate legacy cache */
2582 if (isdir
&& !ni
->security_id
) {
2583 struct CACHED_PERMISSIONS_LEGACY legacy
;
2585 legacy
.mft_no
= ni
->mft_no
;
2586 legacy
.variable
= pxdesc
;
2587 legacy
.varsize
= sizeof(struct POSIX_SECURITY
)
2588 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2589 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
2591 (cache_compare
)leg_compare
,0);
2598 * could not build new security attribute
2599 * errno set by ntfs_build_descr()
2608 le32
ntfs_alloc_securid(struct SECURITY_CONTEXT
*scx
,
2609 uid_t uid
, gid_t gid
, mode_t mode
, BOOL isdir
)
2611 #if !FORCE_FORMAT_v1x
2612 const struct CACHED_SECURID
*cached
;
2613 struct CACHED_SECURID wanted
;
2623 securid
= const_cpu_to_le32(0);
2625 #if !FORCE_FORMAT_v1x
2626 /* check whether target securid is known in cache */
2630 wanted
.dmode
= mode
& 07777;
2631 if (isdir
) wanted
.dmode
|= 0x10000;
2632 wanted
.variable
= (void*)NULL
;
2634 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2635 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2636 (cache_compare
)compare
);
2637 /* quite simple, if we are lucky */
2639 securid
= cached
->securid
;
2641 /* not in cache : make sure we can create ids */
2643 if (!cached
&& (scx
->vol
->major_ver
>= 3)) {
2644 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2645 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2646 if (!usid
|| !gsid
) {
2647 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2648 (int)uid
, (int)gid
);
2649 usid
= gsid
= adminsid
;
2651 newattr
= ntfs_build_descr(mode
, isdir
, usid
, gsid
);
2653 newattrsz
= ntfs_attr_size(newattr
);
2654 securid
= setsecurityattr(scx
->vol
,
2655 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
2658 /* update cache, for subsequent use */
2659 wanted
.securid
= securid
;
2660 ntfs_enter_cache(scx
->vol
->securid_cache
,
2662 (cache_compare
)compare
);
2667 * could not build new security attribute
2668 * errno set by ntfs_build_descr()
2679 * Update ownership and mode of a file, reusing an existing
2680 * security descriptor when possible
2682 * Returns zero if successful
2686 int ntfs_set_owner_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2687 uid_t uid
, gid_t gid
, mode_t mode
,
2688 struct POSIX_SECURITY
*pxdesc
)
2690 int ntfs_set_owner_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2691 uid_t uid
, gid_t gid
, mode_t mode
)
2695 const struct CACHED_SECURID
*cached
;
2696 struct CACHED_SECURID wanted
;
2706 /* check whether target securid is known in cache */
2708 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2711 wanted
.dmode
= mode
& 07777;
2712 if (isdir
) wanted
.dmode
|= 0x10000;
2714 wanted
.variable
= (void*)pxdesc
;
2716 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
2717 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2721 wanted
.variable
= (void*)NULL
;
2724 if (test_nino_flag(ni
, v3_Extensions
)) {
2725 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2726 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2727 (cache_compare
)compare
);
2728 /* quite simple, if we are lucky */
2730 ni
->security_id
= cached
->securid
;
2733 } else cached
= (struct CACHED_SECURID
*)NULL
;
2737 * Do not use usid and gsid from former attributes,
2738 * but recompute them to get repeatable results
2739 * which can be kept in cache.
2741 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2742 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2743 if (!usid
|| !gsid
) {
2744 ntfs_log_error("File made owned by an unmapped user/group %d/%d\n",
2746 usid
= gsid
= adminsid
;
2750 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2753 newattr
= ntfs_build_descr(mode
,
2756 newattr
= ntfs_build_descr(mode
,
2760 res
= update_secur_descr(scx
->vol
, newattr
, ni
);
2762 /* adjust Windows read-only flag */
2765 ni
->flags
&= ~FILE_ATTR_READONLY
;
2767 ni
->flags
|= FILE_ATTR_READONLY
;
2768 NInoFileNameSetDirty(ni
);
2770 /* update cache, for subsequent use */
2771 if (test_nino_flag(ni
, v3_Extensions
)) {
2772 wanted
.securid
= ni
->security_id
;
2773 ntfs_enter_cache(scx
->vol
->securid_cache
,
2775 (cache_compare
)compare
);
2777 #if CACHE_LEGACY_SIZE
2778 /* also invalidate legacy cache */
2779 if (isdir
&& !ni
->security_id
) {
2780 struct CACHED_PERMISSIONS_LEGACY legacy
;
2782 legacy
.mft_no
= ni
->mft_no
;
2784 legacy
.variable
= wanted
.variable
;
2785 legacy
.varsize
= wanted
.varsize
;
2787 legacy
.variable
= (void*)NULL
;
2790 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
2792 (cache_compare
)leg_compare
,0);
2799 * could not build new security attribute
2800 * errno set by ntfs_build_descr()
2809 * Check whether user has ownership rights on a file
2811 * Returns TRUE if allowed
2812 * if not, errno tells why
2815 BOOL
ntfs_allowed_as_owner(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
)
2817 const struct CACHED_PERMISSIONS
*cached
;
2825 processuid
= scx
->uid
;
2826 /* TODO : use CAP_FOWNER process capability */
2828 * Always allow for root
2829 * Also always allow if no mapping has been defined
2831 if (!scx
->mapping
[MAPUSERS
] || !processuid
)
2834 gotowner
= FALSE
; /* default */
2835 /* get the owner, either from cache or from old attribute */
2836 cached
= fetch_cache(scx
, ni
);
2841 oldattr
= getsecurityattr(scx
->vol
, ni
);
2844 usid
= ntfs_acl_owner(oldattr
);
2846 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2848 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2850 usid
= (const SID
*)&oldattr
2851 [le32_to_cpu(phead
->owner
)];
2853 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],
2861 /* TODO : use CAP_FOWNER process capability */
2862 if (!processuid
|| (processuid
== uid
))
2871 #ifdef HAVE_SETXATTR /* extended attributes interface required */
2876 * Set a new access or default Posix ACL to a file
2877 * (or remove ACL if no input data)
2878 * Validity of input data is checked after merging
2880 * Returns 0, or -1 if there is a problem which errno describes
2883 int ntfs_set_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2884 const char *name
, const char *value
, size_t size
,
2887 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2888 const struct CACHED_PERMISSIONS
*cached
;
2901 struct POSIX_SECURITY
*oldpxdesc
;
2902 struct POSIX_SECURITY
*newpxdesc
;
2904 /* get the current pxsec, either from cache or from old attribute */
2906 deflt
= !strcmp(name
,"system.posix_acl_default");
2908 count
= (size
- sizeof(struct POSIX_ACL
)) / sizeof(struct POSIX_ACE
);
2911 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2912 newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
2914 || (((const struct POSIX_ACL
*)value
)->version
== POSIX_VERSION
))
2915 && (!deflt
|| isdir
|| (!size
&& !value
))) {
2916 cached
= fetch_cache(scx
, ni
);
2920 oldpxdesc
= cached
->pxdesc
;
2922 mode
= oldpxdesc
->mode
;
2923 newpxdesc
= ntfs_replace_acl(oldpxdesc
,
2924 (const struct POSIX_ACL
*)value
,count
,deflt
);
2927 oldattr
= getsecurityattr(scx
->vol
, ni
);
2929 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
2931 usid
= ntfs_acl_owner(oldattr
);
2933 usid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->owner
)];
2935 gsid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->group
)];
2936 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2937 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2938 oldpxdesc
= ntfs_build_permissions_posix(scx
->mapping
,
2939 oldattr
, usid
, gsid
, isdir
);
2942 exist
= oldpxdesc
->defcnt
> 0;
2944 exist
= oldpxdesc
->acccnt
> 3;
2945 if ((exist
&& (flags
& XATTR_CREATE
))
2946 || (!exist
&& (flags
& XATTR_REPLACE
))) {
2947 errno
= (exist
? EEXIST
: ENODATA
);
2949 mode
= oldpxdesc
->mode
;
2950 newpxdesc
= ntfs_replace_acl(oldpxdesc
,
2951 (const struct POSIX_ACL
*)value
,count
,deflt
);
2962 processuid
= scx
->uid
;
2963 /* TODO : use CAP_FOWNER process capability */
2964 if (!processuid
|| (uid
== processuid
)) {
2966 * clear setgid if file group does
2967 * not match process group
2969 if (processuid
&& (gid
!= scx
->gid
)
2970 && !groupmember(scx
, scx
->uid
, gid
)) {
2971 newpxdesc
->mode
&= ~S_ISGID
;
2973 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
2974 newpxdesc
->mode
, newpxdesc
);
2979 return (res
? -1 : 0);
2983 * Remove a default Posix ACL from a file
2985 * Returns 0, or -1 if there is a problem which errno describes
2988 int ntfs_remove_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2991 return (ntfs_set_posix_acl(scx
, ni
, name
,
2992 (const char*)NULL
, 0, 0));
2998 * Set a new NTFS ACL to a file
3000 * Returns 0, or -1 if there is a problem
3003 int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3004 const char *value
, size_t size
, int flags
)
3011 && !(flags
& XATTR_CREATE
)
3012 && ntfs_valid_descr(value
,size
)
3013 && (ntfs_attr_size(value
) == size
)) {
3014 /* need copying in order to write */
3015 attr
= (char*)ntfs_malloc(size
);
3017 memcpy(attr
,value
,size
);
3018 res
= update_secur_descr(scx
->vol
, attr
, ni
);
3020 * No need to invalidate standard caches :
3021 * the relation between a securid and
3022 * the associated protection is unchanged,
3023 * only the relation between a file and
3024 * its securid and protection is changed.
3026 #if CACHE_LEGACY_SIZE
3028 * we must however invalidate the legacy
3029 * cache, which is based on inode numbers.
3030 * For safety, invalidate even if updating
3033 if ((ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3034 && !ni
->security_id
) {
3035 struct CACHED_PERMISSIONS_LEGACY legacy
;
3037 legacy
.mft_no
= ni
->mft_no
;
3038 legacy
.variable
= (char*)NULL
;
3040 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
3042 (cache_compare
)leg_compare
,0);
3050 return (res
? -1 : 0);
3053 #endif /* HAVE_SETXATTR */
3056 * Set new permissions to a file
3057 * Checks user mapping has been defined before request for setting
3059 * rejected if request is not originated by owner or root
3061 * returns 0 on success
3062 * -1 on failure, with errno = EIO
3065 int ntfs_set_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
, mode_t mode
)
3067 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3068 const struct CACHED_PERMISSIONS
*cached
;
3079 const struct POSIX_SECURITY
*oldpxdesc
;
3080 struct POSIX_SECURITY
*newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3083 /* get the current owner, either from cache or from old attribute */
3085 cached
= fetch_cache(scx
, ni
);
3090 oldpxdesc
= cached
->pxdesc
;
3092 /* must copy before merging */
3093 pxsize
= sizeof(struct POSIX_SECURITY
)
3094 + (oldpxdesc
->acccnt
+ oldpxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
3095 newpxdesc
= (struct POSIX_SECURITY
*)malloc(pxsize
);
3097 memcpy(newpxdesc
, oldpxdesc
, pxsize
);
3098 if (ntfs_merge_mode_posix(newpxdesc
, mode
))
3103 newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3106 oldattr
= getsecurityattr(scx
->vol
, ni
);
3108 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
3110 usid
= ntfs_acl_owner(oldattr
);
3112 usid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->owner
)];
3114 gsid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->group
)];
3115 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3116 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3118 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
3119 newpxdesc
= ntfs_build_permissions_posix(scx
->mapping
,
3120 oldattr
, usid
, gsid
, isdir
);
3121 if (!newpxdesc
|| ntfs_merge_mode_posix(newpxdesc
, mode
))
3130 processuid
= scx
->uid
;
3131 /* TODO : use CAP_FOWNER process capability */
3132 if (!processuid
|| (uid
== processuid
)) {
3134 * clear setgid if file group does
3135 * not match process group
3137 if (processuid
&& (gid
!= scx
->gid
)
3138 && !groupmember(scx
, scx
->uid
, gid
))
3142 newpxdesc
->mode
= mode
;
3143 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3146 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3149 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3153 res
= -1; /* neither owner nor root */
3157 * Should not happen : a default descriptor is generated
3158 * by getsecurityattr() when there are none
3160 ntfs_log_error("File has no security descriptor\n");
3165 if (newpxdesc
) free(newpxdesc
);
3167 return (res
? -1 : 0);
3171 * Create a default security descriptor for files whose descriptor
3172 * cannot be inherited
3175 int ntfs_sd_add_everyone(ntfs_inode
*ni
)
3177 /* JPA SECURITY_DESCRIPTOR_ATTR *sd; */
3178 SECURITY_DESCRIPTOR_RELATIVE
*sd
;
3180 ACCESS_ALLOWED_ACE
*ace
;
3184 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
3186 * Calculate security descriptor length. We have 2 sub-authorities in
3187 * owner and group SIDs, but structure SID contain only one, so add
3188 * 4 bytes to every SID.
3190 sd_len
= sizeof(SECURITY_DESCRIPTOR_ATTR
) + 2 * (sizeof(SID
) + 4) +
3191 sizeof(ACL
) + sizeof(ACCESS_ALLOWED_ACE
);
3192 sd
= (SECURITY_DESCRIPTOR_RELATIVE
*)ntfs_calloc(sd_len
);
3196 sd
->revision
= SECURITY_DESCRIPTOR_REVISION
;
3197 sd
->control
= SE_DACL_PRESENT
| SE_SELF_RELATIVE
;
3199 sid
= (SID
*)((u8
*)sd
+ sizeof(SECURITY_DESCRIPTOR_ATTR
));
3200 sid
->revision
= SID_REVISION
;
3201 sid
->sub_authority_count
= 2;
3202 sid
->sub_authority
[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID
);
3203 sid
->sub_authority
[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS
);
3204 sid
->identifier_authority
.value
[5] = 5;
3205 sd
->owner
= cpu_to_le32((u8
*)sid
- (u8
*)sd
);
3207 sid
= (SID
*)((u8
*)sid
+ sizeof(SID
) + 4);
3208 sid
->revision
= SID_REVISION
;
3209 sid
->sub_authority_count
= 2;
3210 sid
->sub_authority
[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID
);
3211 sid
->sub_authority
[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS
);
3212 sid
->identifier_authority
.value
[5] = 5;
3213 sd
->group
= cpu_to_le32((u8
*)sid
- (u8
*)sd
);
3215 acl
= (ACL
*)((u8
*)sid
+ sizeof(SID
) + 4);
3216 acl
->revision
= ACL_REVISION
;
3217 acl
->size
= const_cpu_to_le16(sizeof(ACL
) + sizeof(ACCESS_ALLOWED_ACE
));
3218 acl
->ace_count
= const_cpu_to_le16(1);
3219 sd
->dacl
= cpu_to_le32((u8
*)acl
- (u8
*)sd
);
3221 ace
= (ACCESS_ALLOWED_ACE
*)((u8
*)acl
+ sizeof(ACL
));
3222 ace
->type
= ACCESS_ALLOWED_ACE_TYPE
;
3223 ace
->flags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
;
3224 ace
->size
= const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE
));
3225 ace
->mask
= const_cpu_to_le32(0x1f01ff); /* FIXME */
3226 ace
->sid
.revision
= SID_REVISION
;
3227 ace
->sid
.sub_authority_count
= 1;
3228 ace
->sid
.sub_authority
[0] = const_cpu_to_le32(0);
3229 ace
->sid
.identifier_authority
.value
[5] = 1;
3231 ret
= ntfs_attr_add(ni
, AT_SECURITY_DESCRIPTOR
, AT_UNNAMED
, 0, (u8
*)sd
,
3234 ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR");
3241 * Check whether user can access a file in a specific way
3243 * Returns 1 if access is allowed, including user is root or no
3244 * user mapping defined
3245 * 2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX
3246 * 0 and sets errno if there is a problem or if access
3249 * This is used for Posix ACL and checking creation of DOS file names
3252 int ntfs_allowed_access(struct SECURITY_CONTEXT
*scx
,
3254 int accesstype
) /* access type required (S_Ixxx values) */
3262 * Always allow for root unless execution is requested.
3263 * (was checked by fuse until kernel 2.6.29)
3264 * Also always allow if no mapping has been defined
3266 if (!scx
->mapping
[MAPUSERS
]
3268 && (!(accesstype
& S_IEXEC
)
3269 || (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
))))
3272 perm
= ntfs_get_perm(scx
, ni
, accesstype
);
3275 switch (accesstype
) {
3277 allow
= (perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0;
3280 allow
= (perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0;
3282 case S_IWRITE
+ S_IEXEC
:
3283 allow
= ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3284 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3287 allow
= (perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0;
3289 case S_IREAD
+ S_IEXEC
:
3290 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3291 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3293 case S_IREAD
+ S_IWRITE
:
3294 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3295 && ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0);
3297 case S_IWRITE
+ S_IEXEC
+ S_ISVTX
:
3298 if (perm
& S_ISVTX
) {
3299 if ((ntfs_get_owner_mode(scx
,ni
,&stbuf
) >= 0)
3300 && (stbuf
.st_uid
== scx
->uid
))
3305 allow
= ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3306 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3308 case S_IREAD
+ S_IWRITE
+ S_IEXEC
:
3309 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3310 && ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3311 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3326 #if 0 /* not needed any more */
3329 * Check whether user can access the parent directory
3330 * of a file in a specific way
3332 * Returns true if access is allowed, including user is root and
3333 * no user mapping defined
3335 * Sets errno if there is a problem or if not allowed
3337 * This is used for Posix ACL and checking creation of DOS file names
3340 BOOL
old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT
*scx
,
3341 const char *path
, int accesstype
)
3351 dirpath
= strdup(path
);
3353 /* the root of file system is seen as a parent of itself */
3354 /* is that correct ? */
3355 name
= strrchr(dirpath
, '/');
3357 dir_ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, dirpath
);
3359 allow
= ntfs_allowed_access(scx
,
3360 dir_ni
, accesstype
);
3361 ntfs_inode_close(dir_ni
);
3363 * for an not-owned sticky directory, have to
3364 * check whether file itself is owned
3366 if ((accesstype
== (S_IWRITE
+ S_IEXEC
+ S_ISVTX
))
3368 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
,
3372 allow
= (ntfs_get_owner_mode(scx
,ni
,&stbuf
) >= 0)
3373 && (stbuf
.st_uid
== scx
->uid
);
3374 ntfs_inode_close(ni
);
3380 return (allow
); /* errno is set if not allowed */
3386 * Define a new owner/group to a file
3388 * returns zero if successful
3391 int ntfs_set_owner(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3392 uid_t uid
, gid_t gid
)
3394 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3395 const struct CACHED_PERMISSIONS
*cached
;
3406 struct POSIX_SECURITY
*pxdesc
;
3407 BOOL pxdescbuilt
= FALSE
;
3411 /* get the current owner and mode from cache or security attributes */
3412 oldattr
= (char*)NULL
;
3413 cached
= fetch_cache(scx
,ni
);
3415 fileuid
= cached
->uid
;
3416 filegid
= cached
->gid
;
3417 mode
= cached
->mode
;
3419 pxdesc
= cached
->pxdesc
;
3427 oldattr
= getsecurityattr(scx
->vol
, ni
);
3429 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3430 != const_cpu_to_le16(0);
3431 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
3434 &oldattr
[le32_to_cpu(phead
->group
)];
3436 usid
= ntfs_acl_owner(oldattr
);
3439 &oldattr
[le32_to_cpu(phead
->owner
)];
3442 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
, oldattr
,
3446 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3447 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3448 mode
= perm
= pxdesc
->mode
;
3452 mode
= perm
= ntfs_build_permissions(oldattr
,
3455 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3456 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3465 /* check requested by root */
3466 /* or chgrp requested by owner to an owned group */
3468 || ((((int)uid
< 0) || (uid
== fileuid
))
3469 && ((gid
== scx
->gid
) || groupmember(scx
, scx
->uid
, gid
))
3470 && (fileuid
== scx
->uid
))) {
3471 /* replace by the new usid and gsid */
3472 /* or reuse old gid and sid for cacheing */
3477 /* clear setuid and setgid if owner has changed */
3478 /* unless request originated by root */
3479 if (uid
&& (fileuid
!= uid
))
3482 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3485 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3488 res
= -1; /* neither owner nor root */
3497 * Should not happen : a default descriptor is generated
3498 * by getsecurityattr() when there are none
3500 ntfs_log_error("File has no security descriptor\n");
3504 return (res
? -1 : 0);
3508 * Define new owner/group and mode to a file
3510 * returns zero if successful
3513 int ntfs_set_ownmod(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3514 uid_t uid
, gid_t gid
, const mode_t mode
)
3516 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3517 const struct CACHED_PERMISSIONS
*cached
;
3526 const struct POSIX_SECURITY
*oldpxdesc
;
3527 struct POSIX_SECURITY
*newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3532 /* get the current owner and mode from cache or security attributes */
3533 oldattr
= (char*)NULL
;
3534 cached
= fetch_cache(scx
,ni
);
3536 fileuid
= cached
->uid
;
3537 filegid
= cached
->gid
;
3539 oldpxdesc
= cached
->pxdesc
;
3541 /* must copy before merging */
3542 pxsize
= sizeof(struct POSIX_SECURITY
)
3543 + (oldpxdesc
->acccnt
+ oldpxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
3544 newpxdesc
= (struct POSIX_SECURITY
*)malloc(pxsize
);
3546 memcpy(newpxdesc
, oldpxdesc
, pxsize
);
3547 if (ntfs_merge_mode_posix(newpxdesc
, mode
))
3556 oldattr
= getsecurityattr(scx
->vol
, ni
);
3558 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3559 != const_cpu_to_le16(0);
3560 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
3563 &oldattr
[le32_to_cpu(phead
->group
)];
3565 usid
= ntfs_acl_owner(oldattr
);
3568 &oldattr
[le32_to_cpu(phead
->owner
)];
3571 newpxdesc
= ntfs_build_permissions_posix(scx
->mapping
, oldattr
,
3573 if (!newpxdesc
|| ntfs_merge_mode_posix(newpxdesc
, mode
))
3576 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3577 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3585 /* check requested by root */
3586 /* or chgrp requested by owner to an owned group */
3588 || ((((int)uid
< 0) || (uid
== fileuid
))
3589 && ((gid
== scx
->gid
) || groupmember(scx
, scx
->uid
, gid
))
3590 && (fileuid
== scx
->uid
))) {
3591 /* replace by the new usid and gsid */
3592 /* or reuse old gid and sid for cacheing */
3598 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3601 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3604 res
= -1; /* neither owner nor root */
3609 * Should not happen : a default descriptor is generated
3610 * by getsecurityattr() when there are none
3612 ntfs_log_error("File has no security descriptor\n");
3619 return (res
? -1 : 0);
3623 * Build a security id for a descriptor inherited from
3624 * parent directory the Windows way
3627 static le32
build_inherited_id(struct SECURITY_CONTEXT
*scx
,
3628 const char *parentattr
, BOOL fordir
)
3630 const SECURITY_DESCRIPTOR_RELATIVE
*pphead
;
3639 SECURITY_DESCRIPTOR_RELATIVE
*pnhead
;
3650 parentattrsz
= ntfs_attr_size(parentattr
);
3651 pphead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)parentattr
;
3652 if (scx
->mapping
[MAPUSERS
]) {
3653 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
], scx
->uid
, (SID
*)&defusid
);
3654 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
], scx
->gid
, (SID
*)&defgsid
);
3661 * If there is no user mapping, we have to copy owner
3662 * and group from parent directory.
3663 * Windows never has to do that, because it can always
3664 * rely on a user mapping
3666 offowner
= le32_to_cpu(pphead
->owner
);
3667 usid
= (const SID
*)&parentattr
[offowner
];
3668 offgroup
= le32_to_cpu(pphead
->group
);
3669 gsid
= (const SID
*)&parentattr
[offgroup
];
3672 * new attribute is smaller than parent's
3673 * except for differences in SIDs which appear in
3674 * owner, group and possible grants and denials in
3675 * generic creator-owner and creator-group ACEs.
3676 * For directories, an ACE may be duplicated for
3677 * access and inheritance, so we double the count.
3679 usidsz
= ntfs_sid_size(usid
);
3680 gsidsz
= ntfs_sid_size(gsid
);
3681 newattrsz
= parentattrsz
+ 3*usidsz
+ 3*gsidsz
;
3684 newattr
= (char*)ntfs_malloc(newattrsz
);
3686 pnhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)newattr
;
3687 pnhead
->revision
= SECURITY_DESCRIPTOR_REVISION
;
3688 pnhead
->alignment
= 0;
3689 pnhead
->control
= SE_SELF_RELATIVE
;
3690 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
3692 * locate and inherit DACL
3693 * do not test SE_DACL_PRESENT (wrong for "DR Watson")
3695 pnhead
->dacl
= const_cpu_to_le32(0);
3697 offpacl
= le32_to_cpu(pphead
->dacl
);
3698 ppacl
= (const ACL
*)&parentattr
[offpacl
];
3699 pnacl
= (ACL
*)&newattr
[pos
];
3700 aclsz
= ntfs_inherit_acl(ppacl
, pnacl
, usid
, gsid
, fordir
);
3702 pnhead
->dacl
= cpu_to_le32(pos
);
3704 pnhead
->control
|= SE_DACL_PRESENT
;
3708 * locate and inherit SACL
3710 pnhead
->sacl
= const_cpu_to_le32(0);
3712 offpacl
= le32_to_cpu(pphead
->sacl
);
3713 ppacl
= (const ACL
*)&parentattr
[offpacl
];
3714 pnacl
= (ACL
*)&newattr
[pos
];
3715 aclsz
= ntfs_inherit_acl(ppacl
, pnacl
, usid
, gsid
, fordir
);
3717 pnhead
->sacl
= cpu_to_le32(pos
);
3719 pnhead
->control
|= SE_SACL_PRESENT
;
3723 * inherit or redefine owner
3725 memcpy(&newattr
[pos
],usid
,usidsz
);
3726 pnhead
->owner
= cpu_to_le32(pos
);
3729 * inherit or redefine group
3731 memcpy(&newattr
[pos
],gsid
,gsidsz
);
3732 pnhead
->group
= cpu_to_le32(pos
);
3734 securid
= setsecurityattr(scx
->vol
,
3735 (SECURITY_DESCRIPTOR_RELATIVE
*)newattr
, pos
);
3738 securid
= const_cpu_to_le32(0);
3743 * Get an inherited security id
3745 * For Windows compatibility, the normal initial permission setting
3746 * may be inherited from the parent directory instead of being
3747 * defined by the creation arguments.
3749 * The following creates an inherited id for that purpose.
3751 * Note : the owner and group of parent directory are also
3752 * inherited (which is not the case on Windows) if no user mapping
3755 * Returns the inherited id, or zero if not possible (eg on NTFS 1.x)
3758 le32
ntfs_inherited_id(struct SECURITY_CONTEXT
*scx
,
3759 ntfs_inode
*dir_ni
, BOOL fordir
)
3761 struct CACHED_PERMISSIONS
*cached
;
3765 securid
= const_cpu_to_le32(0);
3766 cached
= (struct CACHED_PERMISSIONS
*)NULL
;
3768 * Try to get inherited id from cache
3770 if (test_nino_flag(dir_ni
, v3_Extensions
)
3771 && dir_ni
->security_id
) {
3772 cached
= fetch_cache(scx
, dir_ni
);
3774 securid
= (fordir
? cached
->inh_dirid
3775 : cached
->inh_fileid
);
3778 * Not cached or not available in cache, compute it all
3779 * Note : if parent directory has no id, it is not cacheable
3782 parentattr
= getsecurityattr(scx
->vol
, dir_ni
);
3784 securid
= build_inherited_id(scx
,
3785 parentattr
, fordir
);
3788 * Store the result into cache for further use
3791 cached
= fetch_cache(scx
, dir_ni
);
3794 cached
->inh_dirid
= securid
;
3796 cached
->inh_fileid
= securid
;
3805 * Link a group to a member of group
3807 * Returns 0 if OK, -1 (and errno set) if error
3810 static int link_single_group(struct MAPPING
*usermapping
, struct passwd
*user
,
3813 struct group
*group
;
3820 group
= getgrgid(gid
);
3821 if (group
&& group
->gr_mem
) {
3822 grcnt
= usermapping
->grcnt
;
3823 groups
= usermapping
->groups
;
3824 grmem
= group
->gr_mem
;
3825 while (*grmem
&& strcmp(user
->pw_name
, *grmem
))
3829 groups
= (gid_t
*)malloc(sizeof(gid_t
));
3831 groups
= (gid_t
*)realloc(groups
,
3832 (grcnt
+1)*sizeof(gid_t
));
3834 groups
[grcnt
++] = gid
;
3840 usermapping
->grcnt
= grcnt
;
3841 usermapping
->groups
= groups
;
3848 * Statically link group to users
3849 * This is based on groups defined in /etc/group and does not take
3850 * the groups dynamically set by setgroups() nor any changes in
3851 * /etc/group into account
3853 * Only mapped groups and root group are linked to mapped users
3855 * Returns 0 if OK, -1 (and errno set) if error
3859 static int link_group_members(struct SECURITY_CONTEXT
*scx
)
3861 struct MAPPING
*usermapping
;
3862 struct MAPPING
*groupmapping
;
3863 struct passwd
*user
;
3867 for (usermapping
=scx
->mapping
[MAPUSERS
]; usermapping
&& !res
;
3868 usermapping
=usermapping
->next
) {
3869 usermapping
->grcnt
= 0;
3870 usermapping
->groups
= (gid_t
*)NULL
;
3871 user
= getpwuid(usermapping
->xid
);
3872 if (user
&& user
->pw_name
) {
3873 for (groupmapping
=scx
->mapping
[MAPGROUPS
];
3874 groupmapping
&& !res
;
3875 groupmapping
=groupmapping
->next
) {
3876 if (link_single_group(usermapping
, user
,
3880 if (!res
&& link_single_group(usermapping
,
3889 * Apply default single user mapping
3890 * returns zero if successful
3893 static int ntfs_do_default_mapping(struct SECURITY_CONTEXT
*scx
,
3894 uid_t uid
, gid_t gid
, const SID
*usid
)
3896 struct MAPPING
*usermapping
;
3897 struct MAPPING
*groupmapping
;
3903 sidsz
= ntfs_sid_size(usid
);
3904 sid
= (SID
*)ntfs_malloc(sidsz
);
3906 memcpy(sid
,usid
,sidsz
);
3907 usermapping
= (struct MAPPING
*)ntfs_malloc(sizeof(struct MAPPING
));
3909 groupmapping
= (struct MAPPING
*)ntfs_malloc(sizeof(struct MAPPING
));
3911 usermapping
->sid
= sid
;
3912 usermapping
->xid
= uid
;
3913 usermapping
->next
= (struct MAPPING
*)NULL
;
3914 groupmapping
->sid
= sid
;
3915 groupmapping
->xid
= gid
;
3916 groupmapping
->next
= (struct MAPPING
*)NULL
;
3917 scx
->mapping
[MAPUSERS
] = usermapping
;
3918 scx
->mapping
[MAPGROUPS
] = groupmapping
;
3927 * Make sure there are no ambiguous mapping
3928 * Ambiguous mapping may lead to undesired configurations and
3929 * we had rather be safe until the consequences are understood
3932 #if 0 /* not activated for now */
3934 static BOOL
check_mapping(const struct MAPPING
*usermapping
,
3935 const struct MAPPING
*groupmapping
)
3937 const struct MAPPING
*mapping1
;
3938 const struct MAPPING
*mapping2
;
3942 for (mapping1
=usermapping
; mapping1
; mapping1
=mapping1
->next
)
3943 for (mapping2
=mapping1
->next
; mapping2
; mapping1
=mapping2
->next
)
3944 if (ntfs_same_sid(mapping1
->sid
,mapping2
->sid
)) {
3945 if (mapping1
->xid
!= mapping2
->xid
)
3948 if (mapping1
->xid
== mapping2
->xid
)
3951 for (mapping1
=groupmapping
; mapping1
; mapping1
=mapping1
->next
)
3952 for (mapping2
=mapping1
->next
; mapping2
; mapping1
=mapping2
->next
)
3953 if (ntfs_same_sid(mapping1
->sid
,mapping2
->sid
)) {
3954 if (mapping1
->xid
!= mapping2
->xid
)
3957 if (mapping1
->xid
== mapping2
->xid
)
3965 #if 0 /* not used any more */
3968 * Try and apply default single user mapping
3969 * returns zero if successful
3972 static int ntfs_default_mapping(struct SECURITY_CONTEXT
*scx
)
3974 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3981 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, "/.");
3983 securattr
= getsecurityattr(scx
->vol
, ni
);
3985 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)securattr
;
3986 usid
= (SID
*)&securattr
[le32_to_cpu(phead
->owner
)];
3987 if (ntfs_is_user_sid(usid
))
3988 res
= ntfs_do_default_mapping(scx
,
3989 scx
->uid
, scx
->gid
, usid
);
3992 ntfs_inode_close(ni
);
4000 * Basic read from a user mapping file on another volume
4003 static int basicread(void *fileid
, char *buf
, size_t size
, off_t offs
__attribute__((unused
)))
4005 return (read(*(int*)fileid
, buf
, size
));
4010 * Read from a user mapping file on current NTFS partition
4013 static int localread(void *fileid
, char *buf
, size_t size
, off_t offs
)
4015 return (ntfs_attr_data_read((ntfs_inode
*)fileid
,
4016 AT_UNNAMED
, 0, buf
, size
, offs
));
4020 * Build the user mapping
4021 * - according to a mapping file if defined (or default present),
4022 * - or try default single user mapping if possible
4024 * The mapping is specific to a mounted device
4025 * No locking done, mounting assumed non multithreaded
4027 * returns zero if mapping is successful
4028 * (failure should not be interpreted as an error)
4031 int ntfs_build_mapping(struct SECURITY_CONTEXT
*scx
, const char *usermap_path
,
4034 struct MAPLIST
*item
;
4035 struct MAPLIST
*firstitem
;
4036 struct MAPPING
*usermapping
;
4037 struct MAPPING
*groupmapping
;
4051 1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5),
4052 const_cpu_to_le32(21),
4053 const_cpu_to_le32(DEFSECAUTH1
), const_cpu_to_le32(DEFSECAUTH2
),
4054 const_cpu_to_le32(DEFSECAUTH3
), const_cpu_to_le32(DEFSECBASE
)
4057 /* be sure not to map anything until done */
4058 scx
->mapping
[MAPUSERS
] = (struct MAPPING
*)NULL
;
4059 scx
->mapping
[MAPGROUPS
] = (struct MAPPING
*)NULL
;
4061 if (!usermap_path
) usermap_path
= MAPPINGFILE
;
4062 if (usermap_path
[0] == '/') {
4063 fd
= open(usermap_path
,O_RDONLY
);
4065 firstitem
= ntfs_read_mapping(basicread
, (void*)&fd
);
4068 firstitem
= (struct MAPLIST
*)NULL
;
4070 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, usermap_path
);
4072 firstitem
= ntfs_read_mapping(localread
, ni
);
4073 ntfs_inode_close(ni
);
4075 firstitem
= (struct MAPLIST
*)NULL
;
4080 usermapping
= ntfs_do_user_mapping(firstitem
);
4081 groupmapping
= ntfs_do_group_mapping(firstitem
);
4082 if (usermapping
&& groupmapping
) {
4083 scx
->mapping
[MAPUSERS
] = usermapping
;
4084 scx
->mapping
[MAPGROUPS
] = groupmapping
;
4086 ntfs_log_error("There were no valid user or no valid group\n");
4087 /* now we can free the memory copy of input text */
4088 /* and rely on internal representation */
4090 item
= firstitem
->next
;
4095 /* no mapping file, try a default mapping */
4097 if (!ntfs_do_default_mapping(scx
,
4098 0, 0, (const SID
*)&defmap
))
4099 ntfs_log_info("Using default user mapping\n");
4102 return (!scx
->mapping
[MAPUSERS
] || link_group_members(scx
));
4105 #ifdef HAVE_SETXATTR /* extended attributes interface required */
4108 * Get the ntfs attribute into an extended attribute
4109 * The attribute is returned according to cpu endianness
4112 int ntfs_get_ntfs_attrib(ntfs_inode
*ni
, char *value
, size_t size
)
4117 outsize
= 0; /* default to no data and no error */
4119 attrib
= le32_to_cpu(ni
->flags
);
4120 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
4121 attrib
|= const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4123 attrib
&= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4125 attrib
|= const_le32_to_cpu(FILE_ATTR_NORMAL
);
4126 outsize
= sizeof(FILE_ATTR_FLAGS
);
4127 if (size
>= outsize
) {
4129 memcpy(value
,&attrib
,outsize
);
4134 return (outsize
? (int)outsize
: -errno
);
4138 * Return the ntfs attribute into an extended attribute
4139 * The attribute is expected according to cpu endianness
4141 * Returns 0, or -1 if there is a problem
4144 int ntfs_set_ntfs_attrib(ntfs_inode
*ni
,
4145 const char *value
, size_t size
, int flags
)
4149 ATTR_FLAGS dirflags
;
4153 if (ni
&& value
&& (size
>= sizeof(FILE_ATTR_FLAGS
))) {
4154 if (!(flags
& XATTR_CREATE
)) {
4155 /* copy to avoid alignment problems */
4156 memcpy(&attrib
,value
,sizeof(FILE_ATTR_FLAGS
));
4157 settable
= FILE_ATTR_SETTABLE
;
4159 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
4161 * Accept changing compression for a directory
4162 * and set index root accordingly
4164 settable
|= FILE_ATTR_COMPRESSED
;
4165 if ((ni
->flags
^ cpu_to_le32(attrib
))
4166 & FILE_ATTR_COMPRESSED
) {
4167 if (ni
->flags
& FILE_ATTR_COMPRESSED
)
4168 dirflags
= const_cpu_to_le16(0);
4170 dirflags
= ATTR_IS_COMPRESSED
;
4171 res
= ntfs_attr_set_flags(ni
,
4175 ATTR_COMPRESSION_MASK
);
4179 ni
->flags
= (ni
->flags
& ~settable
)
4180 | (cpu_to_le32(attrib
) & settable
);
4181 NInoFileNameSetDirty(ni
);
4188 return (res
? -1 : 0);
4191 #endif /* HAVE_SETXATTR */
4194 * Open $Secure once for all
4195 * returns zero if it succeeds
4196 * non-zero if it fails. This is not an error (on NTFS v1.x)
4200 int ntfs_open_secure(ntfs_volume
*vol
)
4206 vol
->secure_ni
= (ntfs_inode
*)NULL
;
4207 vol
->secure_xsii
= (ntfs_index_context
*)NULL
;
4208 vol
->secure_xsdh
= (ntfs_index_context
*)NULL
;
4209 if (vol
->major_ver
>= 3) {
4210 /* make sure this is a genuine $Secure inode 9 */
4211 ni
= ntfs_pathname_to_inode(vol
, NULL
, "$Secure");
4212 if (ni
&& (ni
->mft_no
== 9)) {
4213 vol
->secure_reentry
= 0;
4214 vol
->secure_xsii
= ntfs_index_ctx_get(ni
,
4216 vol
->secure_xsdh
= ntfs_index_ctx_get(ni
,
4218 if (ni
&& vol
->secure_xsii
&& vol
->secure_xsdh
) {
4219 vol
->secure_ni
= ni
;
4229 * Allocated memory is freed to facilitate the detection of memory leaks
4232 void ntfs_close_secure(struct SECURITY_CONTEXT
*scx
)
4237 if (vol
->secure_ni
) {
4238 ntfs_index_ctx_put(vol
->secure_xsii
);
4239 ntfs_index_ctx_put(vol
->secure_xsdh
);
4240 ntfs_inode_close(vol
->secure_ni
);
4243 ntfs_free_mapping(scx
->mapping
);
4248 * API for direct access to security descriptors
4249 * based on Win32 API
4254 * Selective feeding of a security descriptor into user buffer
4256 * Returns TRUE if successful
4259 static BOOL
feedsecurityattr(const char *attr
, u32 selection
,
4260 char *buf
, u32 buflen
, u32
*psize
)
4262 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4263 SECURITY_DESCRIPTOR_RELATIVE
*pnhead
;
4268 unsigned int offdacl
;
4269 unsigned int offsacl
;
4270 unsigned int offowner
;
4271 unsigned int offgroup
;
4272 unsigned int daclsz
;
4273 unsigned int saclsz
;
4274 unsigned int usidsz
;
4275 unsigned int gsidsz
;
4276 unsigned int size
; /* size of requested attributes */
4283 control
= SE_SELF_RELATIVE
;
4284 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
;
4285 size
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4287 /* locate DACL if requested and available */
4288 if (phead
->dacl
&& (selection
& DACL_SECURITY_INFORMATION
)) {
4289 offdacl
= le32_to_cpu(phead
->dacl
);
4290 pdacl
= (const ACL
*)&attr
[offdacl
];
4291 daclsz
= le16_to_cpu(pdacl
->size
);
4293 avail
|= DACL_SECURITY_INFORMATION
;
4295 offdacl
= daclsz
= 0;
4297 /* locate owner if requested and available */
4298 offowner
= le32_to_cpu(phead
->owner
);
4299 if (offowner
&& (selection
& OWNER_SECURITY_INFORMATION
)) {
4300 /* find end of USID */
4301 pusid
= (const SID
*)&attr
[offowner
];
4302 usidsz
= ntfs_sid_size(pusid
);
4304 avail
|= OWNER_SECURITY_INFORMATION
;
4306 offowner
= usidsz
= 0;
4308 /* locate group if requested and available */
4309 offgroup
= le32_to_cpu(phead
->group
);
4310 if (offgroup
&& (selection
& GROUP_SECURITY_INFORMATION
)) {
4311 /* find end of GSID */
4312 pgsid
= (const SID
*)&attr
[offgroup
];
4313 gsidsz
= ntfs_sid_size(pgsid
);
4315 avail
|= GROUP_SECURITY_INFORMATION
;
4317 offgroup
= gsidsz
= 0;
4319 /* locate SACL if requested and available */
4320 if (phead
->sacl
&& (selection
& SACL_SECURITY_INFORMATION
)) {
4321 /* find end of SACL */
4322 offsacl
= le32_to_cpu(phead
->sacl
);
4323 psacl
= (const ACL
*)&attr
[offsacl
];
4324 saclsz
= le16_to_cpu(psacl
->size
);
4326 avail
|= SACL_SECURITY_INFORMATION
;
4328 offsacl
= saclsz
= 0;
4331 * Check having enough size in destination buffer
4332 * (required size is returned nevertheless so that
4333 * the request can be reissued with adequate size)
4335 if (size
> buflen
) {
4340 if (selection
& OWNER_SECURITY_INFORMATION
)
4341 control
|= phead
->control
& SE_OWNER_DEFAULTED
;
4342 if (selection
& GROUP_SECURITY_INFORMATION
)
4343 control
|= phead
->control
& SE_GROUP_DEFAULTED
;
4344 if (selection
& DACL_SECURITY_INFORMATION
)
4345 control
|= phead
->control
4348 | SE_DACL_AUTO_INHERITED
4349 | SE_DACL_PROTECTED
);
4350 if (selection
& SACL_SECURITY_INFORMATION
)
4351 control
|= phead
->control
4354 | SE_SACL_AUTO_INHERITED
4355 | SE_SACL_PROTECTED
);
4357 * copy header and feed new flags, even if no detailed data
4359 memcpy(buf
,attr
,sizeof(SECURITY_DESCRIPTOR_RELATIVE
));
4360 pnhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)buf
;
4361 pnhead
->control
= control
;
4362 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4364 /* copy DACL if requested and available */
4365 if (selection
& avail
& DACL_SECURITY_INFORMATION
) {
4366 pnhead
->dacl
= cpu_to_le32(pos
);
4367 memcpy(&buf
[pos
],&attr
[offdacl
],daclsz
);
4370 pnhead
->dacl
= const_cpu_to_le32(0);
4372 /* copy SACL if requested and available */
4373 if (selection
& avail
& SACL_SECURITY_INFORMATION
) {
4374 pnhead
->sacl
= cpu_to_le32(pos
);
4375 memcpy(&buf
[pos
],&attr
[offsacl
],saclsz
);
4378 pnhead
->sacl
= const_cpu_to_le32(0);
4380 /* copy owner if requested and available */
4381 if (selection
& avail
& OWNER_SECURITY_INFORMATION
) {
4382 pnhead
->owner
= cpu_to_le32(pos
);
4383 memcpy(&buf
[pos
],&attr
[offowner
],usidsz
);
4386 pnhead
->owner
= const_cpu_to_le32(0);
4388 /* copy group if requested and available */
4389 if (selection
& avail
& GROUP_SECURITY_INFORMATION
) {
4390 pnhead
->group
= cpu_to_le32(pos
);
4391 memcpy(&buf
[pos
],&attr
[offgroup
],gsidsz
);
4394 pnhead
->group
= const_cpu_to_le32(0);
4396 ntfs_log_error("Error in security descriptor size\n");
4405 * Merge a new security descriptor into the old one
4406 * and assign to designated file
4408 * Returns TRUE if successful
4411 static BOOL
mergesecurityattr(ntfs_volume
*vol
, const char *oldattr
,
4412 const char *newattr
, u32 selection
, ntfs_inode
*ni
)
4414 const SECURITY_DESCRIPTOR_RELATIVE
*oldhead
;
4415 const SECURITY_DESCRIPTOR_RELATIVE
*newhead
;
4416 SECURITY_DESCRIPTOR_RELATIVE
*targhead
;
4433 ok
= FALSE
; /* default return */
4434 oldhead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
4435 newhead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
;
4436 oldattrsz
= ntfs_attr_size(oldattr
);
4437 newattrsz
= ntfs_attr_size(newattr
);
4438 target
= (char*)ntfs_malloc(oldattrsz
+ newattrsz
);
4440 targhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)target
;
4441 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4442 control
= SE_SELF_RELATIVE
;
4444 * copy new DACL if selected
4445 * or keep old DACL if any
4447 if ((selection
& DACL_SECURITY_INFORMATION
) ?
4448 newhead
->dacl
: oldhead
->dacl
) {
4449 if (selection
& DACL_SECURITY_INFORMATION
) {
4450 offdacl
= le32_to_cpu(newhead
->dacl
);
4451 pdacl
= (const ACL
*)&newattr
[offdacl
];
4453 offdacl
= le32_to_cpu(oldhead
->dacl
);
4454 pdacl
= (const ACL
*)&oldattr
[offdacl
];
4456 size
= le16_to_cpu(pdacl
->size
);
4457 memcpy(&target
[pos
], pdacl
, size
);
4458 targhead
->dacl
= cpu_to_le32(pos
);
4461 targhead
->dacl
= const_cpu_to_le32(0);
4462 if (selection
& DACL_SECURITY_INFORMATION
) {
4463 control
|= newhead
->control
4466 | SE_DACL_PROTECTED
);
4467 if (newhead
->control
& SE_DACL_AUTO_INHERIT_REQ
)
4468 control
|= SE_DACL_AUTO_INHERITED
;
4470 control
|= oldhead
->control
4473 | SE_DACL_AUTO_INHERITED
4474 | SE_DACL_PROTECTED
);
4476 * copy new SACL if selected
4477 * or keep old SACL if any
4479 if ((selection
& SACL_SECURITY_INFORMATION
) ?
4480 newhead
->sacl
: oldhead
->sacl
) {
4481 if (selection
& SACL_SECURITY_INFORMATION
) {
4482 offsacl
= le32_to_cpu(newhead
->sacl
);
4483 psacl
= (const ACL
*)&newattr
[offsacl
];
4485 offsacl
= le32_to_cpu(oldhead
->sacl
);
4486 psacl
= (const ACL
*)&oldattr
[offsacl
];
4488 size
= le16_to_cpu(psacl
->size
);
4489 memcpy(&target
[pos
], psacl
, size
);
4490 targhead
->sacl
= cpu_to_le32(pos
);
4493 targhead
->sacl
= const_cpu_to_le32(0);
4494 if (selection
& SACL_SECURITY_INFORMATION
) {
4495 control
|= newhead
->control
4498 | SE_SACL_PROTECTED
);
4499 if (newhead
->control
& SE_SACL_AUTO_INHERIT_REQ
)
4500 control
|= SE_SACL_AUTO_INHERITED
;
4502 control
|= oldhead
->control
4505 | SE_SACL_AUTO_INHERITED
4506 | SE_SACL_PROTECTED
);
4508 * copy new OWNER if selected
4509 * or keep old OWNER if any
4511 if ((selection
& OWNER_SECURITY_INFORMATION
) ?
4512 newhead
->owner
: oldhead
->owner
) {
4513 if (selection
& OWNER_SECURITY_INFORMATION
) {
4514 offowner
= le32_to_cpu(newhead
->owner
);
4515 powner
= (const SID
*)&newattr
[offowner
];
4517 offowner
= le32_to_cpu(oldhead
->owner
);
4518 powner
= (const SID
*)&oldattr
[offowner
];
4520 size
= ntfs_sid_size(powner
);
4521 memcpy(&target
[pos
], powner
, size
);
4522 targhead
->owner
= cpu_to_le32(pos
);
4525 targhead
->owner
= const_cpu_to_le32(0);
4526 if (selection
& OWNER_SECURITY_INFORMATION
)
4527 control
|= newhead
->control
& SE_OWNER_DEFAULTED
;
4529 control
|= oldhead
->control
& SE_OWNER_DEFAULTED
;
4531 * copy new GROUP if selected
4532 * or keep old GROUP if any
4534 if ((selection
& GROUP_SECURITY_INFORMATION
) ?
4535 newhead
->group
: oldhead
->group
) {
4536 if (selection
& GROUP_SECURITY_INFORMATION
) {
4537 offgroup
= le32_to_cpu(newhead
->group
);
4538 pgroup
= (const SID
*)&newattr
[offgroup
];
4539 control
|= newhead
->control
4540 & SE_GROUP_DEFAULTED
;
4542 offgroup
= le32_to_cpu(oldhead
->group
);
4543 pgroup
= (const SID
*)&oldattr
[offgroup
];
4544 control
|= oldhead
->control
4545 & SE_GROUP_DEFAULTED
;
4547 size
= ntfs_sid_size(pgroup
);
4548 memcpy(&target
[pos
], pgroup
, size
);
4549 targhead
->group
= cpu_to_le32(pos
);
4552 targhead
->group
= const_cpu_to_le32(0);
4553 if (selection
& GROUP_SECURITY_INFORMATION
)
4554 control
|= newhead
->control
& SE_GROUP_DEFAULTED
;
4556 control
|= oldhead
->control
& SE_GROUP_DEFAULTED
;
4557 targhead
->revision
= SECURITY_DESCRIPTOR_REVISION
;
4558 targhead
->alignment
= 0;
4559 targhead
->control
= control
;
4560 ok
= !update_secur_descr(vol
, target
, ni
);
4567 * Return the security descriptor of a file
4568 * This is intended to be similar to GetFileSecurity() from Win32
4569 * in order to facilitate the development of portable tools
4571 * returns zero if unsuccessful (following Win32 conventions)
4573 * the securid if any
4575 * The Win32 API is :
4577 * BOOL WINAPI GetFileSecurity(
4578 * __in LPCTSTR lpFileName,
4579 * __in SECURITY_INFORMATION RequestedInformation,
4580 * __out_opt PSECURITY_DESCRIPTOR pSecurityDescriptor,
4581 * __in DWORD nLength,
4582 * __out LPDWORD lpnLengthNeeded
4587 int ntfs_get_file_security(struct SECURITY_API
*scapi
,
4588 const char *path
, u32 selection
,
4589 char *buf
, u32 buflen
, u32
*psize
)
4595 res
= 0; /* default return */
4596 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4597 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4599 attr
= getsecurityattr(scapi
->security
.vol
, ni
);
4601 if (feedsecurityattr(attr
,selection
,
4602 buf
,buflen
,psize
)) {
4603 if (test_nino_flag(ni
, v3_Extensions
)
4612 ntfs_inode_close(ni
);
4615 if (!res
) *psize
= 0;
4617 errno
= EINVAL
; /* do not clear *psize */
4623 * Set the security descriptor of a file or directory
4624 * This is intended to be similar to SetFileSecurity() from Win32
4625 * in order to facilitate the development of portable tools
4627 * returns zero if unsuccessful (following Win32 conventions)
4629 * the securid if any
4631 * The Win32 API is :
4633 * BOOL WINAPI SetFileSecurity(
4634 * __in LPCTSTR lpFileName,
4635 * __in SECURITY_INFORMATION SecurityInformation,
4636 * __in PSECURITY_DESCRIPTOR pSecurityDescriptor
4640 int ntfs_set_file_security(struct SECURITY_API
*scapi
,
4641 const char *path
, u32 selection
, const char *attr
)
4643 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4650 res
= 0; /* default return */
4651 if (scapi
&& (scapi
->magic
== MAGIC_API
) && attr
) {
4652 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
;
4653 attrsz
= ntfs_attr_size(attr
);
4654 /* if selected, owner and group must be present or defaulted */
4655 missing
= ((selection
& OWNER_SECURITY_INFORMATION
)
4657 && !(phead
->control
& SE_OWNER_DEFAULTED
))
4658 || ((selection
& GROUP_SECURITY_INFORMATION
)
4660 && !(phead
->control
& SE_GROUP_DEFAULTED
));
4662 && (phead
->control
& SE_SELF_RELATIVE
)
4663 && ntfs_valid_descr(attr
, attrsz
)) {
4664 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
,
4667 oldattr
= getsecurityattr(scapi
->security
.vol
,
4670 if (mergesecurityattr(
4671 scapi
->security
.vol
,
4674 if (test_nino_flag(ni
,
4683 ntfs_inode_close(ni
);
4694 * Return the attributes of a file
4695 * This is intended to be similar to GetFileAttributes() from Win32
4696 * in order to facilitate the development of portable tools
4698 * returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES)
4700 * The Win32 API is :
4702 * DWORD WINAPI GetFileAttributes(
4703 * __in LPCTSTR lpFileName
4707 int ntfs_get_file_attributes(struct SECURITY_API
*scapi
, const char *path
)
4712 attrib
= -1; /* default return */
4713 if (scapi
&& (scapi
->magic
== MAGIC_API
) && path
) {
4714 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4716 attrib
= le32_to_cpu(ni
->flags
);
4717 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
4718 attrib
|= const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4720 attrib
&= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4722 attrib
|= const_le32_to_cpu(FILE_ATTR_NORMAL
);
4724 ntfs_inode_close(ni
);
4728 errno
= EINVAL
; /* do not clear *psize */
4734 * Set attributes to a file or directory
4735 * This is intended to be similar to SetFileAttributes() from Win32
4736 * in order to facilitate the development of portable tools
4738 * Only a few flags can be set (same list as Win32)
4740 * returns zero if unsuccessful (following Win32 conventions)
4741 * nonzero if successful
4743 * The Win32 API is :
4745 * BOOL WINAPI SetFileAttributes(
4746 * __in LPCTSTR lpFileName,
4747 * __in DWORD dwFileAttributes
4751 BOOL
ntfs_set_file_attributes(struct SECURITY_API
*scapi
,
4752 const char *path
, s32 attrib
)
4756 ATTR_FLAGS dirflags
;
4759 res
= 0; /* default return */
4760 if (scapi
&& (scapi
->magic
== MAGIC_API
) && path
) {
4761 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4763 settable
= FILE_ATTR_SETTABLE
;
4764 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
4766 * Accept changing compression for a directory
4767 * and set index root accordingly
4769 settable
|= FILE_ATTR_COMPRESSED
;
4770 if ((ni
->flags
^ cpu_to_le32(attrib
))
4771 & FILE_ATTR_COMPRESSED
) {
4772 if (ni
->flags
& FILE_ATTR_COMPRESSED
)
4773 dirflags
= const_cpu_to_le16(0);
4775 dirflags
= ATTR_IS_COMPRESSED
;
4776 res
= ntfs_attr_set_flags(ni
,
4780 ATTR_COMPRESSION_MASK
);
4784 ni
->flags
= (ni
->flags
& ~settable
)
4785 | (cpu_to_le32(attrib
) & settable
);
4788 if (!ntfs_inode_close(ni
))
4797 BOOL
ntfs_read_directory(struct SECURITY_API
*scapi
,
4798 const char *path
, ntfs_filldir_t callback
, void *context
)
4804 ok
= FALSE
; /* default return */
4805 if (scapi
&& (scapi
->magic
== MAGIC_API
) && callback
) {
4806 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4808 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
4810 ntfs_readdir(ni
,&pos
,context
,callback
);
4811 ok
= !ntfs_inode_close(ni
);
4813 ntfs_inode_close(ni
);
4819 errno
= EINVAL
; /* do not clear *psize */
4824 * read $SDS (for auditing security data)
4826 * Returns the number or read bytes, or -1 if there is an error
4829 int ntfs_read_sds(struct SECURITY_API
*scapi
,
4830 char *buf
, u32 size
, u32 offset
)
4834 got
= -1; /* default return */
4835 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4836 if (scapi
->security
.vol
->secure_ni
)
4837 got
= ntfs_attr_data_read(scapi
->security
.vol
->secure_ni
,
4838 STREAM_SDS
, 4, buf
, size
, offset
);
4847 * read $SII (for auditing security data)
4849 * Returns next entry, or NULL if there is an error
4852 INDEX_ENTRY
*ntfs_read_sii(struct SECURITY_API
*scapi
,
4858 ntfs_index_context
*xsii
;
4860 ret
= (INDEX_ENTRY
*)NULL
; /* default return */
4861 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4862 xsii
= scapi
->security
.vol
->secure_xsii
;
4865 key
.security_id
= const_cpu_to_le32(0);
4866 found
= !ntfs_index_lookup((char*)&key
,
4867 sizeof(SII_INDEX_KEY
), xsii
);
4868 /* not supposed to find */
4869 if (!found
&& (errno
== ENOENT
))
4872 ret
= ntfs_index_next(entry
,xsii
);
4883 * read $SDH (for auditing security data)
4885 * Returns next entry, or NULL if there is an error
4888 INDEX_ENTRY
*ntfs_read_sdh(struct SECURITY_API
*scapi
,
4894 ntfs_index_context
*xsdh
;
4896 ret
= (INDEX_ENTRY
*)NULL
; /* default return */
4897 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4898 xsdh
= scapi
->security
.vol
->secure_xsdh
;
4901 key
.hash
= const_cpu_to_le32(0);
4902 key
.security_id
= const_cpu_to_le32(0);
4903 found
= !ntfs_index_lookup((char*)&key
,
4904 sizeof(SDH_INDEX_KEY
), xsdh
);
4905 /* not supposed to find */
4906 if (!found
&& (errno
== ENOENT
))
4909 ret
= ntfs_index_next(entry
,xsdh
);
4912 } else errno
= ENOTSUP
;
4919 * Get the mapped user SID
4920 * A buffer of 40 bytes has to be supplied
4922 * returns the size of the SID, or zero and errno set if not found
4925 int ntfs_get_usid(struct SECURITY_API
*scapi
, uid_t uid
, char *buf
)
4932 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4933 usid
= ntfs_find_usid(scapi
->security
.mapping
[MAPUSERS
], uid
, (SID
*)&defusid
);
4935 size
= ntfs_sid_size(usid
);
4936 memcpy(buf
,usid
,size
);
4945 * Get the mapped group SID
4946 * A buffer of 40 bytes has to be supplied
4948 * returns the size of the SID, or zero and errno set if not found
4951 int ntfs_get_gsid(struct SECURITY_API
*scapi
, gid_t gid
, char *buf
)
4958 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4959 gsid
= ntfs_find_gsid(scapi
->security
.mapping
[MAPGROUPS
], gid
, (SID
*)&defgsid
);
4961 size
= ntfs_sid_size(gsid
);
4962 memcpy(buf
,gsid
,size
);
4971 * Get the user mapped to a SID
4973 * returns the uid, or -1 if not found
4976 int ntfs_get_user(struct SECURITY_API
*scapi
, const SID
*usid
)
4981 if (scapi
&& (scapi
->magic
== MAGIC_API
) && ntfs_valid_sid(usid
)) {
4982 if (ntfs_same_sid(usid
,adminsid
))
4985 uid
= ntfs_find_user(scapi
->security
.mapping
[MAPUSERS
], usid
);
4997 * Get the group mapped to a SID
4999 * returns the uid, or -1 if not found
5002 int ntfs_get_group(struct SECURITY_API
*scapi
, const SID
*gsid
)
5007 if (scapi
&& (scapi
->magic
== MAGIC_API
) && ntfs_valid_sid(gsid
)) {
5008 if (ntfs_same_sid(gsid
,adminsid
))
5011 gid
= ntfs_find_group(scapi
->security
.mapping
[MAPGROUPS
], gsid
);
5023 * Initializations before calling ntfs_get_file_security()
5024 * ntfs_set_file_security() and ntfs_read_directory()
5026 * Only allowed for root
5028 * Returns an (obscured) struct SECURITY_API* needed for further calls
5029 * NULL if not root (EPERM) or device is mounted (EBUSY)
5032 struct SECURITY_API
*ntfs_initialize_file_security(const char *device
,
5033 unsigned long flags
)
5036 unsigned long mntflag
;
5038 struct SECURITY_API
*scapi
;
5039 struct SECURITY_CONTEXT
*scx
;
5041 scapi
= (struct SECURITY_API
*)NULL
;
5042 mnt
= ntfs_check_if_mounted(device
, &mntflag
);
5043 if (!mnt
&& !(mntflag
& NTFS_MF_MOUNTED
) && !getuid()) {
5044 vol
= ntfs_mount(device
, flags
);
5046 scapi
= (struct SECURITY_API
*)
5047 ntfs_malloc(sizeof(struct SECURITY_API
));
5048 if (!ntfs_volume_get_free_space(vol
)
5050 scapi
->magic
= MAGIC_API
;
5051 scapi
->seccache
= (struct PERMISSIONS_CACHE
*)NULL
;
5052 scx
= &scapi
->security
;
5054 scx
->uid
= getuid();
5055 scx
->gid
= getgid();
5056 scx
->pseccache
= &scapi
->seccache
;
5057 scx
->vol
->secure_flags
= 0;
5058 /* accept no mapping and no $Secure */
5059 ntfs_build_mapping(scx
,(const char*)NULL
,TRUE
);
5060 ntfs_open_secure(vol
);
5066 mnt
= ntfs_umount(vol
,FALSE
);
5067 scapi
= (struct SECURITY_API
*)NULL
;
5079 * Leaving after ntfs_initialize_file_security()
5081 * Returns FALSE if FAILED
5084 BOOL
ntfs_leave_file_security(struct SECURITY_API
*scapi
)
5090 if (scapi
&& (scapi
->magic
== MAGIC_API
) && scapi
->security
.vol
) {
5091 vol
= scapi
->security
.vol
;
5092 ntfs_close_secure(&scapi
->security
);
5094 if (!ntfs_umount(vol
, 0))