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-2012 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
69 * JPA NTFS constants or structs
70 * should be moved to layout.h
73 #define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */
74 #define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */
75 #define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */
76 #define FIRST_SECURITY_ID 0x100 /* Lowest security id */
78 /* Mask for attributes which can be forced */
79 #define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY \
83 | FILE_ATTR_TEMPORARY \
85 | FILE_ATTR_NOT_CONTENT_INDEXED )
87 struct SII
{ /* this is an image of an $SII index entry */
97 /* did not find official description for the following */
100 le32 dataoffsl
; /* documented as badly aligned */
105 struct SDH
{ /* this is an image of an $SDH index entry */
116 /* did not find official description for the following */
126 * A few useful constants
129 static ntfschar sii_stream
[] = { const_cpu_to_le16('$'),
130 const_cpu_to_le16('S'),
131 const_cpu_to_le16('I'),
132 const_cpu_to_le16('I'),
133 const_cpu_to_le16(0) };
134 static ntfschar sdh_stream
[] = { const_cpu_to_le16('$'),
135 const_cpu_to_le16('S'),
136 const_cpu_to_le16('D'),
137 const_cpu_to_le16('H'),
138 const_cpu_to_le16(0) };
144 extern const SID
*nullsid
;
150 static const GUID __zero_guid
= { const_cpu_to_le32(0), const_cpu_to_le16(0),
151 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
152 static const GUID
*const zero_guid
= &__zero_guid
;
155 * ntfs_guid_is_zero - check if a GUID is zero
156 * @guid: [IN] guid to check
158 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
159 * and FALSE otherwise.
161 BOOL
ntfs_guid_is_zero(const GUID
*guid
)
163 return (memcmp(guid
, zero_guid
, sizeof(*zero_guid
)));
167 * ntfs_guid_to_mbs - convert a GUID to a multi byte string
168 * @guid: [IN] guid to convert
169 * @guid_str: [OUT] string in which to return the GUID (optional)
171 * Convert the GUID pointed to by @guid to a multi byte string of the form
172 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
173 * needs to be able to store at least 37 bytes.
175 * If @guid_str is not NULL it will contain the converted GUID on return. If
176 * it is NULL a string will be allocated and this will be returned. The caller
177 * is responsible for free()ing the string in that case.
179 * On success return the converted string and on failure return NULL with errno
180 * set to the error code.
182 char *ntfs_guid_to_mbs(const GUID
*guid
, char *guid_str
)
191 _guid_str
= guid_str
;
193 _guid_str
= (char*)ntfs_malloc(37);
197 res
= snprintf(_guid_str
, 37,
198 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
199 (unsigned int)le32_to_cpu(guid
->data1
),
200 le16_to_cpu(guid
->data2
), le16_to_cpu(guid
->data3
),
201 guid
->data4
[0], guid
->data4
[1],
202 guid
->data4
[2], guid
->data4
[3], guid
->data4
[4],
203 guid
->data4
[5], guid
->data4
[6], guid
->data4
[7]);
213 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
214 * @sid: [IN] SID for which to determine the maximum string size
216 * Determine the maximum multi byte string size in bytes which is needed to
217 * store the standard textual representation of the SID pointed to by @sid.
218 * See ntfs_sid_to_mbs(), below.
220 * On success return the maximum number of bytes needed to store the multi byte
221 * string and on failure return -1 with errno set to the error code.
223 int ntfs_sid_to_mbs_size(const SID
*sid
)
227 if (!ntfs_sid_is_valid(sid
)) {
231 /* Start with "S-". */
234 * Add the SID_REVISION. Hopefully the compiler will optimize this
235 * away as SID_REVISION is a constant.
237 for (i
= SID_REVISION
; i
> 0; i
/= 10)
242 * Add the identifier authority. If it needs to be in decimal, the
243 * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
244 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
246 if (!sid
->identifier_authority
.high_part
)
251 * Finally, add the sub authorities. For each we have a "-" followed
252 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
254 size
+= (1 + 10) * sid
->sub_authority_count
;
255 /* We need the zero byte at the end, too. */
257 return size
* sizeof(char);
261 * ntfs_sid_to_mbs - convert a SID to a multi byte string
262 * @sid: [IN] SID to convert
263 * @sid_str: [OUT] string in which to return the SID (optional)
264 * @sid_str_size: [IN] size in bytes of @sid_str
266 * Convert the SID pointed to by @sid to its standard textual representation.
267 * @sid_str (if not NULL) needs to be able to store at least
268 * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
269 * @sid_str if @sid_str is not NULL.
271 * The standard textual representation of the SID is of the form:
274 * - The first "S" is the literal character 'S' identifying the following
276 * - R is the revision level of the SID expressed as a sequence of digits
278 * - I is the 48-bit identifier_authority, expressed as digits in decimal,
279 * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
280 * - S... is one or more sub_authority values, expressed as digits in
283 * If @sid_str is not NULL it will contain the converted SUID on return. If it
284 * is NULL a string will be allocated and this will be returned. The caller is
285 * responsible for free()ing the string in that case.
287 * On success return the converted string and on failure return NULL with errno
288 * set to the error code.
290 char *ntfs_sid_to_mbs(const SID
*sid
, char *sid_str
, size_t sid_str_size
)
298 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
299 * check @sid, too. 8 is the minimum SID string size.
301 if (sid_str
&& (sid_str_size
< 8 || !ntfs_sid_is_valid(sid
))) {
305 /* Allocate string if not provided. */
307 cnt
= ntfs_sid_to_mbs_size(sid
);
310 s
= (char*)ntfs_malloc(cnt
);
314 /* So we know we allocated it. */
320 /* Start with "S-R-". */
321 i
= snprintf(s
, cnt
, "S-%hhu-", (unsigned char)sid
->revision
);
322 if (i
< 0 || i
>= cnt
)
326 /* Add the identifier authority. */
327 for (u
= i
= 0, j
= 40; i
< 6; i
++, j
-= 8)
328 u
+= (u64
)sid
->identifier_authority
.value
[i
] << j
;
329 if (!sid
->identifier_authority
.high_part
)
330 i
= snprintf(s
, cnt
, "%lu", (unsigned long)u
);
332 i
= snprintf(s
, cnt
, "0x%llx", (unsigned long long)u
);
333 if (i
< 0 || i
>= cnt
)
337 /* Finally, add the sub authorities. */
338 for (j
= 0; j
< sid
->sub_authority_count
; j
++) {
339 leauth
= sid
->sub_authority
[j
];
340 i
= snprintf(s
, cnt
, "-%u", (unsigned int)
341 le32_to_cpu(leauth
));
342 if (i
< 0 || i
>= cnt
)
360 * ntfs_generate_guid - generatates a random current guid.
361 * @guid: [OUT] pointer to a GUID struct to hold the generated guid.
363 * perhaps not a very good random number generator though...
365 void ntfs_generate_guid(GUID
*guid
)
370 for (i
= 0; i
< sizeof(GUID
); i
++) {
371 p
[i
] = (u8
)(random() & 0xFF);
373 p
[7] = (p
[7] & 0x0F) | 0x40;
375 p
[8] = (p
[8] & 0x3F) | 0x80;
380 * ntfs_security_hash - calculate the hash of a security descriptor
381 * @sd: self-relative security descriptor whose hash to calculate
382 * @length: size in bytes of the security descritor @sd
384 * Calculate the hash of the self-relative security descriptor @sd of length
387 * This hash is used in the $Secure system file as the primary key for the $SDH
388 * index and is also stored in the header of each security descriptor in the
389 * $SDS data stream as well as in the index data of both the $SII and $SDH
390 * indexes. In all three cases it forms part of the SDS_ENTRY_HEADER
393 * Return the calculated security hash in little endian.
395 le32
ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE
*sd
, const u32 len
)
397 const le32
*pos
= (const le32
*)sd
;
398 const le32
*end
= pos
+ (len
>> 2);
402 hash
= le32_to_cpup(pos
) + ntfs_rol32(hash
, 3);
405 return cpu_to_le32(hash
);
409 * Get the first entry of current index block
410 * cut and pasted form ntfs_ie_get_first() in index.c
413 static INDEX_ENTRY
*ntfs_ie_get_first(INDEX_HEADER
*ih
)
415 return (INDEX_ENTRY
*)((u8
*)ih
+ le32_to_cpu(ih
->entries_offset
));
419 * Stuff a 256KB block into $SDS before writing descriptors
422 * This prevents $SDS from being automatically declared as sparse
423 * when the second copy of the first security descriptor is written
424 * 256KB further ahead.
426 * Having $SDS declared as a sparse file is not wrong by itself
427 * and chkdsk leaves it as a sparse file. It does however complain
428 * and add a sparse flag (0x0200) into field file_attributes of
429 * STANDARD_INFORMATION of $Secure. This probably means that a
430 * sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse
431 * files (FILE_ATTR_SPARSE_FILE).
433 * Windows normally does not convert to sparse attribute or sparse
434 * file. Stuffing is just a way to get to the same result.
437 static int entersecurity_stuff(ntfs_volume
*vol
, off_t offs
)
446 stuff
= (char*)ntfs_malloc(STUFFSZ
);
448 memset(stuff
, 0, STUFFSZ
);
450 written
= ntfs_attr_data_write(vol
->secure_ni
,
451 STREAM_SDS
, 4, stuff
, STUFFSZ
, offs
);
452 if (written
== STUFFSZ
) {
459 } while (!res
&& (total
< ALIGN_SDS_BLOCK
));
469 * Enter a new security descriptor into $Secure (data only)
470 * it has to be written twice with an offset of 256KB
472 * Should only be called by entersecurityattr() to ensure consistency
474 * Returns zero if sucessful
477 static int entersecurity_data(ntfs_volume
*vol
,
478 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
,
479 le32 hash
, le32 keyid
, off_t offs
, int gap
)
486 SECURITY_DESCRIPTOR_HEADER
*phsds
;
489 fullsz
= attrsz
+ gap
+ sizeof(SECURITY_DESCRIPTOR_HEADER
);
490 fullattr
= (char*)ntfs_malloc(fullsz
);
493 * Clear the gap from previous descriptor
494 * this could be useful for appending the second
495 * copy to the end of file. When creating a new
496 * 256K block, the gap is cleared while writing
500 memset(fullattr
,0,gap
);
501 memcpy(&fullattr
[gap
+ sizeof(SECURITY_DESCRIPTOR_HEADER
)],
503 phsds
= (SECURITY_DESCRIPTOR_HEADER
*)&fullattr
[gap
];
505 phsds
->security_id
= keyid
;
506 phsds
->offset
= cpu_to_le64(offs
);
507 phsds
->length
= cpu_to_le32(fullsz
- gap
);
508 written1
= ntfs_attr_data_write(vol
->secure_ni
,
509 STREAM_SDS
, 4, fullattr
, fullsz
,
511 written2
= ntfs_attr_data_write(vol
->secure_ni
,
512 STREAM_SDS
, 4, fullattr
, fullsz
,
513 offs
- gap
+ ALIGN_SDS_BLOCK
);
514 if ((written1
== fullsz
)
515 && (written2
== written1
))
526 * Enter a new security descriptor in $Secure (indexes only)
528 * Should only be called by entersecurityattr() to ensure consistency
530 * Returns zero if sucessful
533 static int entersecurity_indexes(ntfs_volume
*vol
, s64 attrsz
,
534 le32 hash
, le32 keyid
, off_t offs
)
544 ntfs_index_context
*xsii
;
545 ntfs_index_context
*xsdh
;
550 /* enter a new $SII record */
552 xsii
= vol
->secure_xsii
;
553 ntfs_index_ctx_reinit(xsii
);
554 newsii
.offs
= const_cpu_to_le16(20);
555 newsii
.size
= const_cpu_to_le16(sizeof(struct SII
) - 20);
556 newsii
.fill1
= const_cpu_to_le32(0);
557 newsii
.indexsz
= const_cpu_to_le16(sizeof(struct SII
));
558 newsii
.indexksz
= const_cpu_to_le16(sizeof(SII_INDEX_KEY
));
559 newsii
.flags
= const_cpu_to_le16(0);
560 newsii
.fill2
= const_cpu_to_le16(0);
561 newsii
.keysecurid
= keyid
;
563 newsii
.securid
= keyid
;
564 realign
.all
= cpu_to_le64(offs
);
565 newsii
.dataoffsh
= realign
.parts
.dataoffsh
;
566 newsii
.dataoffsl
= realign
.parts
.dataoffsl
;
567 newsii
.datasize
= cpu_to_le32(attrsz
568 + sizeof(SECURITY_DESCRIPTOR_HEADER
));
569 if (!ntfs_ie_add(xsii
,(INDEX_ENTRY
*)&newsii
)) {
571 /* enter a new $SDH record */
573 xsdh
= vol
->secure_xsdh
;
574 ntfs_index_ctx_reinit(xsdh
);
575 newsdh
.offs
= const_cpu_to_le16(24);
576 newsdh
.size
= const_cpu_to_le16(
577 sizeof(SECURITY_DESCRIPTOR_HEADER
));
578 newsdh
.fill1
= const_cpu_to_le32(0);
579 newsdh
.indexsz
= const_cpu_to_le16(
581 newsdh
.indexksz
= const_cpu_to_le16(
582 sizeof(SDH_INDEX_KEY
));
583 newsdh
.flags
= const_cpu_to_le16(0);
584 newsdh
.fill2
= const_cpu_to_le16(0);
585 newsdh
.keyhash
= hash
;
586 newsdh
.keysecurid
= keyid
;
588 newsdh
.securid
= keyid
;
589 newsdh
.dataoffsh
= realign
.parts
.dataoffsh
;
590 newsdh
.dataoffsl
= realign
.parts
.dataoffsl
;
591 newsdh
.datasize
= cpu_to_le32(attrsz
592 + sizeof(SECURITY_DESCRIPTOR_HEADER
));
593 /* special filler value, Windows generally */
594 /* fills with 0x00490049, sometimes with zero */
595 newsdh
.fill3
= const_cpu_to_le32(0x00490049);
596 if (!ntfs_ie_add(xsdh
,(INDEX_ENTRY
*)&newsdh
))
603 * Enter a new security descriptor in $Secure (data and indexes)
604 * Returns id of entry, or zero if there is a problem.
605 * (should not be called for NTFS version < 3.0)
607 * important : calls have to be serialized, however no locking is
608 * needed while fuse is not multithreaded
611 static le32
entersecurityattr(ntfs_volume
*vol
,
612 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
,
632 ntfs_index_context
*xsii
;
637 /* find the first available securid beyond the last key */
638 /* in $Secure:$SII. This also determines the first */
639 /* available location in $Secure:$SDS, as this stream */
640 /* is always appended to and the id's are allocated */
643 securid
= const_cpu_to_le32(0);
644 xsii
= vol
->secure_xsii
;
645 ntfs_index_ctx_reinit(xsii
);
647 keyid
= const_cpu_to_le32(-1);
649 found
= !ntfs_index_lookup((char*)&keyid
,
650 sizeof(SII_INDEX_KEY
), xsii
);
651 if (!found
&& (errno
!= ENOENT
)) {
652 ntfs_log_perror("Inconsistency in index $SII");
653 psii
= (struct SII
*)NULL
;
655 /* restore errno to avoid misinterpretation */
658 psii
= (struct SII
*)xsii
->entry
;
662 * Get last entry in block, but must get first one
663 * one first, as we should already be beyond the
664 * last one. For some reason the search for the last
665 * entry sometimes does not return the last block...
666 * we assume this can only happen in root block
668 if (xsii
->is_in_root
)
669 entry
= ntfs_ie_get_first
670 ((INDEX_HEADER
*)&xsii
->ir
->index
);
672 entry
= ntfs_ie_get_first
673 ((INDEX_HEADER
*)&xsii
->ib
->index
);
675 * All index blocks should be at least half full
676 * so there always is a last entry but one,
677 * except when creating the first entry in index root.
678 * This was however found not to be true : chkdsk
679 * sometimes deletes all the (unused) keys in the last
680 * index block without rebalancing the tree.
681 * When this happens, a new search is restarted from
684 keyid
= const_cpu_to_le32(0);
687 next
= ntfs_index_next(entry
,xsii
);
689 psii
= (struct SII
*)next
;
690 /* save last key and */
691 /* available position */
692 keyid
= psii
->keysecurid
;
693 realign
.parts
.dataoffsh
695 realign
.parts
.dataoffsl
697 offs
= le64_to_cpu(realign
.all
);
698 size
= le32_to_cpu(psii
->datasize
);
701 if (!entry
&& !keyid
&& !retries
) {
702 /* search failed, retry from smallest key */
703 ntfs_index_ctx_reinit(xsii
);
704 found
= !ntfs_index_lookup((char*)&keyid
,
705 sizeof(SII_INDEX_KEY
), xsii
);
706 if (!found
&& (errno
!= ENOENT
)) {
707 ntfs_log_perror("Index $SII is broken");
719 * could not find any entry, before creating the first
720 * entry, make a double check by making sure size of $SII
721 * is less than needed for one entry
723 securid
= const_cpu_to_le32(0);
724 na
= ntfs_attr_open(vol
->secure_ni
,AT_INDEX_ROOT
,sii_stream
,4);
726 if ((size_t)na
->data_size
< sizeof(struct SII
)) {
727 ntfs_log_error("Creating the first security_id\n");
728 securid
= const_cpu_to_le32(FIRST_SECURITY_ID
);
733 ntfs_log_error("Error creating a security_id\n");
737 newkey
= le32_to_cpu(keyid
) + 1;
738 securid
= cpu_to_le32(newkey
);
741 * The security attr has to be written twice 256KB
742 * apart. This implies that offsets like
743 * 0x40000*odd_integer must be left available for
744 * the second copy. So align to next block when
745 * the last byte overflows on a wrong block.
749 gap
= (-size
) & (ALIGN_SDS_ENTRY
- 1);
751 if ((offs
+ attrsz
+ sizeof(SECURITY_DESCRIPTOR_HEADER
) - 1)
753 offs
= ((offs
+ attrsz
754 + sizeof(SECURITY_DESCRIPTOR_HEADER
) - 1)
755 | (ALIGN_SDS_BLOCK
- 1)) + 1;
757 if (!(offs
& (ALIGN_SDS_BLOCK
- 1)))
758 entersecurity_stuff(vol
, offs
);
760 * now write the security attr to storage :
761 * first data, then SII, then SDH
762 * If failure occurs while writing SDS, data will never
763 * be accessed through indexes, and will be overwritten
764 * by the next allocated descriptor
765 * If failure occurs while writing SII, the id has not
766 * recorded and will be reallocated later
767 * If failure occurs while writing SDH, the space allocated
768 * in SDS or SII will not be reused, an inconsistency
769 * will persist with no significant consequence
771 if (entersecurity_data(vol
, attr
, attrsz
, hash
, securid
, offs
, gap
)
772 || entersecurity_indexes(vol
, attrsz
, hash
, securid
, offs
))
773 securid
= const_cpu_to_le32(0);
775 /* inode now is dirty, synchronize it all */
776 ntfs_index_entry_mark_dirty(vol
->secure_xsii
);
777 ntfs_index_ctx_reinit(vol
->secure_xsii
);
778 ntfs_index_entry_mark_dirty(vol
->secure_xsdh
);
779 ntfs_index_ctx_reinit(vol
->secure_xsdh
);
780 NInoSetDirty(vol
->secure_ni
);
781 if (ntfs_inode_sync(vol
->secure_ni
))
782 ntfs_log_perror("Could not sync $Secure\n");
787 * Find a matching security descriptor in $Secure,
788 * if none, allocate a new id and write the descriptor to storage
789 * Returns id of entry, or zero if there is a problem.
791 * important : calls have to be serialized, however no locking is
792 * needed while fuse is not multithreaded
795 static le32
setsecurityattr(ntfs_volume
*vol
,
796 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
)
798 struct SDH
*psdh
; /* this is an image of index (le) */
812 ntfs_index_context
*xsdh
;
820 hash
= ntfs_security_hash(attr
,attrsz
);
821 oldattr
= (char*)NULL
;
822 securid
= const_cpu_to_le32(0);
824 xsdh
= vol
->secure_xsdh
;
825 if (vol
->secure_ni
&& xsdh
&& !vol
->secure_reentry
++) {
826 ntfs_index_ctx_reinit(xsdh
);
828 * find the nearest key as (hash,0)
829 * (do not search for partial key : in case of collision,
830 * it could return a key which is not the first one which
834 key
.security_id
= const_cpu_to_le32(0);
836 found
= !ntfs_index_lookup((char*)&key
,
837 sizeof(SDH_INDEX_KEY
), xsdh
);
838 if (!found
&& (errno
!= ENOENT
))
839 ntfs_log_perror("Inconsistency in index $SDH");
841 /* restore errno to avoid misinterpretation */
846 * lookup() may return a node with no data,
849 if (entry
->ie_flags
& INDEX_ENTRY_END
)
850 entry
= ntfs_index_next(entry
,xsdh
);
853 psdh
= (struct SDH
*)entry
;
855 size
= (size_t) le32_to_cpu(psdh
->datasize
)
856 - sizeof(SECURITY_DESCRIPTOR_HEADER
);
858 /* if hash is not the same, the key is not present */
859 if (psdh
&& (size
> 0)
860 && (psdh
->keyhash
== hash
)) {
861 /* if hash is the same */
862 /* check the whole record */
863 realign
.parts
.dataoffsh
= psdh
->dataoffsh
;
864 realign
.parts
.dataoffsl
= psdh
->dataoffsl
;
865 offs
= le64_to_cpu(realign
.all
)
866 + sizeof(SECURITY_DESCRIPTOR_HEADER
);
867 oldattr
= (char*)ntfs_malloc(size
);
869 rdsize
= ntfs_attr_data_read(
872 oldattr
, size
, offs
);
873 found
= (rdsize
== size
)
874 && !memcmp(oldattr
,attr
,size
);
876 /* if the records do not compare */
877 /* (hash collision), try next one */
879 entry
= ntfs_index_next(
886 } while (collision
&& entry
);
888 securid
= psdh
->keysecurid
;
892 securid
= const_cpu_to_le32(0);
896 * have to build a new one
898 securid
= entersecurityattr(vol
,
904 if (--vol
->secure_reentry
)
905 ntfs_log_perror("Reentry error, check no multithreading\n");
911 * Update the security descriptor of a file
912 * Either as an attribute (complying with pre v3.x NTFS version)
913 * or, when possible, as an entry in $Secure (for NTFS v3.x)
915 * returns 0 if success
918 static int update_secur_descr(ntfs_volume
*vol
,
919 char *newattr
, ntfs_inode
*ni
)
926 newattrsz
= ntfs_attr_size(newattr
);
928 #if !FORCE_FORMAT_v1x
929 if ((vol
->major_ver
< 3) || !vol
->secure_ni
) {
932 /* update for NTFS format v1.x */
934 /* update the old security attribute */
935 na
= ntfs_attr_open(ni
, AT_SECURITY_DESCRIPTOR
, AT_UNNAMED
, 0);
937 /* resize attribute */
938 res
= ntfs_attr_truncate(na
, (s64
) newattrsz
);
939 /* overwrite value */
941 written
= (int)ntfs_attr_pwrite(na
, (s64
) 0,
942 (s64
) newattrsz
, newattr
);
943 if (written
!= newattrsz
) {
944 ntfs_log_error("Failed to update "
945 "a v1.x security descriptor\n");
952 /* if old security attribute was found, also */
953 /* truncate standard information attribute to v1.x */
954 /* this is needed when security data is wanted */
955 /* as v1.x though volume is formatted for v3.x */
956 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
959 clear_nino_flag(ni
, v3_Extensions
);
961 * Truncating the record does not sweep extensions
962 * from copy in memory. Clear security_id to be safe
964 ni
->security_id
= const_cpu_to_le32(0);
965 res
= ntfs_attr_truncate(na
, (s64
)48);
967 clear_nino_flag(ni
, v3_Extensions
);
971 * insert the new security attribute if there
974 res
= ntfs_attr_add(ni
, AT_SECURITY_DESCRIPTOR
,
975 AT_UNNAMED
, 0, (u8
*)newattr
,
978 #if !FORCE_FORMAT_v1x
981 /* update for NTFS format v3.x */
985 securid
= setsecurityattr(vol
,
986 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
989 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
993 if (!test_nino_flag(ni
, v3_Extensions
)) {
994 /* expand standard information attribute to v3.x */
995 res
= ntfs_attr_truncate(na
,
996 (s64
)sizeof(STANDARD_INFORMATION
));
997 ni
->owner_id
= const_cpu_to_le32(0);
998 ni
->quota_charged
= const_cpu_to_le64(0);
999 ni
->usn
= const_cpu_to_le64(0);
1000 ntfs_attr_remove(ni
,
1001 AT_SECURITY_DESCRIPTOR
,
1004 set_nino_flag(ni
, v3_Extensions
);
1005 ni
->security_id
= securid
;
1006 ntfs_attr_close(na
);
1008 ntfs_log_error("Failed to update "
1009 "standard informations\n");
1018 /* mark node as dirty */
1024 * Upgrade the security descriptor of a file
1025 * This is intended to allow graceful upgrades for files which
1026 * were created in previous versions, with a security attributes
1027 * and no security id.
1029 * It will allocate a security id and replace the individual
1030 * security attribute by a reference to the global one
1032 * Special files are not upgraded (currently / and files in
1035 * Though most code is similar to update_secur_desc() it has
1036 * been kept apart to facilitate the further processing of
1037 * special cases or even to remove it if found dangerous.
1039 * returns 0 if success,
1040 * 1 if not upgradable. This is not an error.
1041 * -1 if there is a problem
1044 static int upgrade_secur_desc(ntfs_volume
*vol
,
1045 const char *attr
, ntfs_inode
*ni
)
1053 * upgrade requires NTFS format v3.x
1054 * also refuse upgrading for special files
1055 * whose number is less than FILE_first_user
1058 if ((vol
->major_ver
>= 3)
1059 && (ni
->mft_no
>= FILE_first_user
)) {
1060 attrsz
= ntfs_attr_size(attr
);
1061 securid
= setsecurityattr(vol
,
1062 (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
,
1065 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);
1132 #if defined(__sun) && defined (__SVR4)
1135 * Check whether current thread owner is member of file group
1136 * Solaris/OpenIndiana version
1137 * Should not be called for user root, however the group may be root
1139 * The group list is available in "/proc/$PID/cred"
1143 static BOOL
groupmember(struct SECURITY_CONTEXT
*scx
, uid_t uid
, gid_t gid
)
1145 typedef struct prcred
{
1146 uid_t pr_euid
; /* effective user id */
1147 uid_t pr_ruid
; /* real user id */
1148 uid_t pr_suid
; /* saved user id (from exec) */
1149 gid_t pr_egid
; /* effective group id */
1150 gid_t pr_rgid
; /* real group id */
1151 gid_t pr_sgid
; /* saved group id (from exec) */
1152 int pr_ngroups
; /* number of supplementary groups */
1153 gid_t pr_groups
[1]; /* array of supplementary groups */
1155 enum { readset
= 16 };
1158 gid_t groups
[readset
];
1168 if (scx
->vol
->secure_flags
& (1 << SECURITY_STATICGRPS
))
1169 ismember
= staticgroupmember(scx
, uid
, gid
);
1171 ismember
= FALSE
; /* default return */
1173 sprintf(filename
,"/proc/%u/cred",tid
);
1174 fd
= open(filename
,O_RDONLY
);
1176 got
= read(fd
, &basecreds
, sizeof(prcred_t
));
1177 if (got
== sizeof(prcred_t
)) {
1178 if (basecreds
.pr_egid
== gid
)
1180 p
= basecreds
.pr_groups
;
1184 && (k
< basecreds
.pr_ngroups
)
1191 got
= read(fd
, groups
,
1192 readset
*sizeof(gid_t
));
1193 cnt
= got
/sizeof(gid_t
);
1198 && (k
< basecreds
.pr_ngroups
))
1207 #else /* defined(__sun) && defined (__SVR4) */
1210 * Check whether current thread owner is member of file group
1212 * Should not be called for user root, however the group may be root
1214 * As indicated by Miklos Szeredi :
1216 * The group list is available in
1218 * /proc/$PID/task/$TID/status
1220 * and fuse supplies TID in get_fuse_context()->pid. The only problem is
1221 * finding out PID, for which I have no good solution, except to iterate
1222 * through all processes. This is rather slow, but may be speeded up
1223 * with caching and heuristics (for single threaded programs PID = TID).
1225 * The following implementation gets the group list from
1226 * /proc/$TID/task/$TID/status which apparently exists and
1227 * contains the same data.
1230 static BOOL
groupmember(struct SECURITY_CONTEXT
*scx
, uid_t uid
, gid_t gid
)
1232 static char key
[] = "\nGroups:";
1235 enum { INKEY
, INSEP
, INNUM
, INEND
} state
;
1245 if (scx
->vol
->secure_flags
& (1 << SECURITY_STATICGRPS
))
1246 ismember
= staticgroupmember(scx
, uid
, gid
);
1248 ismember
= FALSE
; /* default return */
1250 sprintf(filename
,"/proc/%u/task/%u/status",tid
,tid
);
1251 fd
= open(filename
,O_RDONLY
);
1253 got
= read(fd
, buf
, BUFSZ
);
1260 * A simple automaton to process lines like
1261 * Groups: 14 500 513
1267 got
= read(fd
, buf
, BUFSZ
);
1270 c
= *p
++; /* 0 at end of file */
1274 if (key
[matched
] == c
) {
1275 if (!key
[++matched
])
1284 if ((c
>= '0') && (c
<= '9')) {
1288 if ((c
!= ' ') && (c
!= '\t'))
1292 if ((c
>= '0') && (c
<= '9'))
1293 grp
= grp
*10 + c
- '0';
1295 ismember
= (grp
== gid
);
1296 if ((c
!= ' ') && (c
!= '\t'))
1304 } while (!ismember
&& c
&& (state
!= INEND
));
1307 ntfs_log_error("No group record found in %s\n",filename
);
1309 ntfs_log_error("Could not open %s\n",filename
);
1314 #endif /* defined(__sun) && defined (__SVR4) */
1317 * Cacheing is done two-way :
1318 * - from uid, gid and perm to securid (CACHED_SECURID)
1319 * - from a securid to uid, gid and perm (CACHED_PERMISSIONS)
1321 * CACHED_SECURID data is kept in a most-recent-first list
1322 * which should not be too long to be efficient. Its optimal
1323 * size is depends on usage and is hard to determine.
1325 * CACHED_PERMISSIONS data is kept in a two-level indexed array. It
1326 * is optimal at the expense of storage. Use of a most-recent-first
1327 * list would save memory and provide similar performances for
1328 * standard usage, but not for file servers with too many file
1331 * CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS
1332 * for legacy directories which were not allocated a security_id
1333 * it is organized in a most-recent-first list.
1335 * In main caches, data is never invalidated, as the meaning of
1336 * a security_id only changes when user mapping is changed, which
1337 * current implies remounting. However returned entries may be
1338 * overwritten at next update, so data has to be copied elsewhere
1339 * before another cache update is made.
1340 * In legacy cache, data has to be invalidated when protection is
1343 * Though the same data may be found in both list, they
1344 * must be kept separately : the interpretation of ACL
1345 * in both direction are approximations which could be non
1346 * reciprocal for some configuration of the user mapping data
1348 * During the process of recompiling ntfs-3g from a tgz archive,
1349 * security processing added 7.6% to the cpu time used by ntfs-3g
1350 * and 30% if the cache is disabled.
1353 static struct PERMISSIONS_CACHE
*create_caches(struct SECURITY_CONTEXT
*scx
,
1356 struct PERMISSIONS_CACHE
*cache
;
1357 unsigned int index1
;
1360 cache
= (struct PERMISSIONS_CACHE
*)NULL
;
1361 /* create the first permissions blocks */
1362 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1363 cache
= (struct PERMISSIONS_CACHE
*)
1364 ntfs_malloc(sizeof(struct PERMISSIONS_CACHE
)
1365 + index1
*sizeof(struct CACHED_PERMISSIONS
*));
1367 cache
->head
.last
= index1
;
1368 cache
->head
.p_reads
= 0;
1369 cache
->head
.p_hits
= 0;
1370 cache
->head
.p_writes
= 0;
1371 *scx
->pseccache
= cache
;
1372 for (i
=0; i
<=index1
; i
++)
1373 cache
->cachetable
[i
]
1374 = (struct CACHED_PERMISSIONS
*)NULL
;
1380 * Free memory used by caches
1381 * The only purpose is to facilitate the detection of memory leaks
1384 static void free_caches(struct SECURITY_CONTEXT
*scx
)
1386 unsigned int index1
;
1387 struct PERMISSIONS_CACHE
*pseccache
;
1389 pseccache
= *scx
->pseccache
;
1391 for (index1
=0; index1
<=pseccache
->head
.last
; index1
++)
1392 if (pseccache
->cachetable
[index1
]) {
1394 struct CACHED_PERMISSIONS
*cacheentry
;
1395 unsigned int index2
;
1397 for (index2
=0; index2
<(1<< CACHE_PERMISSIONS_BITS
); index2
++) {
1398 cacheentry
= &pseccache
->cachetable
[index1
][index2
];
1399 if (cacheentry
->valid
1400 && cacheentry
->pxdesc
)
1401 free(cacheentry
->pxdesc
);
1404 free(pseccache
->cachetable
[index1
]);
1410 static int compare(const struct CACHED_SECURID
*cached
,
1411 const struct CACHED_SECURID
*item
)
1417 /* only compare data and sizes */
1418 csize
= (cached
->variable
?
1419 sizeof(struct POSIX_ACL
)
1420 + (((struct POSIX_SECURITY
*)cached
->variable
)->acccnt
1421 + ((struct POSIX_SECURITY
*)cached
->variable
)->defcnt
)
1422 *sizeof(struct POSIX_ACE
) :
1424 isize
= (item
->variable
?
1425 sizeof(struct POSIX_ACL
)
1426 + (((struct POSIX_SECURITY
*)item
->variable
)->acccnt
1427 + ((struct POSIX_SECURITY
*)item
->variable
)->defcnt
)
1428 *sizeof(struct POSIX_ACE
) :
1430 return ((cached
->uid
!= item
->uid
)
1431 || (cached
->gid
!= item
->gid
)
1432 || (cached
->dmode
!= item
->dmode
)
1436 && memcmp(&((struct POSIX_SECURITY
*)cached
->variable
)->acl
,
1437 &((struct POSIX_SECURITY
*)item
->variable
)->acl
, csize
)));
1439 return ((cached
->uid
!= item
->uid
)
1440 || (cached
->gid
!= item
->gid
)
1441 || (cached
->dmode
!= item
->dmode
));
1445 static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY
*cached
,
1446 const struct CACHED_PERMISSIONS_LEGACY
*item
)
1448 return (cached
->mft_no
!= item
->mft_no
);
1452 * Resize permission cache table
1453 * do not call unless resizing is needed
1455 * If allocation fails, the cache size is not updated
1456 * Lack of memory is not considered as an error, the cache is left
1457 * consistent and errno is not set.
1460 static void resize_cache(struct SECURITY_CONTEXT
*scx
,
1463 struct PERMISSIONS_CACHE
*oldcache
;
1464 struct PERMISSIONS_CACHE
*newcache
;
1467 unsigned int index1
;
1470 oldcache
= *scx
->pseccache
;
1471 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1472 newcnt
= index1
+ 1;
1473 if (newcnt
<= ((CACHE_PERMISSIONS_SIZE
1474 + (1 << CACHE_PERMISSIONS_BITS
)
1475 - 1) >> CACHE_PERMISSIONS_BITS
)) {
1476 /* expand cache beyond current end, do not use realloc() */
1477 /* to avoid losing data when there is no more memory */
1478 oldcnt
= oldcache
->head
.last
+ 1;
1479 newcache
= (struct PERMISSIONS_CACHE
*)
1481 sizeof(struct PERMISSIONS_CACHE
)
1482 + (newcnt
- 1)*sizeof(struct CACHED_PERMISSIONS
*));
1484 memcpy(newcache
,oldcache
,
1485 sizeof(struct PERMISSIONS_CACHE
)
1486 + (oldcnt
- 1)*sizeof(struct CACHED_PERMISSIONS
*));
1488 /* mark new entries as not valid */
1489 for (i
=newcache
->head
.last
+1; i
<=index1
; i
++)
1490 newcache
->cachetable
[i
]
1491 = (struct CACHED_PERMISSIONS
*)NULL
;
1492 newcache
->head
.last
= index1
;
1493 *scx
->pseccache
= newcache
;
1499 * Enter uid, gid and mode into cache, if possible
1501 * returns the updated or created cache entry,
1502 * or NULL if not possible (typically if there is no
1503 * security id associated)
1507 static struct CACHED_PERMISSIONS
*enter_cache(struct SECURITY_CONTEXT
*scx
,
1508 ntfs_inode
*ni
, uid_t uid
, gid_t gid
,
1509 struct POSIX_SECURITY
*pxdesc
)
1511 static struct CACHED_PERMISSIONS
*enter_cache(struct SECURITY_CONTEXT
*scx
,
1512 ntfs_inode
*ni
, uid_t uid
, gid_t gid
, mode_t mode
)
1515 struct CACHED_PERMISSIONS
*cacheentry
;
1516 struct CACHED_PERMISSIONS
*cacheblock
;
1517 struct PERMISSIONS_CACHE
*pcache
;
1521 struct POSIX_SECURITY
*pxcached
;
1523 unsigned int index1
;
1524 unsigned int index2
;
1527 /* cacheing is only possible if a security_id has been defined */
1528 if (test_nino_flag(ni
, v3_Extensions
)
1529 && ni
->security_id
) {
1531 * Immediately test the most frequent situation
1532 * where the entry exists
1534 securindex
= le32_to_cpu(ni
->security_id
);
1535 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1536 index2
= securindex
& ((1 << CACHE_PERMISSIONS_BITS
) - 1);
1537 pcache
= *scx
->pseccache
;
1539 && (pcache
->head
.last
>= index1
)
1540 && pcache
->cachetable
[index1
]) {
1541 cacheentry
= &pcache
->cachetable
[index1
][index2
];
1542 cacheentry
->uid
= uid
;
1543 cacheentry
->gid
= gid
;
1545 if (cacheentry
->valid
&& cacheentry
->pxdesc
)
1546 free(cacheentry
->pxdesc
);
1548 pxsize
= sizeof(struct POSIX_SECURITY
)
1549 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1550 pxcached
= (struct POSIX_SECURITY
*)malloc(pxsize
);
1552 memcpy(pxcached
, pxdesc
, pxsize
);
1553 cacheentry
->pxdesc
= pxcached
;
1555 cacheentry
->valid
= 0;
1556 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1558 cacheentry
->mode
= pxdesc
->mode
& 07777;
1560 cacheentry
->pxdesc
= (struct POSIX_SECURITY
*)NULL
;
1562 cacheentry
->mode
= mode
& 07777;
1564 cacheentry
->inh_fileid
= const_cpu_to_le32(0);
1565 cacheentry
->inh_dirid
= const_cpu_to_le32(0);
1566 cacheentry
->valid
= 1;
1567 pcache
->head
.p_writes
++;
1570 /* create the first cache block */
1571 pcache
= create_caches(scx
, securindex
);
1573 if (index1
> pcache
->head
.last
) {
1574 resize_cache(scx
, securindex
);
1575 pcache
= *scx
->pseccache
;
1578 /* allocate block, if cache table was allocated */
1579 if (pcache
&& (index1
<= pcache
->head
.last
)) {
1580 cacheblock
= (struct CACHED_PERMISSIONS
*)
1581 malloc(sizeof(struct CACHED_PERMISSIONS
)
1582 << CACHE_PERMISSIONS_BITS
);
1583 pcache
->cachetable
[index1
] = cacheblock
;
1584 for (i
=0; i
<(1 << CACHE_PERMISSIONS_BITS
); i
++)
1585 cacheblock
[i
].valid
= 0;
1586 cacheentry
= &cacheblock
[index2
];
1588 cacheentry
->uid
= uid
;
1589 cacheentry
->gid
= gid
;
1592 pxsize
= sizeof(struct POSIX_SECURITY
)
1593 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1594 pxcached
= (struct POSIX_SECURITY
*)malloc(pxsize
);
1596 memcpy(pxcached
, pxdesc
, pxsize
);
1597 cacheentry
->pxdesc
= pxcached
;
1599 cacheentry
->valid
= 0;
1600 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1602 cacheentry
->mode
= pxdesc
->mode
& 07777;
1604 cacheentry
->pxdesc
= (struct POSIX_SECURITY
*)NULL
;
1606 cacheentry
->mode
= mode
& 07777;
1608 cacheentry
->inh_fileid
= const_cpu_to_le32(0);
1609 cacheentry
->inh_dirid
= const_cpu_to_le32(0);
1610 cacheentry
->valid
= 1;
1611 pcache
->head
.p_writes
++;
1614 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1617 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1618 #if CACHE_LEGACY_SIZE
1619 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
1620 struct CACHED_PERMISSIONS_LEGACY wanted
;
1621 struct CACHED_PERMISSIONS_LEGACY
*legacy
;
1623 wanted
.perm
.uid
= uid
;
1624 wanted
.perm
.gid
= gid
;
1626 wanted
.perm
.mode
= pxdesc
->mode
& 07777;
1627 wanted
.perm
.inh_fileid
= const_cpu_to_le32(0);
1628 wanted
.perm
.inh_dirid
= const_cpu_to_le32(0);
1629 wanted
.mft_no
= ni
->mft_no
;
1630 wanted
.variable
= (void*)pxdesc
;
1631 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
1632 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1634 wanted
.perm
.mode
= mode
& 07777;
1635 wanted
.perm
.inh_fileid
= const_cpu_to_le32(0);
1636 wanted
.perm
.inh_dirid
= const_cpu_to_le32(0);
1637 wanted
.mft_no
= ni
->mft_no
;
1638 wanted
.variable
= (void*)NULL
;
1641 legacy
= (struct CACHED_PERMISSIONS_LEGACY
*)ntfs_enter_cache(
1642 scx
->vol
->legacy_cache
, GENERIC(&wanted
),
1643 (cache_compare
)leg_compare
);
1645 cacheentry
= &legacy
->perm
;
1648 * give direct access to the cached pxdesc
1649 * in the permissions structure
1651 cacheentry
->pxdesc
= legacy
->variable
;
1657 return (cacheentry
);
1661 * Fetch owner, group and permission of a file, if cached
1663 * Beware : do not use the returned entry after a cache update :
1664 * the cache may be relocated making the returned entry meaningless
1666 * returns the cache entry, or NULL if not available
1669 static struct CACHED_PERMISSIONS
*fetch_cache(struct SECURITY_CONTEXT
*scx
,
1672 struct CACHED_PERMISSIONS
*cacheentry
;
1673 struct PERMISSIONS_CACHE
*pcache
;
1675 unsigned int index1
;
1676 unsigned int index2
;
1678 /* cacheing is only possible if a security_id has been defined */
1679 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1680 if (test_nino_flag(ni
, v3_Extensions
)
1681 && (ni
->security_id
)) {
1682 securindex
= le32_to_cpu(ni
->security_id
);
1683 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1684 index2
= securindex
& ((1 << CACHE_PERMISSIONS_BITS
) - 1);
1685 pcache
= *scx
->pseccache
;
1687 && (pcache
->head
.last
>= index1
)
1688 && pcache
->cachetable
[index1
]) {
1689 cacheentry
= &pcache
->cachetable
[index1
][index2
];
1690 /* reject if entry is not valid */
1691 if (!cacheentry
->valid
)
1692 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1694 pcache
->head
.p_hits
++;
1696 pcache
->head
.p_reads
++;
1699 #if CACHE_LEGACY_SIZE
1701 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1702 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
1703 struct CACHED_PERMISSIONS_LEGACY wanted
;
1704 struct CACHED_PERMISSIONS_LEGACY
*legacy
;
1706 wanted
.mft_no
= ni
->mft_no
;
1707 wanted
.variable
= (void*)NULL
;
1709 legacy
= (struct CACHED_PERMISSIONS_LEGACY
*)ntfs_fetch_cache(
1710 scx
->vol
->legacy_cache
, GENERIC(&wanted
),
1711 (cache_compare
)leg_compare
);
1712 if (legacy
) cacheentry
= &legacy
->perm
;
1717 if (cacheentry
&& !cacheentry
->pxdesc
) {
1718 ntfs_log_error("No Posix descriptor in cache\n");
1719 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1722 return (cacheentry
);
1726 * Retrieve a security attribute from $Secure
1729 static char *retrievesecurityattr(ntfs_volume
*vol
, SII_INDEX_KEY id
)
1744 ntfs_index_context
*xsii
;
1747 securattr
= (char*)NULL
;
1748 ni
= vol
->secure_ni
;
1749 xsii
= vol
->secure_xsii
;
1751 ntfs_index_ctx_reinit(xsii
);
1753 !ntfs_index_lookup((char*)&id
,
1754 sizeof(SII_INDEX_KEY
), xsii
);
1756 psii
= (struct SII
*)xsii
->entry
;
1758 (size_t) le32_to_cpu(psii
->datasize
)
1759 - sizeof(SECURITY_DESCRIPTOR_HEADER
);
1760 /* work around bad alignment problem */
1761 realign
.parts
.dataoffsh
= psii
->dataoffsh
;
1762 realign
.parts
.dataoffsl
= psii
->dataoffsl
;
1763 offs
= le64_to_cpu(realign
.all
)
1764 + sizeof(SECURITY_DESCRIPTOR_HEADER
);
1766 securattr
= (char*)ntfs_malloc(size
);
1768 rdsize
= ntfs_attr_data_read(
1770 securattr
, size
, offs
);
1771 if ((rdsize
!= size
)
1772 || !ntfs_valid_descr(securattr
,
1774 /* error to be logged by caller */
1776 securattr
= (char*)NULL
;
1780 if (errno
!= ENOENT
)
1781 ntfs_log_perror("Inconsistency in index $SII");
1784 ntfs_log_error("Failed to retrieve a security descriptor\n");
1791 * Get the security descriptor associated to a file
1794 * - read the security descriptor attribute (v1.x format)
1795 * - or find the descriptor in $Secure:$SDS (v3.x format)
1797 * in both case, sanity checks are done on the attribute and
1798 * the descriptor can be assumed safe
1800 * The returned descriptor is dynamically allocated and has to be freed
1803 static char *getsecurityattr(ntfs_volume
*vol
, ntfs_inode
*ni
)
1805 SII_INDEX_KEY securid
;
1810 * Warning : in some situations, after fixing by chkdsk,
1811 * v3_Extensions are marked present (long standard informations)
1812 * with a default security descriptor inserted in an
1815 if (test_nino_flag(ni
, v3_Extensions
)
1816 && vol
->secure_ni
&& ni
->security_id
) {
1817 /* get v3.x descriptor in $Secure */
1818 securid
.security_id
= ni
->security_id
;
1819 securattr
= retrievesecurityattr(vol
,securid
);
1821 ntfs_log_error("Bad security descriptor for 0x%lx\n",
1822 (long)le32_to_cpu(ni
->security_id
));
1824 /* get v1.x security attribute */
1826 securattr
= ntfs_attr_readall(ni
, AT_SECURITY_DESCRIPTOR
,
1827 AT_UNNAMED
, 0, &readallsz
);
1828 if (securattr
&& !ntfs_valid_descr(securattr
, readallsz
)) {
1829 ntfs_log_error("Bad security descriptor for inode %lld\n",
1830 (long long)ni
->mft_no
);
1832 securattr
= (char*)NULL
;
1837 * in some situations, there is no security
1838 * descriptor, and chkdsk does not detect or fix
1839 * anything. This could be a normal situation.
1840 * When this happens, simulate a descriptor with
1841 * minimum rights, so that a real descriptor can
1842 * be created by chown or chmod
1844 ntfs_log_error("No security descriptor found for inode %lld\n",
1845 (long long)ni
->mft_no
);
1846 securattr
= ntfs_build_descr(0, 0, adminsid
, adminsid
);
1854 * Determine which access types to a file are allowed
1855 * according to the relation of current process to the file
1857 * Do not call if default_permissions is set
1860 static int access_check_posix(struct SECURITY_CONTEXT
*scx
,
1861 struct POSIX_SECURITY
*pxdesc
, mode_t request
,
1862 uid_t uid
, gid_t gid
)
1864 struct POSIX_ACE
*pxace
;
1873 perms
= pxdesc
->mode
;
1874 /* owner and root access */
1875 if (!scx
->uid
|| (uid
== scx
->uid
)) {
1877 /* root access if owner or other execution */
1881 /* root access if some group execution */
1884 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1885 pxace
= &pxdesc
->acl
.ace
[i
];
1886 switch (pxace
->tag
) {
1887 case POSIX_ACL_USER_OBJ
:
1888 case POSIX_ACL_GROUP_OBJ
:
1889 case POSIX_ACL_GROUP
:
1890 groupperms
|= pxace
->perms
;
1892 case POSIX_ACL_MASK
:
1893 mask
= pxace
->perms
& 7;
1899 perms
= (groupperms
& mask
& 1) | 6;
1905 * analyze designated users, get mask
1906 * and identify whether we need to check
1907 * the group memberships. The groups are
1908 * not needed when all groups have the
1909 * same permissions as other for the
1916 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1917 pxace
= &pxdesc
->acl
.ace
[i
];
1918 switch (pxace
->tag
) {
1919 case POSIX_ACL_USER
:
1920 if ((uid_t
)pxace
->id
== scx
->uid
)
1921 userperms
= pxace
->perms
;
1923 case POSIX_ACL_MASK
:
1924 mask
= pxace
->perms
& 7;
1926 case POSIX_ACL_GROUP_OBJ
:
1927 case POSIX_ACL_GROUP
:
1928 if (((pxace
->perms
& mask
) ^ perms
)
1929 & (request
>> 6) & 7)
1936 /* designated users */
1938 perms
= (perms
& 07000) + (userperms
& mask
);
1939 else if (!needgroups
)
1943 if (!(~(perms
>> 3) & request
& mask
)
1944 && ((gid
== scx
->gid
)
1945 || groupmember(scx
, scx
->uid
, gid
)))
1951 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1952 pxace
= &pxdesc
->acl
.ace
[i
];
1953 if ((pxace
->tag
== POSIX_ACL_GROUP
)
1954 && groupmember(scx
, uid
, pxace
->id
)) {
1955 if (!(~pxace
->perms
& request
& mask
))
1956 groupperms
= pxace
->perms
;
1960 if (groupperms
>= 0)
1961 perms
= (perms
& 07000) + (groupperms
& mask
);
1974 * Get permissions to access a file
1975 * Takes into account the relation of user to file (owner, group, ...)
1976 * Do no use as mode of the file
1977 * Do no call if default_permissions is set
1979 * returns -1 if there is a problem
1982 static int ntfs_get_perm(struct SECURITY_CONTEXT
*scx
,
1983 ntfs_inode
* ni
, mode_t request
)
1985 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
1986 const struct CACHED_PERMISSIONS
*cached
;
1988 const SID
*usid
; /* owner of file/directory */
1989 const SID
*gsid
; /* group of file/directory */
1994 struct POSIX_SECURITY
*pxdesc
;
1996 if (!scx
->mapping
[MAPUSERS
])
1999 /* check whether available in cache */
2000 cached
= fetch_cache(scx
,ni
);
2004 perm
= access_check_posix(scx
,cached
->pxdesc
,request
,uid
,gid
);
2006 perm
= 0; /* default to no permission */
2007 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2008 != const_cpu_to_le16(0);
2009 securattr
= getsecurityattr(scx
->vol
, ni
);
2011 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2013 gsid
= (const SID
*)&
2014 securattr
[le32_to_cpu(phead
->group
)];
2015 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2017 usid
= ntfs_acl_owner(securattr
);
2018 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2021 perm
= pxdesc
->mode
& 07777;
2024 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2026 usid
= (const SID
*)&
2027 securattr
[le32_to_cpu(phead
->owner
)];
2028 pxdesc
= ntfs_build_permissions_posix(scx
,securattr
,
2031 perm
= pxdesc
->mode
& 07777;
2034 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2035 uid
= find_tenant(scx
, securattr
);
2039 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2042 * Create a security id if there were none
2043 * and upgrade option is selected
2045 if (!test_nino_flag(ni
, v3_Extensions
)
2047 && (scx
->vol
->secure_flags
2048 & (1 << SECURITY_ADDSECURIDS
))) {
2049 upgrade_secur_desc(scx
->vol
,
2052 * fetch owner and group for cacheing
2053 * if there is a securid
2056 if (test_nino_flag(ni
, v3_Extensions
)
2058 enter_cache(scx
, ni
, uid
,
2062 perm
= access_check_posix(scx
,pxdesc
,request
,uid
,gid
);
2078 * returns size or -errno if there is a problem
2079 * if size was too small, no copy is done and errno is not set,
2080 * the caller is expected to issue a new call
2083 int ntfs_get_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2084 const char *name
, char *value
, size_t size
)
2086 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2087 struct POSIX_SECURITY
*pxdesc
;
2088 const struct CACHED_PERMISSIONS
*cached
;
2090 const SID
*usid
; /* owner of file/directory */
2091 const SID
*gsid
; /* group of file/directory */
2097 outsize
= 0; /* default to error */
2098 if (!scx
->mapping
[MAPUSERS
])
2101 /* check whether available in cache */
2102 cached
= fetch_cache(scx
,ni
);
2104 pxdesc
= cached
->pxdesc
;
2106 securattr
= getsecurityattr(scx
->vol
, ni
);
2107 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2108 != const_cpu_to_le16(0);
2111 (const SECURITY_DESCRIPTOR_RELATIVE
*)
2113 gsid
= (const SID
*)&
2114 securattr
[le32_to_cpu(phead
->group
)];
2116 usid
= ntfs_acl_owner(securattr
);
2118 usid
= (const SID
*)&
2119 securattr
[le32_to_cpu(phead
->owner
)];
2121 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2125 * fetch owner and group for cacheing
2129 * Create a security id if there were none
2130 * and upgrade option is selected
2132 if (!test_nino_flag(ni
, v3_Extensions
)
2133 && (scx
->vol
->secure_flags
2134 & (1 << SECURITY_ADDSECURIDS
))) {
2135 upgrade_secur_desc(scx
->vol
,
2139 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2141 if (!(pxdesc
->mode
& 07777)
2142 && ntfs_same_sid(usid
, adminsid
)) {
2143 uid
= find_tenant(scx
,
2146 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2148 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2149 if (pxdesc
->tagsset
& POSIX_ACL_EXTENSIONS
)
2150 enter_cache(scx
, ni
, uid
,
2155 pxdesc
= (struct POSIX_SECURITY
*)NULL
;
2159 if (ntfs_valid_posix(pxdesc
)) {
2160 if (!strcmp(name
,"system.posix_acl_default")) {
2162 & MFT_RECORD_IS_DIRECTORY
)
2163 outsize
= sizeof(struct POSIX_ACL
)
2164 + pxdesc
->defcnt
*sizeof(struct POSIX_ACE
);
2167 * getting default ACL from plain file :
2168 * return EACCES if size > 0 as
2169 * indicated in the man, but return ok
2170 * if size == 0, so that ls does not
2177 outsize
= sizeof(struct POSIX_ACL
);
2179 if (outsize
&& (outsize
<= size
)) {
2180 memcpy(value
,&pxdesc
->acl
,sizeof(struct POSIX_ACL
));
2181 memcpy(&value
[sizeof(struct POSIX_ACL
)],
2182 &pxdesc
->acl
.ace
[pxdesc
->firstdef
],
2183 outsize
-sizeof(struct POSIX_ACL
));
2186 outsize
= sizeof(struct POSIX_ACL
)
2187 + pxdesc
->acccnt
*sizeof(struct POSIX_ACE
);
2188 if (outsize
<= size
)
2189 memcpy(value
,&pxdesc
->acl
,outsize
);
2194 ntfs_log_error("Invalid Posix ACL built\n");
2201 return (outsize
? (int)outsize
: -errno
);
2204 #else /* POSIXACLS */
2208 * Get permissions to access a file
2209 * Takes into account the relation of user to file (owner, group, ...)
2210 * Do no use as mode of the file
2212 * returns -1 if there is a problem
2215 static int ntfs_get_perm(struct SECURITY_CONTEXT
*scx
,
2216 ntfs_inode
*ni
, mode_t request
)
2218 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2219 const struct CACHED_PERMISSIONS
*cached
;
2221 const SID
*usid
; /* owner of file/directory */
2222 const SID
*gsid
; /* group of file/directory */
2228 if (!scx
->mapping
[MAPUSERS
] || (!scx
->uid
&& !(request
& S_IEXEC
)))
2231 /* check whether available in cache */
2232 cached
= fetch_cache(scx
,ni
);
2234 perm
= cached
->mode
;
2238 perm
= 0; /* default to no permission */
2239 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2240 != const_cpu_to_le16(0);
2241 securattr
= getsecurityattr(scx
->vol
, ni
);
2243 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2245 gsid
= (const SID
*)&
2246 securattr
[le32_to_cpu(phead
->group
)];
2247 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2249 usid
= ntfs_acl_owner(securattr
);
2250 perm
= ntfs_build_permissions(securattr
,
2252 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2254 usid
= (const SID
*)&
2255 securattr
[le32_to_cpu(phead
->owner
)];
2256 perm
= ntfs_build_permissions(securattr
,
2258 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2259 uid
= find_tenant(scx
, securattr
);
2263 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2266 * Create a security id if there were none
2267 * and upgrade option is selected
2269 if (!test_nino_flag(ni
, v3_Extensions
)
2271 && (scx
->vol
->secure_flags
2272 & (1 << SECURITY_ADDSECURIDS
))) {
2273 upgrade_secur_desc(scx
->vol
,
2276 * fetch owner and group for cacheing
2277 * if there is a securid
2280 if (test_nino_flag(ni
, v3_Extensions
)
2282 enter_cache(scx
, ni
, uid
,
2293 /* root access and execution */
2299 if (uid
== scx
->uid
)
2303 * avoid checking group membership
2304 * when the requested perms for group
2305 * are the same as perms for other
2307 if ((gid
== scx
->gid
)
2308 || ((((perm
>> 3) ^ perm
)
2309 & (request
>> 6) & 7)
2310 && groupmember(scx
, scx
->uid
, gid
)))
2319 #endif /* POSIXACLS */
2324 * Returns size or -errno if there is a problem
2325 * if size was too small, no copy is done and errno is not set,
2326 * the caller is expected to issue a new call
2329 int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2330 char *value
, size_t size
)
2335 outsize
= 0; /* default to no data and no error */
2336 securattr
= getsecurityattr(scx
->vol
, ni
);
2338 outsize
= ntfs_attr_size(securattr
);
2339 if (outsize
<= size
) {
2340 memcpy(value
,securattr
,outsize
);
2344 return (outsize
? (int)outsize
: -errno
);
2348 * Get owner, group and permissions in an stat structure
2349 * returns permissions, or -1 if there is a problem
2352 int ntfs_get_owner_mode(struct SECURITY_CONTEXT
*scx
,
2353 ntfs_inode
* ni
, struct stat
*stbuf
)
2355 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2357 const SID
*usid
; /* owner of file/directory */
2358 const SID
*gsid
; /* group of file/directory */
2359 const struct CACHED_PERMISSIONS
*cached
;
2363 struct POSIX_SECURITY
*pxdesc
;
2366 if (!scx
->mapping
[MAPUSERS
])
2369 /* check whether available in cache */
2370 cached
= fetch_cache(scx
,ni
);
2372 perm
= cached
->mode
;
2373 stbuf
->st_uid
= cached
->uid
;
2374 stbuf
->st_gid
= cached
->gid
;
2375 stbuf
->st_mode
= (stbuf
->st_mode
& ~07777) + perm
;
2377 perm
= -1; /* default to error */
2378 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2379 != const_cpu_to_le16(0);
2380 securattr
= getsecurityattr(scx
->vol
, ni
);
2383 (const SECURITY_DESCRIPTOR_RELATIVE
*)
2385 gsid
= (const SID
*)&
2386 securattr
[le32_to_cpu(phead
->group
)];
2388 usid
= ntfs_acl_owner(securattr
);
2390 usid
= (const SID
*)&
2391 securattr
[le32_to_cpu(phead
->owner
)];
2394 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
, securattr
,
2397 perm
= pxdesc
->mode
& 07777;
2401 perm
= ntfs_build_permissions(securattr
,
2405 * fetch owner and group for cacheing
2409 * Create a security id if there were none
2410 * and upgrade option is selected
2412 if (!test_nino_flag(ni
, v3_Extensions
)
2413 && (scx
->vol
->secure_flags
2414 & (1 << SECURITY_ADDSECURIDS
))) {
2415 upgrade_secur_desc(scx
->vol
,
2419 stbuf
->st_uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2421 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2428 stbuf
->st_uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2430 stbuf
->st_gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2432 (stbuf
->st_mode
& ~07777) + perm
;
2434 enter_cache(scx
, ni
, stbuf
->st_uid
,
2435 stbuf
->st_gid
, pxdesc
);
2438 enter_cache(scx
, ni
, stbuf
->st_uid
,
2439 stbuf
->st_gid
, perm
);
2452 * Get the base for a Posix inheritance and
2453 * build an inherited Posix descriptor
2456 static struct POSIX_SECURITY
*inherit_posix(struct SECURITY_CONTEXT
*scx
,
2457 ntfs_inode
*dir_ni
, mode_t mode
, BOOL isdir
)
2459 const struct CACHED_PERMISSIONS
*cached
;
2460 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2461 struct POSIX_SECURITY
*pxdesc
;
2462 struct POSIX_SECURITY
*pydesc
;
2469 pydesc
= (struct POSIX_SECURITY
*)NULL
;
2470 /* check whether parent directory is available in cache */
2471 cached
= fetch_cache(scx
,dir_ni
);
2475 pxdesc
= cached
->pxdesc
;
2477 pydesc
= ntfs_build_inherited_posix(pxdesc
,mode
,
2481 securattr
= getsecurityattr(scx
->vol
, dir_ni
);
2483 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2485 gsid
= (const SID
*)&
2486 securattr
[le32_to_cpu(phead
->group
)];
2487 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2489 usid
= ntfs_acl_owner(securattr
);
2490 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2492 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2494 usid
= (const SID
*)&
2495 securattr
[le32_to_cpu(phead
->owner
)];
2496 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2498 if (pxdesc
&& ntfs_same_sid(usid
, adminsid
)) {
2499 uid
= find_tenant(scx
, securattr
);
2501 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2505 * Create a security id if there were none
2506 * and upgrade option is selected
2508 if (!test_nino_flag(dir_ni
, v3_Extensions
)
2509 && (scx
->vol
->secure_flags
2510 & (1 << SECURITY_ADDSECURIDS
))) {
2511 upgrade_secur_desc(scx
->vol
,
2514 * fetch owner and group for cacheing
2515 * if there is a securid
2518 if (test_nino_flag(dir_ni
, v3_Extensions
)) {
2519 enter_cache(scx
, dir_ni
, uid
,
2522 pydesc
= ntfs_build_inherited_posix(pxdesc
,
2523 mode
, scx
->umask
, isdir
);
2533 * Allocate a security_id for a file being created
2535 * Returns zero if not possible (NTFS v3.x required)
2538 le32
ntfs_alloc_securid(struct SECURITY_CONTEXT
*scx
,
2539 uid_t uid
, gid_t gid
, ntfs_inode
*dir_ni
,
2540 mode_t mode
, BOOL isdir
)
2542 #if !FORCE_FORMAT_v1x
2543 const struct CACHED_SECURID
*cached
;
2544 struct CACHED_SECURID wanted
;
2545 struct POSIX_SECURITY
*pxdesc
;
2555 securid
= const_cpu_to_le32(0);
2557 #if !FORCE_FORMAT_v1x
2559 pxdesc
= inherit_posix(scx
, dir_ni
, mode
, isdir
);
2561 /* check whether target securid is known in cache */
2565 wanted
.dmode
= pxdesc
->mode
& mode
& 07777;
2566 if (isdir
) wanted
.dmode
|= 0x10000;
2567 wanted
.variable
= (void*)pxdesc
;
2568 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
2569 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2570 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2571 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2572 (cache_compare
)compare
);
2573 /* quite simple, if we are lucky */
2575 securid
= cached
->securid
;
2577 /* not in cache : make sure we can create ids */
2579 if (!cached
&& (scx
->vol
->major_ver
>= 3)) {
2580 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2581 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2582 if (!usid
|| !gsid
) {
2583 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2584 (int)uid
, (int)gid
);
2585 usid
= gsid
= adminsid
;
2587 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2590 newattrsz
= ntfs_attr_size(newattr
);
2591 securid
= setsecurityattr(scx
->vol
,
2592 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
2595 /* update cache, for subsequent use */
2596 wanted
.securid
= securid
;
2597 ntfs_enter_cache(scx
->vol
->securid_cache
,
2599 (cache_compare
)compare
);
2604 * could not build new security attribute
2605 * errno set by ntfs_build_descr()
2616 * Apply Posix inheritance to a newly created file
2617 * (for NTFS 1.x only : no securid)
2620 int ntfs_set_inherited_posix(struct SECURITY_CONTEXT
*scx
,
2621 ntfs_inode
*ni
, uid_t uid
, gid_t gid
,
2622 ntfs_inode
*dir_ni
, mode_t mode
)
2624 struct POSIX_SECURITY
*pxdesc
;
2634 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2635 pxdesc
= inherit_posix(scx
, dir_ni
, mode
, isdir
);
2637 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2638 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2639 if (!usid
|| !gsid
) {
2640 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2641 (int)uid
, (int)gid
);
2642 usid
= gsid
= adminsid
;
2644 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2647 /* Adjust Windows read-only flag */
2648 res
= update_secur_descr(scx
->vol
, newattr
, ni
);
2649 if (!res
&& !isdir
) {
2651 ni
->flags
&= ~FILE_ATTR_READONLY
;
2653 ni
->flags
|= FILE_ATTR_READONLY
;
2655 #if CACHE_LEGACY_SIZE
2656 /* also invalidate legacy cache */
2657 if (isdir
&& !ni
->security_id
) {
2658 struct CACHED_PERMISSIONS_LEGACY legacy
;
2660 legacy
.mft_no
= ni
->mft_no
;
2661 legacy
.variable
= pxdesc
;
2662 legacy
.varsize
= sizeof(struct POSIX_SECURITY
)
2663 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2664 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
2666 (cache_compare
)leg_compare
,0);
2673 * could not build new security attribute
2674 * errno set by ntfs_build_descr()
2683 le32
ntfs_alloc_securid(struct SECURITY_CONTEXT
*scx
,
2684 uid_t uid
, gid_t gid
, mode_t mode
, BOOL isdir
)
2686 #if !FORCE_FORMAT_v1x
2687 const struct CACHED_SECURID
*cached
;
2688 struct CACHED_SECURID wanted
;
2698 securid
= const_cpu_to_le32(0);
2700 #if !FORCE_FORMAT_v1x
2701 /* check whether target securid is known in cache */
2705 wanted
.dmode
= mode
& 07777;
2706 if (isdir
) wanted
.dmode
|= 0x10000;
2707 wanted
.variable
= (void*)NULL
;
2709 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2710 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2711 (cache_compare
)compare
);
2712 /* quite simple, if we are lucky */
2714 securid
= cached
->securid
;
2716 /* not in cache : make sure we can create ids */
2718 if (!cached
&& (scx
->vol
->major_ver
>= 3)) {
2719 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2720 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2721 if (!usid
|| !gsid
) {
2722 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2723 (int)uid
, (int)gid
);
2724 usid
= gsid
= adminsid
;
2726 newattr
= ntfs_build_descr(mode
, isdir
, usid
, gsid
);
2728 newattrsz
= ntfs_attr_size(newattr
);
2729 securid
= setsecurityattr(scx
->vol
,
2730 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
2733 /* update cache, for subsequent use */
2734 wanted
.securid
= securid
;
2735 ntfs_enter_cache(scx
->vol
->securid_cache
,
2737 (cache_compare
)compare
);
2742 * could not build new security attribute
2743 * errno set by ntfs_build_descr()
2754 * Update ownership and mode of a file, reusing an existing
2755 * security descriptor when possible
2757 * Returns zero if successful
2761 int ntfs_set_owner_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2762 uid_t uid
, gid_t gid
, mode_t mode
,
2763 struct POSIX_SECURITY
*pxdesc
)
2765 int ntfs_set_owner_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2766 uid_t uid
, gid_t gid
, mode_t mode
)
2770 const struct CACHED_SECURID
*cached
;
2771 struct CACHED_SECURID wanted
;
2781 /* check whether target securid is known in cache */
2783 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2786 wanted
.dmode
= mode
& 07777;
2787 if (isdir
) wanted
.dmode
|= 0x10000;
2789 wanted
.variable
= (void*)pxdesc
;
2791 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
2792 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2796 wanted
.variable
= (void*)NULL
;
2799 if (test_nino_flag(ni
, v3_Extensions
)) {
2800 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2801 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2802 (cache_compare
)compare
);
2803 /* quite simple, if we are lucky */
2805 ni
->security_id
= cached
->securid
;
2808 } else cached
= (struct CACHED_SECURID
*)NULL
;
2812 * Do not use usid and gsid from former attributes,
2813 * but recompute them to get repeatable results
2814 * which can be kept in cache.
2816 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2817 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2818 if (!usid
|| !gsid
) {
2819 ntfs_log_error("File made owned by an unmapped user/group %d/%d\n",
2821 usid
= gsid
= adminsid
;
2825 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2828 newattr
= ntfs_build_descr(mode
,
2831 newattr
= ntfs_build_descr(mode
,
2835 res
= update_secur_descr(scx
->vol
, newattr
, ni
);
2837 /* adjust Windows read-only flag */
2840 ni
->flags
&= ~FILE_ATTR_READONLY
;
2842 ni
->flags
|= FILE_ATTR_READONLY
;
2843 NInoFileNameSetDirty(ni
);
2845 /* update cache, for subsequent use */
2846 if (test_nino_flag(ni
, v3_Extensions
)) {
2847 wanted
.securid
= ni
->security_id
;
2848 ntfs_enter_cache(scx
->vol
->securid_cache
,
2850 (cache_compare
)compare
);
2852 #if CACHE_LEGACY_SIZE
2853 /* also invalidate legacy cache */
2854 if (isdir
&& !ni
->security_id
) {
2855 struct CACHED_PERMISSIONS_LEGACY legacy
;
2857 legacy
.mft_no
= ni
->mft_no
;
2859 legacy
.variable
= wanted
.variable
;
2860 legacy
.varsize
= wanted
.varsize
;
2862 legacy
.variable
= (void*)NULL
;
2865 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
2867 (cache_compare
)leg_compare
,0);
2874 * could not build new security attribute
2875 * errno set by ntfs_build_descr()
2884 * Check whether user has ownership rights on a file
2886 * Returns TRUE if allowed
2887 * if not, errno tells why
2890 BOOL
ntfs_allowed_as_owner(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
)
2892 const struct CACHED_PERMISSIONS
*cached
;
2900 processuid
= scx
->uid
;
2901 /* TODO : use CAP_FOWNER process capability */
2903 * Always allow for root
2904 * Also always allow if no mapping has been defined
2906 if (!scx
->mapping
[MAPUSERS
] || !processuid
)
2909 gotowner
= FALSE
; /* default */
2910 /* get the owner, either from cache or from old attribute */
2911 cached
= fetch_cache(scx
, ni
);
2916 oldattr
= getsecurityattr(scx
->vol
, ni
);
2919 usid
= ntfs_acl_owner(oldattr
);
2921 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2923 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2925 usid
= (const SID
*)&oldattr
2926 [le32_to_cpu(phead
->owner
)];
2928 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],
2936 /* TODO : use CAP_FOWNER process capability */
2937 if (!processuid
|| (processuid
== uid
))
2946 #ifdef HAVE_SETXATTR /* extended attributes interface required */
2951 * Set a new access or default Posix ACL to a file
2952 * (or remove ACL if no input data)
2953 * Validity of input data is checked after merging
2955 * Returns 0, or -1 if there is a problem which errno describes
2958 int ntfs_set_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2959 const char *name
, const char *value
, size_t size
,
2962 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2963 const struct CACHED_PERMISSIONS
*cached
;
2975 struct POSIX_SECURITY
*oldpxdesc
;
2976 struct POSIX_SECURITY
*newpxdesc
;
2978 /* get the current pxsec, either from cache or from old attribute */
2980 deflt
= !strcmp(name
,"system.posix_acl_default");
2982 count
= (size
- sizeof(struct POSIX_ACL
)) / sizeof(struct POSIX_ACE
);
2985 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2986 newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
2988 || (((const struct POSIX_ACL
*)value
)->version
== POSIX_VERSION
))
2989 && (!deflt
|| isdir
|| (!size
&& !value
))) {
2990 cached
= fetch_cache(scx
, ni
);
2994 oldpxdesc
= cached
->pxdesc
;
2996 newpxdesc
= ntfs_replace_acl(oldpxdesc
,
2997 (const struct POSIX_ACL
*)value
,count
,deflt
);
3000 oldattr
= getsecurityattr(scx
->vol
, ni
);
3002 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
3004 usid
= ntfs_acl_owner(oldattr
);
3006 usid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->owner
)];
3008 gsid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->group
)];
3009 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3010 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3011 oldpxdesc
= ntfs_build_permissions_posix(scx
->mapping
,
3012 oldattr
, usid
, gsid
, isdir
);
3015 exist
= oldpxdesc
->defcnt
> 0;
3017 exist
= oldpxdesc
->acccnt
> 3;
3018 if ((exist
&& (flags
& XATTR_CREATE
))
3019 || (!exist
&& (flags
& XATTR_REPLACE
))) {
3020 errno
= (exist
? EEXIST
: ENODATA
);
3022 newpxdesc
= ntfs_replace_acl(oldpxdesc
,
3023 (const struct POSIX_ACL
*)value
,count
,deflt
);
3034 processuid
= scx
->uid
;
3035 /* TODO : use CAP_FOWNER process capability */
3036 if (!processuid
|| (uid
== processuid
)) {
3038 * clear setgid if file group does
3039 * not match process group
3041 if (processuid
&& (gid
!= scx
->gid
)
3042 && !groupmember(scx
, scx
->uid
, gid
)) {
3043 newpxdesc
->mode
&= ~S_ISGID
;
3045 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3046 newpxdesc
->mode
, newpxdesc
);
3051 return (res
? -1 : 0);
3055 * Remove a default Posix ACL from a file
3057 * Returns 0, or -1 if there is a problem which errno describes
3060 int ntfs_remove_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3063 return (ntfs_set_posix_acl(scx
, ni
, name
,
3064 (const char*)NULL
, 0, 0));
3070 * Set a new NTFS ACL to a file
3072 * Returns 0, or -1 if there is a problem
3075 int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3076 const char *value
, size_t size
, int flags
)
3083 && !(flags
& XATTR_CREATE
)
3084 && ntfs_valid_descr(value
,size
)
3085 && (ntfs_attr_size(value
) == size
)) {
3086 /* need copying in order to write */
3087 attr
= (char*)ntfs_malloc(size
);
3089 memcpy(attr
,value
,size
);
3090 res
= update_secur_descr(scx
->vol
, attr
, ni
);
3092 * No need to invalidate standard caches :
3093 * the relation between a securid and
3094 * the associated protection is unchanged,
3095 * only the relation between a file and
3096 * its securid and protection is changed.
3098 #if CACHE_LEGACY_SIZE
3100 * we must however invalidate the legacy
3101 * cache, which is based on inode numbers.
3102 * For safety, invalidate even if updating
3105 if ((ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3106 && !ni
->security_id
) {
3107 struct CACHED_PERMISSIONS_LEGACY legacy
;
3109 legacy
.mft_no
= ni
->mft_no
;
3110 legacy
.variable
= (char*)NULL
;
3112 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
3114 (cache_compare
)leg_compare
,0);
3122 return (res
? -1 : 0);
3125 #endif /* HAVE_SETXATTR */
3128 * Set new permissions to a file
3129 * Checks user mapping has been defined before request for setting
3131 * rejected if request is not originated by owner or root
3133 * returns 0 on success
3134 * -1 on failure, with errno = EIO
3137 int ntfs_set_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
, mode_t mode
)
3139 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3140 const struct CACHED_PERMISSIONS
*cached
;
3151 const struct POSIX_SECURITY
*oldpxdesc
;
3152 struct POSIX_SECURITY
*newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3155 /* get the current owner, either from cache or from old attribute */
3157 cached
= fetch_cache(scx
, ni
);
3162 oldpxdesc
= cached
->pxdesc
;
3164 /* must copy before merging */
3165 pxsize
= sizeof(struct POSIX_SECURITY
)
3166 + (oldpxdesc
->acccnt
+ oldpxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
3167 newpxdesc
= (struct POSIX_SECURITY
*)malloc(pxsize
);
3169 memcpy(newpxdesc
, oldpxdesc
, pxsize
);
3170 if (ntfs_merge_mode_posix(newpxdesc
, mode
))
3175 newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3178 oldattr
= getsecurityattr(scx
->vol
, ni
);
3180 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
3182 usid
= ntfs_acl_owner(oldattr
);
3184 usid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->owner
)];
3186 gsid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->group
)];
3187 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3188 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3190 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
3191 newpxdesc
= ntfs_build_permissions_posix(scx
->mapping
,
3192 oldattr
, usid
, gsid
, isdir
);
3193 if (!newpxdesc
|| ntfs_merge_mode_posix(newpxdesc
, mode
))
3202 processuid
= scx
->uid
;
3203 /* TODO : use CAP_FOWNER process capability */
3204 if (!processuid
|| (uid
== processuid
)) {
3206 * clear setgid if file group does
3207 * not match process group
3209 if (processuid
&& (gid
!= scx
->gid
)
3210 && !groupmember(scx
, scx
->uid
, gid
))
3214 newpxdesc
->mode
= mode
;
3215 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3218 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3221 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3225 res
= -1; /* neither owner nor root */
3229 * Should not happen : a default descriptor is generated
3230 * by getsecurityattr() when there are none
3232 ntfs_log_error("File has no security descriptor\n");
3237 if (newpxdesc
) free(newpxdesc
);
3239 return (res
? -1 : 0);
3243 * Create a default security descriptor for files whose descriptor
3244 * cannot be inherited
3247 int ntfs_sd_add_everyone(ntfs_inode
*ni
)
3249 /* JPA SECURITY_DESCRIPTOR_ATTR *sd; */
3250 SECURITY_DESCRIPTOR_RELATIVE
*sd
;
3252 ACCESS_ALLOWED_ACE
*ace
;
3256 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
3258 * Calculate security descriptor length. We have 2 sub-authorities in
3259 * owner and group SIDs, but structure SID contain only one, so add
3260 * 4 bytes to every SID.
3262 sd_len
= sizeof(SECURITY_DESCRIPTOR_ATTR
) + 2 * (sizeof(SID
) + 4) +
3263 sizeof(ACL
) + sizeof(ACCESS_ALLOWED_ACE
);
3264 sd
= (SECURITY_DESCRIPTOR_RELATIVE
*)ntfs_calloc(sd_len
);
3268 sd
->revision
= SECURITY_DESCRIPTOR_REVISION
;
3269 sd
->control
= SE_DACL_PRESENT
| SE_SELF_RELATIVE
;
3271 sid
= (SID
*)((u8
*)sd
+ sizeof(SECURITY_DESCRIPTOR_ATTR
));
3272 sid
->revision
= SID_REVISION
;
3273 sid
->sub_authority_count
= 2;
3274 sid
->sub_authority
[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID
);
3275 sid
->sub_authority
[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS
);
3276 sid
->identifier_authority
.value
[5] = 5;
3277 sd
->owner
= cpu_to_le32((u8
*)sid
- (u8
*)sd
);
3279 sid
= (SID
*)((u8
*)sid
+ sizeof(SID
) + 4);
3280 sid
->revision
= SID_REVISION
;
3281 sid
->sub_authority_count
= 2;
3282 sid
->sub_authority
[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID
);
3283 sid
->sub_authority
[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS
);
3284 sid
->identifier_authority
.value
[5] = 5;
3285 sd
->group
= cpu_to_le32((u8
*)sid
- (u8
*)sd
);
3287 acl
= (ACL
*)((u8
*)sid
+ sizeof(SID
) + 4);
3288 acl
->revision
= ACL_REVISION
;
3289 acl
->size
= const_cpu_to_le16(sizeof(ACL
) + sizeof(ACCESS_ALLOWED_ACE
));
3290 acl
->ace_count
= const_cpu_to_le16(1);
3291 sd
->dacl
= cpu_to_le32((u8
*)acl
- (u8
*)sd
);
3293 ace
= (ACCESS_ALLOWED_ACE
*)((u8
*)acl
+ sizeof(ACL
));
3294 ace
->type
= ACCESS_ALLOWED_ACE_TYPE
;
3295 ace
->flags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
;
3296 ace
->size
= const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE
));
3297 ace
->mask
= const_cpu_to_le32(0x1f01ff); /* FIXME */
3298 ace
->sid
.revision
= SID_REVISION
;
3299 ace
->sid
.sub_authority_count
= 1;
3300 ace
->sid
.sub_authority
[0] = const_cpu_to_le32(0);
3301 ace
->sid
.identifier_authority
.value
[5] = 1;
3303 ret
= ntfs_attr_add(ni
, AT_SECURITY_DESCRIPTOR
, AT_UNNAMED
, 0, (u8
*)sd
,
3306 ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR");
3313 * Check whether user can access a file in a specific way
3315 * Returns 1 if access is allowed, including user is root or no
3316 * user mapping defined
3317 * 2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX
3318 * 0 and sets errno if there is a problem or if access
3321 * This is used for Posix ACL and checking creation of DOS file names
3324 int ntfs_allowed_access(struct SECURITY_CONTEXT
*scx
,
3326 int accesstype
) /* access type required (S_Ixxx values) */
3334 * Always allow for root unless execution is requested.
3335 * (was checked by fuse until kernel 2.6.29)
3336 * Also always allow if no mapping has been defined
3338 if (!scx
->mapping
[MAPUSERS
]
3340 && (!(accesstype
& S_IEXEC
)
3341 || (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
))))
3344 perm
= ntfs_get_perm(scx
, ni
, accesstype
);
3347 switch (accesstype
) {
3349 allow
= (perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0;
3352 allow
= (perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0;
3354 case S_IWRITE
+ S_IEXEC
:
3355 allow
= ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3356 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3359 allow
= (perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0;
3361 case S_IREAD
+ S_IEXEC
:
3362 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3363 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3365 case S_IREAD
+ S_IWRITE
:
3366 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3367 && ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0);
3369 case S_IWRITE
+ S_IEXEC
+ S_ISVTX
:
3370 if (perm
& S_ISVTX
) {
3371 if ((ntfs_get_owner_mode(scx
,ni
,&stbuf
) >= 0)
3372 && (stbuf
.st_uid
== scx
->uid
))
3377 allow
= ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3378 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3380 case S_IREAD
+ S_IWRITE
+ S_IEXEC
:
3381 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3382 && ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3383 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3399 * Check whether user can create a file (or directory)
3401 * Returns TRUE if access is allowed,
3402 * Also returns the gid and dsetgid applicable to the created file
3405 int ntfs_allowed_create(struct SECURITY_CONTEXT
*scx
,
3406 ntfs_inode
*dir_ni
, gid_t
*pgid
, mode_t
*pdsetgid
)
3414 * Always allow for root.
3415 * Also always allow if no mapping has been defined
3417 if (!scx
->mapping
[MAPUSERS
])
3420 perm
= ntfs_get_perm(scx
, dir_ni
, S_IWRITE
+ S_IEXEC
);
3421 if (!scx
->mapping
[MAPUSERS
]
3425 perm
= ntfs_get_perm(scx
, dir_ni
, S_IWRITE
+ S_IEXEC
);
3428 allow
= ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3429 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3437 /* return directory group if S_ISGID is set */
3438 if (allow
&& (perm
& S_ISGID
)) {
3439 if (ntfs_get_owner_mode(scx
, dir_ni
, &stbuf
) >= 0) {
3440 *pdsetgid
= stbuf
.st_mode
& S_ISGID
;
3442 *pgid
= stbuf
.st_gid
;
3448 #if 0 /* not needed any more */
3451 * Check whether user can access the parent directory
3452 * of a file in a specific way
3454 * Returns true if access is allowed, including user is root and
3455 * no user mapping defined
3457 * Sets errno if there is a problem or if not allowed
3459 * This is used for Posix ACL and checking creation of DOS file names
3462 BOOL
old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT
*scx
,
3463 const char *path
, int accesstype
)
3473 dirpath
= strdup(path
);
3475 /* the root of file system is seen as a parent of itself */
3476 /* is that correct ? */
3477 name
= strrchr(dirpath
, '/');
3479 dir_ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, dirpath
);
3481 allow
= ntfs_allowed_access(scx
,
3482 dir_ni
, accesstype
);
3483 ntfs_inode_close(dir_ni
);
3485 * for an not-owned sticky directory, have to
3486 * check whether file itself is owned
3488 if ((accesstype
== (S_IWRITE
+ S_IEXEC
+ S_ISVTX
))
3490 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
,
3494 allow
= (ntfs_get_owner_mode(scx
,ni
,&stbuf
) >= 0)
3495 && (stbuf
.st_uid
== scx
->uid
);
3496 ntfs_inode_close(ni
);
3502 return (allow
); /* errno is set if not allowed */
3508 * Define a new owner/group to a file
3510 * returns zero if successful
3513 int ntfs_set_owner(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3514 uid_t uid
, gid_t gid
)
3516 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3517 const struct CACHED_PERMISSIONS
*cached
;
3528 struct POSIX_SECURITY
*pxdesc
;
3529 BOOL pxdescbuilt
= FALSE
;
3533 /* get the current owner and mode from cache or security attributes */
3534 oldattr
= (char*)NULL
;
3535 cached
= fetch_cache(scx
,ni
);
3537 fileuid
= cached
->uid
;
3538 filegid
= cached
->gid
;
3539 mode
= cached
->mode
;
3541 pxdesc
= cached
->pxdesc
;
3549 oldattr
= getsecurityattr(scx
->vol
, ni
);
3551 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3552 != const_cpu_to_le16(0);
3553 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
3556 &oldattr
[le32_to_cpu(phead
->group
)];
3558 usid
= ntfs_acl_owner(oldattr
);
3561 &oldattr
[le32_to_cpu(phead
->owner
)];
3564 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
, oldattr
,
3568 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3569 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3570 mode
= perm
= pxdesc
->mode
;
3574 mode
= perm
= ntfs_build_permissions(oldattr
,
3577 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3578 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3587 /* check requested by root */
3588 /* or chgrp requested by owner to an owned group */
3590 || ((((int)uid
< 0) || (uid
== fileuid
))
3591 && ((gid
== scx
->gid
) || groupmember(scx
, scx
->uid
, gid
))
3592 && (fileuid
== scx
->uid
))) {
3593 /* replace by the new usid and gsid */
3594 /* or reuse old gid and sid for cacheing */
3599 #if !defined(__sun) || !defined (__SVR4)
3600 /* clear setuid and setgid if owner has changed */
3601 /* unless request originated by root */
3602 if (uid
&& (fileuid
!= uid
))
3606 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3609 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3612 res
= -1; /* neither owner nor root */
3621 * Should not happen : a default descriptor is generated
3622 * by getsecurityattr() when there are none
3624 ntfs_log_error("File has no security descriptor\n");
3628 return (res
? -1 : 0);
3632 * Define new owner/group and mode to a file
3634 * returns zero if successful
3637 int ntfs_set_ownmod(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3638 uid_t uid
, gid_t gid
, const mode_t mode
)
3640 const struct CACHED_PERMISSIONS
*cached
;
3646 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3650 const struct POSIX_SECURITY
*oldpxdesc
;
3651 struct POSIX_SECURITY
*newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3656 /* get the current owner and mode from cache or security attributes */
3657 oldattr
= (char*)NULL
;
3658 cached
= fetch_cache(scx
,ni
);
3660 fileuid
= cached
->uid
;
3661 filegid
= cached
->gid
;
3663 oldpxdesc
= cached
->pxdesc
;
3665 /* must copy before merging */
3666 pxsize
= sizeof(struct POSIX_SECURITY
)
3667 + (oldpxdesc
->acccnt
+ oldpxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
3668 newpxdesc
= (struct POSIX_SECURITY
*)malloc(pxsize
);
3670 memcpy(newpxdesc
, oldpxdesc
, pxsize
);
3671 if (ntfs_merge_mode_posix(newpxdesc
, mode
))
3680 oldattr
= getsecurityattr(scx
->vol
, ni
);
3683 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3684 != const_cpu_to_le16(0);
3685 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
3688 &oldattr
[le32_to_cpu(phead
->group
)];
3690 usid
= ntfs_acl_owner(oldattr
);
3693 &oldattr
[le32_to_cpu(phead
->owner
)];
3695 newpxdesc
= ntfs_build_permissions_posix(scx
->mapping
, oldattr
,
3697 if (!newpxdesc
|| ntfs_merge_mode_posix(newpxdesc
, mode
))
3700 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3701 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3709 /* check requested by root */
3710 /* or chgrp requested by owner to an owned group */
3712 || ((((int)uid
< 0) || (uid
== fileuid
))
3713 && ((gid
== scx
->gid
) || groupmember(scx
, scx
->uid
, gid
))
3714 && (fileuid
== scx
->uid
))) {
3715 /* replace by the new usid and gsid */
3716 /* or reuse old gid and sid for cacheing */
3722 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3725 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3728 res
= -1; /* neither owner nor root */
3733 * Should not happen : a default descriptor is generated
3734 * by getsecurityattr() when there are none
3736 ntfs_log_error("File has no security descriptor\n");
3743 return (res
? -1 : 0);
3747 * Build a security id for a descriptor inherited from
3748 * parent directory the Windows way
3751 static le32
build_inherited_id(struct SECURITY_CONTEXT
*scx
,
3752 const char *parentattr
, BOOL fordir
)
3754 const SECURITY_DESCRIPTOR_RELATIVE
*pphead
;
3763 SECURITY_DESCRIPTOR_RELATIVE
*pnhead
;
3774 parentattrsz
= ntfs_attr_size(parentattr
);
3775 pphead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)parentattr
;
3776 if (scx
->mapping
[MAPUSERS
]) {
3777 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
], scx
->uid
, (SID
*)&defusid
);
3778 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
], scx
->gid
, (SID
*)&defgsid
);
3785 * If there is no user mapping, we have to copy owner
3786 * and group from parent directory.
3787 * Windows never has to do that, because it can always
3788 * rely on a user mapping
3790 offowner
= le32_to_cpu(pphead
->owner
);
3791 usid
= (const SID
*)&parentattr
[offowner
];
3792 offgroup
= le32_to_cpu(pphead
->group
);
3793 gsid
= (const SID
*)&parentattr
[offgroup
];
3796 * new attribute is smaller than parent's
3797 * except for differences in SIDs which appear in
3798 * owner, group and possible grants and denials in
3799 * generic creator-owner and creator-group ACEs.
3800 * For directories, an ACE may be duplicated for
3801 * access and inheritance, so we double the count.
3803 usidsz
= ntfs_sid_size(usid
);
3804 gsidsz
= ntfs_sid_size(gsid
);
3805 newattrsz
= parentattrsz
+ 3*usidsz
+ 3*gsidsz
;
3808 newattr
= (char*)ntfs_malloc(newattrsz
);
3810 pnhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)newattr
;
3811 pnhead
->revision
= SECURITY_DESCRIPTOR_REVISION
;
3812 pnhead
->alignment
= 0;
3813 pnhead
->control
= (pphead
->control
3814 & (SE_DACL_AUTO_INHERITED
| SE_SACL_AUTO_INHERITED
))
3816 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
3818 * locate and inherit DACL
3819 * do not test SE_DACL_PRESENT (wrong for "DR Watson")
3821 pnhead
->dacl
= const_cpu_to_le32(0);
3823 offpacl
= le32_to_cpu(pphead
->dacl
);
3824 ppacl
= (const ACL
*)&parentattr
[offpacl
];
3825 pnacl
= (ACL
*)&newattr
[pos
];
3826 aclsz
= ntfs_inherit_acl(ppacl
, pnacl
, usid
, gsid
,
3827 fordir
, pphead
->control
3828 & SE_DACL_AUTO_INHERITED
);
3830 pnhead
->dacl
= cpu_to_le32(pos
);
3832 pnhead
->control
|= SE_DACL_PRESENT
;
3836 * locate and inherit SACL
3838 pnhead
->sacl
= const_cpu_to_le32(0);
3840 offpacl
= le32_to_cpu(pphead
->sacl
);
3841 ppacl
= (const ACL
*)&parentattr
[offpacl
];
3842 pnacl
= (ACL
*)&newattr
[pos
];
3843 aclsz
= ntfs_inherit_acl(ppacl
, pnacl
, usid
, gsid
,
3844 fordir
, pphead
->control
3845 & SE_SACL_AUTO_INHERITED
);
3847 pnhead
->sacl
= cpu_to_le32(pos
);
3849 pnhead
->control
|= SE_SACL_PRESENT
;
3853 * inherit or redefine owner
3855 memcpy(&newattr
[pos
],usid
,usidsz
);
3856 pnhead
->owner
= cpu_to_le32(pos
);
3859 * inherit or redefine group
3861 memcpy(&newattr
[pos
],gsid
,gsidsz
);
3862 pnhead
->group
= cpu_to_le32(pos
);
3864 securid
= setsecurityattr(scx
->vol
,
3865 (SECURITY_DESCRIPTOR_RELATIVE
*)newattr
, pos
);
3868 securid
= const_cpu_to_le32(0);
3873 * Get an inherited security id
3875 * For Windows compatibility, the normal initial permission setting
3876 * may be inherited from the parent directory instead of being
3877 * defined by the creation arguments.
3879 * The following creates an inherited id for that purpose.
3881 * Note : the owner and group of parent directory are also
3882 * inherited (which is not the case on Windows) if no user mapping
3885 * Returns the inherited id, or zero if not possible (eg on NTFS 1.x)
3888 le32
ntfs_inherited_id(struct SECURITY_CONTEXT
*scx
,
3889 ntfs_inode
*dir_ni
, BOOL fordir
)
3891 struct CACHED_PERMISSIONS
*cached
;
3895 securid
= const_cpu_to_le32(0);
3896 cached
= (struct CACHED_PERMISSIONS
*)NULL
;
3898 * Try to get inherited id from cache
3900 if (test_nino_flag(dir_ni
, v3_Extensions
)
3901 && dir_ni
->security_id
) {
3902 cached
= fetch_cache(scx
, dir_ni
);
3904 securid
= (fordir
? cached
->inh_dirid
3905 : cached
->inh_fileid
);
3908 * Not cached or not available in cache, compute it all
3909 * Note : if parent directory has no id, it is not cacheable
3912 parentattr
= getsecurityattr(scx
->vol
, dir_ni
);
3914 securid
= build_inherited_id(scx
,
3915 parentattr
, fordir
);
3918 * Store the result into cache for further use
3921 cached
= fetch_cache(scx
, dir_ni
);
3924 cached
->inh_dirid
= securid
;
3926 cached
->inh_fileid
= securid
;
3935 * Link a group to a member of group
3937 * Returns 0 if OK, -1 (and errno set) if error
3940 static int link_single_group(struct MAPPING
*usermapping
, struct passwd
*user
,
3943 struct group
*group
;
3950 group
= getgrgid(gid
);
3951 if (group
&& group
->gr_mem
) {
3952 grcnt
= usermapping
->grcnt
;
3953 groups
= usermapping
->groups
;
3954 grmem
= group
->gr_mem
;
3955 while (*grmem
&& strcmp(user
->pw_name
, *grmem
))
3959 groups
= (gid_t
*)malloc(sizeof(gid_t
));
3961 groups
= (gid_t
*)realloc(groups
,
3962 (grcnt
+1)*sizeof(gid_t
));
3964 groups
[grcnt
++] = gid
;
3970 usermapping
->grcnt
= grcnt
;
3971 usermapping
->groups
= groups
;
3978 * Statically link group to users
3979 * This is based on groups defined in /etc/group and does not take
3980 * the groups dynamically set by setgroups() nor any changes in
3981 * /etc/group into account
3983 * Only mapped groups and root group are linked to mapped users
3985 * Returns 0 if OK, -1 (and errno set) if error
3989 static int link_group_members(struct SECURITY_CONTEXT
*scx
)
3991 struct MAPPING
*usermapping
;
3992 struct MAPPING
*groupmapping
;
3993 struct passwd
*user
;
3997 for (usermapping
=scx
->mapping
[MAPUSERS
]; usermapping
&& !res
;
3998 usermapping
=usermapping
->next
) {
3999 usermapping
->grcnt
= 0;
4000 usermapping
->groups
= (gid_t
*)NULL
;
4001 user
= getpwuid(usermapping
->xid
);
4002 if (user
&& user
->pw_name
) {
4003 for (groupmapping
=scx
->mapping
[MAPGROUPS
];
4004 groupmapping
&& !res
;
4005 groupmapping
=groupmapping
->next
) {
4006 if (link_single_group(usermapping
, user
,
4010 if (!res
&& link_single_group(usermapping
,
4019 * Apply default single user mapping
4020 * returns zero if successful
4023 static int ntfs_do_default_mapping(struct SECURITY_CONTEXT
*scx
,
4024 uid_t uid
, gid_t gid
, const SID
*usid
)
4026 struct MAPPING
*usermapping
;
4027 struct MAPPING
*groupmapping
;
4033 sidsz
= ntfs_sid_size(usid
);
4034 sid
= (SID
*)ntfs_malloc(sidsz
);
4036 memcpy(sid
,usid
,sidsz
);
4037 usermapping
= (struct MAPPING
*)ntfs_malloc(sizeof(struct MAPPING
));
4039 groupmapping
= (struct MAPPING
*)ntfs_malloc(sizeof(struct MAPPING
));
4041 usermapping
->sid
= sid
;
4042 usermapping
->xid
= uid
;
4043 usermapping
->next
= (struct MAPPING
*)NULL
;
4044 groupmapping
->sid
= sid
;
4045 groupmapping
->xid
= gid
;
4046 groupmapping
->next
= (struct MAPPING
*)NULL
;
4047 scx
->mapping
[MAPUSERS
] = usermapping
;
4048 scx
->mapping
[MAPGROUPS
] = groupmapping
;
4057 * Make sure there are no ambiguous mapping
4058 * Ambiguous mapping may lead to undesired configurations and
4059 * we had rather be safe until the consequences are understood
4062 #if 0 /* not activated for now */
4064 static BOOL
check_mapping(const struct MAPPING
*usermapping
,
4065 const struct MAPPING
*groupmapping
)
4067 const struct MAPPING
*mapping1
;
4068 const struct MAPPING
*mapping2
;
4072 for (mapping1
=usermapping
; mapping1
; mapping1
=mapping1
->next
)
4073 for (mapping2
=mapping1
->next
; mapping2
; mapping1
=mapping2
->next
)
4074 if (ntfs_same_sid(mapping1
->sid
,mapping2
->sid
)) {
4075 if (mapping1
->xid
!= mapping2
->xid
)
4078 if (mapping1
->xid
== mapping2
->xid
)
4081 for (mapping1
=groupmapping
; mapping1
; mapping1
=mapping1
->next
)
4082 for (mapping2
=mapping1
->next
; mapping2
; mapping1
=mapping2
->next
)
4083 if (ntfs_same_sid(mapping1
->sid
,mapping2
->sid
)) {
4084 if (mapping1
->xid
!= mapping2
->xid
)
4087 if (mapping1
->xid
== mapping2
->xid
)
4095 #if 0 /* not used any more */
4098 * Try and apply default single user mapping
4099 * returns zero if successful
4102 static int ntfs_default_mapping(struct SECURITY_CONTEXT
*scx
)
4104 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4111 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, "/.");
4113 securattr
= getsecurityattr(scx
->vol
, ni
);
4115 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)securattr
;
4116 usid
= (SID
*)&securattr
[le32_to_cpu(phead
->owner
)];
4117 if (ntfs_is_user_sid(usid
))
4118 res
= ntfs_do_default_mapping(scx
,
4119 scx
->uid
, scx
->gid
, usid
);
4122 ntfs_inode_close(ni
);
4130 * Basic read from a user mapping file on another volume
4133 static int basicread(void *fileid
, char *buf
, size_t size
, off_t offs
__attribute__((unused
)))
4135 return (read(*(int*)fileid
, buf
, size
));
4140 * Read from a user mapping file on current NTFS partition
4143 static int localread(void *fileid
, char *buf
, size_t size
, off_t offs
)
4145 return (ntfs_attr_data_read((ntfs_inode
*)fileid
,
4146 AT_UNNAMED
, 0, buf
, size
, offs
));
4150 * Build the user mapping
4151 * - according to a mapping file if defined (or default present),
4152 * - or try default single user mapping if possible
4154 * The mapping is specific to a mounted device
4155 * No locking done, mounting assumed non multithreaded
4157 * returns zero if mapping is successful
4158 * (failure should not be interpreted as an error)
4161 int ntfs_build_mapping(struct SECURITY_CONTEXT
*scx
, const char *usermap_path
,
4164 struct MAPLIST
*item
;
4165 struct MAPLIST
*firstitem
;
4166 struct MAPPING
*usermapping
;
4167 struct MAPPING
*groupmapping
;
4181 1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5),
4182 const_cpu_to_le32(21),
4183 const_cpu_to_le32(DEFSECAUTH1
), const_cpu_to_le32(DEFSECAUTH2
),
4184 const_cpu_to_le32(DEFSECAUTH3
), const_cpu_to_le32(DEFSECBASE
)
4187 /* be sure not to map anything until done */
4188 scx
->mapping
[MAPUSERS
] = (struct MAPPING
*)NULL
;
4189 scx
->mapping
[MAPGROUPS
] = (struct MAPPING
*)NULL
;
4191 if (!usermap_path
) usermap_path
= MAPPINGFILE
;
4192 if (usermap_path
[0] == '/') {
4193 fd
= open(usermap_path
,O_RDONLY
);
4195 firstitem
= ntfs_read_mapping(basicread
, (void*)&fd
);
4198 firstitem
= (struct MAPLIST
*)NULL
;
4200 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, usermap_path
);
4202 firstitem
= ntfs_read_mapping(localread
, ni
);
4203 ntfs_inode_close(ni
);
4205 firstitem
= (struct MAPLIST
*)NULL
;
4210 usermapping
= ntfs_do_user_mapping(firstitem
);
4211 groupmapping
= ntfs_do_group_mapping(firstitem
);
4212 if (usermapping
&& groupmapping
) {
4213 scx
->mapping
[MAPUSERS
] = usermapping
;
4214 scx
->mapping
[MAPGROUPS
] = groupmapping
;
4216 ntfs_log_error("There were no valid user or no valid group\n");
4217 /* now we can free the memory copy of input text */
4218 /* and rely on internal representation */
4220 item
= firstitem
->next
;
4225 /* no mapping file, try a default mapping */
4227 if (!ntfs_do_default_mapping(scx
,
4228 0, 0, (const SID
*)&defmap
))
4229 ntfs_log_info("Using default user mapping\n");
4232 return (!scx
->mapping
[MAPUSERS
] || link_group_members(scx
));
4235 #ifdef HAVE_SETXATTR /* extended attributes interface required */
4238 * Get the ntfs attribute into an extended attribute
4239 * The attribute is returned according to cpu endianness
4242 int ntfs_get_ntfs_attrib(ntfs_inode
*ni
, char *value
, size_t size
)
4247 outsize
= 0; /* default to no data and no error */
4249 attrib
= le32_to_cpu(ni
->flags
);
4250 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
4251 attrib
|= const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4253 attrib
&= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4255 attrib
|= const_le32_to_cpu(FILE_ATTR_NORMAL
);
4256 outsize
= sizeof(FILE_ATTR_FLAGS
);
4257 if (size
>= outsize
) {
4259 memcpy(value
,&attrib
,outsize
);
4264 return (outsize
? (int)outsize
: -errno
);
4268 * Return the ntfs attribute into an extended attribute
4269 * The attribute is expected according to cpu endianness
4271 * Returns 0, or -1 if there is a problem
4274 int ntfs_set_ntfs_attrib(ntfs_inode
*ni
,
4275 const char *value
, size_t size
, int flags
)
4279 ATTR_FLAGS dirflags
;
4283 if (ni
&& value
&& (size
>= sizeof(FILE_ATTR_FLAGS
))) {
4284 if (!(flags
& XATTR_CREATE
)) {
4285 /* copy to avoid alignment problems */
4286 memcpy(&attrib
,value
,sizeof(FILE_ATTR_FLAGS
));
4287 settable
= FILE_ATTR_SETTABLE
;
4289 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
4291 * Accept changing compression for a directory
4292 * and set index root accordingly
4294 settable
|= FILE_ATTR_COMPRESSED
;
4295 if ((ni
->flags
^ cpu_to_le32(attrib
))
4296 & FILE_ATTR_COMPRESSED
) {
4297 if (ni
->flags
& FILE_ATTR_COMPRESSED
)
4298 dirflags
= const_cpu_to_le16(0);
4300 dirflags
= ATTR_IS_COMPRESSED
;
4301 res
= ntfs_attr_set_flags(ni
,
4305 ATTR_COMPRESSION_MASK
);
4309 ni
->flags
= (ni
->flags
& ~settable
)
4310 | (cpu_to_le32(attrib
) & settable
);
4311 NInoFileNameSetDirty(ni
);
4318 return (res
? -1 : 0);
4321 #endif /* HAVE_SETXATTR */
4324 * Open $Secure once for all
4325 * returns zero if it succeeds
4326 * non-zero if it fails. This is not an error (on NTFS v1.x)
4330 int ntfs_open_secure(ntfs_volume
*vol
)
4336 vol
->secure_ni
= (ntfs_inode
*)NULL
;
4337 vol
->secure_xsii
= (ntfs_index_context
*)NULL
;
4338 vol
->secure_xsdh
= (ntfs_index_context
*)NULL
;
4339 if (vol
->major_ver
>= 3) {
4340 /* make sure this is a genuine $Secure inode 9 */
4341 ni
= ntfs_pathname_to_inode(vol
, NULL
, "$Secure");
4342 if (ni
&& (ni
->mft_no
== 9)) {
4343 vol
->secure_reentry
= 0;
4344 vol
->secure_xsii
= ntfs_index_ctx_get(ni
,
4346 vol
->secure_xsdh
= ntfs_index_ctx_get(ni
,
4348 if (ni
&& vol
->secure_xsii
&& vol
->secure_xsdh
) {
4349 vol
->secure_ni
= ni
;
4359 * Allocated memory is freed to facilitate the detection of memory leaks
4362 void ntfs_close_secure(struct SECURITY_CONTEXT
*scx
)
4367 if (vol
->secure_ni
) {
4368 ntfs_index_ctx_put(vol
->secure_xsii
);
4369 ntfs_index_ctx_put(vol
->secure_xsdh
);
4370 ntfs_inode_close(vol
->secure_ni
);
4373 ntfs_free_mapping(scx
->mapping
);
4378 * API for direct access to security descriptors
4379 * based on Win32 API
4384 * Selective feeding of a security descriptor into user buffer
4386 * Returns TRUE if successful
4389 static BOOL
feedsecurityattr(const char *attr
, u32 selection
,
4390 char *buf
, u32 buflen
, u32
*psize
)
4392 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4393 SECURITY_DESCRIPTOR_RELATIVE
*pnhead
;
4398 unsigned int offdacl
;
4399 unsigned int offsacl
;
4400 unsigned int offowner
;
4401 unsigned int offgroup
;
4402 unsigned int daclsz
;
4403 unsigned int saclsz
;
4404 unsigned int usidsz
;
4405 unsigned int gsidsz
;
4406 unsigned int size
; /* size of requested attributes */
4413 control
= SE_SELF_RELATIVE
;
4414 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
;
4415 size
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4417 /* locate DACL if requested and available */
4418 if (phead
->dacl
&& (selection
& DACL_SECURITY_INFORMATION
)) {
4419 offdacl
= le32_to_cpu(phead
->dacl
);
4420 pdacl
= (const ACL
*)&attr
[offdacl
];
4421 daclsz
= le16_to_cpu(pdacl
->size
);
4423 avail
|= DACL_SECURITY_INFORMATION
;
4425 offdacl
= daclsz
= 0;
4427 /* locate owner if requested and available */
4428 offowner
= le32_to_cpu(phead
->owner
);
4429 if (offowner
&& (selection
& OWNER_SECURITY_INFORMATION
)) {
4430 /* find end of USID */
4431 pusid
= (const SID
*)&attr
[offowner
];
4432 usidsz
= ntfs_sid_size(pusid
);
4434 avail
|= OWNER_SECURITY_INFORMATION
;
4436 offowner
= usidsz
= 0;
4438 /* locate group if requested and available */
4439 offgroup
= le32_to_cpu(phead
->group
);
4440 if (offgroup
&& (selection
& GROUP_SECURITY_INFORMATION
)) {
4441 /* find end of GSID */
4442 pgsid
= (const SID
*)&attr
[offgroup
];
4443 gsidsz
= ntfs_sid_size(pgsid
);
4445 avail
|= GROUP_SECURITY_INFORMATION
;
4447 offgroup
= gsidsz
= 0;
4449 /* locate SACL if requested and available */
4450 if (phead
->sacl
&& (selection
& SACL_SECURITY_INFORMATION
)) {
4451 /* find end of SACL */
4452 offsacl
= le32_to_cpu(phead
->sacl
);
4453 psacl
= (const ACL
*)&attr
[offsacl
];
4454 saclsz
= le16_to_cpu(psacl
->size
);
4456 avail
|= SACL_SECURITY_INFORMATION
;
4458 offsacl
= saclsz
= 0;
4461 * Check having enough size in destination buffer
4462 * (required size is returned nevertheless so that
4463 * the request can be reissued with adequate size)
4465 if (size
> buflen
) {
4470 if (selection
& OWNER_SECURITY_INFORMATION
)
4471 control
|= phead
->control
& SE_OWNER_DEFAULTED
;
4472 if (selection
& GROUP_SECURITY_INFORMATION
)
4473 control
|= phead
->control
& SE_GROUP_DEFAULTED
;
4474 if (selection
& DACL_SECURITY_INFORMATION
)
4475 control
|= phead
->control
4478 | SE_DACL_AUTO_INHERITED
4479 | SE_DACL_PROTECTED
);
4480 if (selection
& SACL_SECURITY_INFORMATION
)
4481 control
|= phead
->control
4484 | SE_SACL_AUTO_INHERITED
4485 | SE_SACL_PROTECTED
);
4487 * copy header and feed new flags, even if no detailed data
4489 memcpy(buf
,attr
,sizeof(SECURITY_DESCRIPTOR_RELATIVE
));
4490 pnhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)buf
;
4491 pnhead
->control
= control
;
4492 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4494 /* copy DACL if requested and available */
4495 if (selection
& avail
& DACL_SECURITY_INFORMATION
) {
4496 pnhead
->dacl
= cpu_to_le32(pos
);
4497 memcpy(&buf
[pos
],&attr
[offdacl
],daclsz
);
4500 pnhead
->dacl
= const_cpu_to_le32(0);
4502 /* copy SACL if requested and available */
4503 if (selection
& avail
& SACL_SECURITY_INFORMATION
) {
4504 pnhead
->sacl
= cpu_to_le32(pos
);
4505 memcpy(&buf
[pos
],&attr
[offsacl
],saclsz
);
4508 pnhead
->sacl
= const_cpu_to_le32(0);
4510 /* copy owner if requested and available */
4511 if (selection
& avail
& OWNER_SECURITY_INFORMATION
) {
4512 pnhead
->owner
= cpu_to_le32(pos
);
4513 memcpy(&buf
[pos
],&attr
[offowner
],usidsz
);
4516 pnhead
->owner
= const_cpu_to_le32(0);
4518 /* copy group if requested and available */
4519 if (selection
& avail
& GROUP_SECURITY_INFORMATION
) {
4520 pnhead
->group
= cpu_to_le32(pos
);
4521 memcpy(&buf
[pos
],&attr
[offgroup
],gsidsz
);
4524 pnhead
->group
= const_cpu_to_le32(0);
4526 ntfs_log_error("Error in security descriptor size\n");
4535 * Merge a new security descriptor into the old one
4536 * and assign to designated file
4538 * Returns TRUE if successful
4541 static BOOL
mergesecurityattr(ntfs_volume
*vol
, const char *oldattr
,
4542 const char *newattr
, u32 selection
, ntfs_inode
*ni
)
4544 const SECURITY_DESCRIPTOR_RELATIVE
*oldhead
;
4545 const SECURITY_DESCRIPTOR_RELATIVE
*newhead
;
4546 SECURITY_DESCRIPTOR_RELATIVE
*targhead
;
4563 ok
= FALSE
; /* default return */
4564 oldhead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
4565 newhead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
;
4566 oldattrsz
= ntfs_attr_size(oldattr
);
4567 newattrsz
= ntfs_attr_size(newattr
);
4568 target
= (char*)ntfs_malloc(oldattrsz
+ newattrsz
);
4570 targhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)target
;
4571 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4572 control
= SE_SELF_RELATIVE
;
4574 * copy new DACL if selected
4575 * or keep old DACL if any
4577 if ((selection
& DACL_SECURITY_INFORMATION
) ?
4578 newhead
->dacl
: oldhead
->dacl
) {
4579 if (selection
& DACL_SECURITY_INFORMATION
) {
4580 offdacl
= le32_to_cpu(newhead
->dacl
);
4581 pdacl
= (const ACL
*)&newattr
[offdacl
];
4583 offdacl
= le32_to_cpu(oldhead
->dacl
);
4584 pdacl
= (const ACL
*)&oldattr
[offdacl
];
4586 size
= le16_to_cpu(pdacl
->size
);
4587 memcpy(&target
[pos
], pdacl
, size
);
4588 targhead
->dacl
= cpu_to_le32(pos
);
4591 targhead
->dacl
= const_cpu_to_le32(0);
4592 if (selection
& DACL_SECURITY_INFORMATION
) {
4593 control
|= newhead
->control
4596 | SE_DACL_PROTECTED
);
4597 if (newhead
->control
& SE_DACL_AUTO_INHERIT_REQ
)
4598 control
|= SE_DACL_AUTO_INHERITED
;
4600 control
|= oldhead
->control
4603 | SE_DACL_AUTO_INHERITED
4604 | SE_DACL_PROTECTED
);
4606 * copy new SACL if selected
4607 * or keep old SACL if any
4609 if ((selection
& SACL_SECURITY_INFORMATION
) ?
4610 newhead
->sacl
: oldhead
->sacl
) {
4611 if (selection
& SACL_SECURITY_INFORMATION
) {
4612 offsacl
= le32_to_cpu(newhead
->sacl
);
4613 psacl
= (const ACL
*)&newattr
[offsacl
];
4615 offsacl
= le32_to_cpu(oldhead
->sacl
);
4616 psacl
= (const ACL
*)&oldattr
[offsacl
];
4618 size
= le16_to_cpu(psacl
->size
);
4619 memcpy(&target
[pos
], psacl
, size
);
4620 targhead
->sacl
= cpu_to_le32(pos
);
4623 targhead
->sacl
= const_cpu_to_le32(0);
4624 if (selection
& SACL_SECURITY_INFORMATION
) {
4625 control
|= newhead
->control
4628 | SE_SACL_PROTECTED
);
4629 if (newhead
->control
& SE_SACL_AUTO_INHERIT_REQ
)
4630 control
|= SE_SACL_AUTO_INHERITED
;
4632 control
|= oldhead
->control
4635 | SE_SACL_AUTO_INHERITED
4636 | SE_SACL_PROTECTED
);
4638 * copy new OWNER if selected
4639 * or keep old OWNER if any
4641 if ((selection
& OWNER_SECURITY_INFORMATION
) ?
4642 newhead
->owner
: oldhead
->owner
) {
4643 if (selection
& OWNER_SECURITY_INFORMATION
) {
4644 offowner
= le32_to_cpu(newhead
->owner
);
4645 powner
= (const SID
*)&newattr
[offowner
];
4647 offowner
= le32_to_cpu(oldhead
->owner
);
4648 powner
= (const SID
*)&oldattr
[offowner
];
4650 size
= ntfs_sid_size(powner
);
4651 memcpy(&target
[pos
], powner
, size
);
4652 targhead
->owner
= cpu_to_le32(pos
);
4655 targhead
->owner
= const_cpu_to_le32(0);
4656 if (selection
& OWNER_SECURITY_INFORMATION
)
4657 control
|= newhead
->control
& SE_OWNER_DEFAULTED
;
4659 control
|= oldhead
->control
& SE_OWNER_DEFAULTED
;
4661 * copy new GROUP if selected
4662 * or keep old GROUP if any
4664 if ((selection
& GROUP_SECURITY_INFORMATION
) ?
4665 newhead
->group
: oldhead
->group
) {
4666 if (selection
& GROUP_SECURITY_INFORMATION
) {
4667 offgroup
= le32_to_cpu(newhead
->group
);
4668 pgroup
= (const SID
*)&newattr
[offgroup
];
4669 control
|= newhead
->control
4670 & SE_GROUP_DEFAULTED
;
4672 offgroup
= le32_to_cpu(oldhead
->group
);
4673 pgroup
= (const SID
*)&oldattr
[offgroup
];
4674 control
|= oldhead
->control
4675 & SE_GROUP_DEFAULTED
;
4677 size
= ntfs_sid_size(pgroup
);
4678 memcpy(&target
[pos
], pgroup
, size
);
4679 targhead
->group
= cpu_to_le32(pos
);
4682 targhead
->group
= const_cpu_to_le32(0);
4683 if (selection
& GROUP_SECURITY_INFORMATION
)
4684 control
|= newhead
->control
& SE_GROUP_DEFAULTED
;
4686 control
|= oldhead
->control
& SE_GROUP_DEFAULTED
;
4687 targhead
->revision
= SECURITY_DESCRIPTOR_REVISION
;
4688 targhead
->alignment
= 0;
4689 targhead
->control
= control
;
4690 ok
= !update_secur_descr(vol
, target
, ni
);
4697 * Return the security descriptor of a file
4698 * This is intended to be similar to GetFileSecurity() from Win32
4699 * in order to facilitate the development of portable tools
4701 * returns zero if unsuccessful (following Win32 conventions)
4703 * the securid if any
4705 * The Win32 API is :
4707 * BOOL WINAPI GetFileSecurity(
4708 * __in LPCTSTR lpFileName,
4709 * __in SECURITY_INFORMATION RequestedInformation,
4710 * __out_opt PSECURITY_DESCRIPTOR pSecurityDescriptor,
4711 * __in DWORD nLength,
4712 * __out LPDWORD lpnLengthNeeded
4717 int ntfs_get_file_security(struct SECURITY_API
*scapi
,
4718 const char *path
, u32 selection
,
4719 char *buf
, u32 buflen
, u32
*psize
)
4725 res
= 0; /* default return */
4726 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4727 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4729 attr
= getsecurityattr(scapi
->security
.vol
, ni
);
4731 if (feedsecurityattr(attr
,selection
,
4732 buf
,buflen
,psize
)) {
4733 if (test_nino_flag(ni
, v3_Extensions
)
4742 ntfs_inode_close(ni
);
4745 if (!res
) *psize
= 0;
4747 errno
= EINVAL
; /* do not clear *psize */
4753 * Set the security descriptor of a file or directory
4754 * This is intended to be similar to SetFileSecurity() from Win32
4755 * in order to facilitate the development of portable tools
4757 * returns zero if unsuccessful (following Win32 conventions)
4759 * the securid if any
4761 * The Win32 API is :
4763 * BOOL WINAPI SetFileSecurity(
4764 * __in LPCTSTR lpFileName,
4765 * __in SECURITY_INFORMATION SecurityInformation,
4766 * __in PSECURITY_DESCRIPTOR pSecurityDescriptor
4770 int ntfs_set_file_security(struct SECURITY_API
*scapi
,
4771 const char *path
, u32 selection
, const char *attr
)
4773 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4780 res
= 0; /* default return */
4781 if (scapi
&& (scapi
->magic
== MAGIC_API
) && attr
) {
4782 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
;
4783 attrsz
= ntfs_attr_size(attr
);
4784 /* if selected, owner and group must be present or defaulted */
4785 missing
= ((selection
& OWNER_SECURITY_INFORMATION
)
4787 && !(phead
->control
& SE_OWNER_DEFAULTED
))
4788 || ((selection
& GROUP_SECURITY_INFORMATION
)
4790 && !(phead
->control
& SE_GROUP_DEFAULTED
));
4792 && (phead
->control
& SE_SELF_RELATIVE
)
4793 && ntfs_valid_descr(attr
, attrsz
)) {
4794 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
,
4797 oldattr
= getsecurityattr(scapi
->security
.vol
,
4800 if (mergesecurityattr(
4801 scapi
->security
.vol
,
4804 if (test_nino_flag(ni
,
4813 ntfs_inode_close(ni
);
4824 * Return the attributes of a file
4825 * This is intended to be similar to GetFileAttributes() from Win32
4826 * in order to facilitate the development of portable tools
4828 * returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES)
4830 * The Win32 API is :
4832 * DWORD WINAPI GetFileAttributes(
4833 * __in LPCTSTR lpFileName
4837 int ntfs_get_file_attributes(struct SECURITY_API
*scapi
, const char *path
)
4842 attrib
= -1; /* default return */
4843 if (scapi
&& (scapi
->magic
== MAGIC_API
) && path
) {
4844 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4846 attrib
= le32_to_cpu(ni
->flags
);
4847 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
4848 attrib
|= const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4850 attrib
&= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4852 attrib
|= const_le32_to_cpu(FILE_ATTR_NORMAL
);
4854 ntfs_inode_close(ni
);
4858 errno
= EINVAL
; /* do not clear *psize */
4864 * Set attributes to a file or directory
4865 * This is intended to be similar to SetFileAttributes() from Win32
4866 * in order to facilitate the development of portable tools
4868 * Only a few flags can be set (same list as Win32)
4870 * returns zero if unsuccessful (following Win32 conventions)
4871 * nonzero if successful
4873 * The Win32 API is :
4875 * BOOL WINAPI SetFileAttributes(
4876 * __in LPCTSTR lpFileName,
4877 * __in DWORD dwFileAttributes
4881 BOOL
ntfs_set_file_attributes(struct SECURITY_API
*scapi
,
4882 const char *path
, s32 attrib
)
4886 ATTR_FLAGS dirflags
;
4889 res
= 0; /* default return */
4890 if (scapi
&& (scapi
->magic
== MAGIC_API
) && path
) {
4891 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4893 settable
= FILE_ATTR_SETTABLE
;
4894 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
4896 * Accept changing compression for a directory
4897 * and set index root accordingly
4899 settable
|= FILE_ATTR_COMPRESSED
;
4900 if ((ni
->flags
^ cpu_to_le32(attrib
))
4901 & FILE_ATTR_COMPRESSED
) {
4902 if (ni
->flags
& FILE_ATTR_COMPRESSED
)
4903 dirflags
= const_cpu_to_le16(0);
4905 dirflags
= ATTR_IS_COMPRESSED
;
4906 res
= ntfs_attr_set_flags(ni
,
4910 ATTR_COMPRESSION_MASK
);
4914 ni
->flags
= (ni
->flags
& ~settable
)
4915 | (cpu_to_le32(attrib
) & settable
);
4917 NInoFileNameSetDirty(ni
);
4919 if (!ntfs_inode_close(ni
))
4928 BOOL
ntfs_read_directory(struct SECURITY_API
*scapi
,
4929 const char *path
, ntfs_filldir_t callback
, void *context
)
4935 ok
= FALSE
; /* default return */
4936 if (scapi
&& (scapi
->magic
== MAGIC_API
) && callback
) {
4937 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4939 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
4941 ntfs_readdir(ni
,&pos
,context
,callback
);
4942 ok
= !ntfs_inode_close(ni
);
4944 ntfs_inode_close(ni
);
4950 errno
= EINVAL
; /* do not clear *psize */
4955 * read $SDS (for auditing security data)
4957 * Returns the number or read bytes, or -1 if there is an error
4960 int ntfs_read_sds(struct SECURITY_API
*scapi
,
4961 char *buf
, u32 size
, u32 offset
)
4965 got
= -1; /* default return */
4966 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4967 if (scapi
->security
.vol
->secure_ni
)
4968 got
= ntfs_attr_data_read(scapi
->security
.vol
->secure_ni
,
4969 STREAM_SDS
, 4, buf
, size
, offset
);
4978 * read $SII (for auditing security data)
4980 * Returns next entry, or NULL if there is an error
4983 INDEX_ENTRY
*ntfs_read_sii(struct SECURITY_API
*scapi
,
4989 ntfs_index_context
*xsii
;
4991 ret
= (INDEX_ENTRY
*)NULL
; /* default return */
4992 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4993 xsii
= scapi
->security
.vol
->secure_xsii
;
4996 key
.security_id
= const_cpu_to_le32(0);
4997 found
= !ntfs_index_lookup((char*)&key
,
4998 sizeof(SII_INDEX_KEY
), xsii
);
4999 /* not supposed to find */
5000 if (!found
&& (errno
== ENOENT
))
5003 ret
= ntfs_index_next(entry
,xsii
);
5014 * read $SDH (for auditing security data)
5016 * Returns next entry, or NULL if there is an error
5019 INDEX_ENTRY
*ntfs_read_sdh(struct SECURITY_API
*scapi
,
5025 ntfs_index_context
*xsdh
;
5027 ret
= (INDEX_ENTRY
*)NULL
; /* default return */
5028 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
5029 xsdh
= scapi
->security
.vol
->secure_xsdh
;
5032 key
.hash
= const_cpu_to_le32(0);
5033 key
.security_id
= const_cpu_to_le32(0);
5034 found
= !ntfs_index_lookup((char*)&key
,
5035 sizeof(SDH_INDEX_KEY
), xsdh
);
5036 /* not supposed to find */
5037 if (!found
&& (errno
== ENOENT
))
5040 ret
= ntfs_index_next(entry
,xsdh
);
5043 } else errno
= ENOTSUP
;
5050 * Get the mapped user SID
5051 * A buffer of 40 bytes has to be supplied
5053 * returns the size of the SID, or zero and errno set if not found
5056 int ntfs_get_usid(struct SECURITY_API
*scapi
, uid_t uid
, char *buf
)
5063 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
5064 usid
= ntfs_find_usid(scapi
->security
.mapping
[MAPUSERS
], uid
, (SID
*)&defusid
);
5066 size
= ntfs_sid_size(usid
);
5067 memcpy(buf
,usid
,size
);
5076 * Get the mapped group SID
5077 * A buffer of 40 bytes has to be supplied
5079 * returns the size of the SID, or zero and errno set if not found
5082 int ntfs_get_gsid(struct SECURITY_API
*scapi
, gid_t gid
, char *buf
)
5089 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
5090 gsid
= ntfs_find_gsid(scapi
->security
.mapping
[MAPGROUPS
], gid
, (SID
*)&defgsid
);
5092 size
= ntfs_sid_size(gsid
);
5093 memcpy(buf
,gsid
,size
);
5102 * Get the user mapped to a SID
5104 * returns the uid, or -1 if not found
5107 int ntfs_get_user(struct SECURITY_API
*scapi
, const SID
*usid
)
5112 if (scapi
&& (scapi
->magic
== MAGIC_API
) && ntfs_valid_sid(usid
)) {
5113 if (ntfs_same_sid(usid
,adminsid
))
5116 uid
= ntfs_find_user(scapi
->security
.mapping
[MAPUSERS
], usid
);
5128 * Get the group mapped to a SID
5130 * returns the uid, or -1 if not found
5133 int ntfs_get_group(struct SECURITY_API
*scapi
, const SID
*gsid
)
5138 if (scapi
&& (scapi
->magic
== MAGIC_API
) && ntfs_valid_sid(gsid
)) {
5139 if (ntfs_same_sid(gsid
,adminsid
))
5142 gid
= ntfs_find_group(scapi
->security
.mapping
[MAPGROUPS
], gsid
);
5154 * Initializations before calling ntfs_get_file_security()
5155 * ntfs_set_file_security() and ntfs_read_directory()
5157 * Only allowed for root
5159 * Returns an (obscured) struct SECURITY_API* needed for further calls
5160 * NULL if not root (EPERM) or device is mounted (EBUSY)
5163 struct SECURITY_API
*ntfs_initialize_file_security(const char *device
,
5164 unsigned long flags
)
5167 unsigned long mntflag
;
5169 struct SECURITY_API
*scapi
;
5170 struct SECURITY_CONTEXT
*scx
;
5172 scapi
= (struct SECURITY_API
*)NULL
;
5173 mnt
= ntfs_check_if_mounted(device
, &mntflag
);
5174 if (!mnt
&& !(mntflag
& NTFS_MF_MOUNTED
) && !getuid()) {
5175 vol
= ntfs_mount(device
, flags
);
5177 scapi
= (struct SECURITY_API
*)
5178 ntfs_malloc(sizeof(struct SECURITY_API
));
5179 if (!ntfs_volume_get_free_space(vol
)
5181 scapi
->magic
= MAGIC_API
;
5182 scapi
->seccache
= (struct PERMISSIONS_CACHE
*)NULL
;
5183 scx
= &scapi
->security
;
5185 scx
->uid
= getuid();
5186 scx
->gid
= getgid();
5187 scx
->pseccache
= &scapi
->seccache
;
5188 scx
->vol
->secure_flags
= 0;
5189 /* accept no mapping and no $Secure */
5190 ntfs_build_mapping(scx
,(const char*)NULL
,TRUE
);
5191 ntfs_open_secure(vol
);
5197 mnt
= ntfs_umount(vol
,FALSE
);
5198 scapi
= (struct SECURITY_API
*)NULL
;
5210 * Leaving after ntfs_initialize_file_security()
5212 * Returns FALSE if FAILED
5215 BOOL
ntfs_leave_file_security(struct SECURITY_API
*scapi
)
5221 if (scapi
&& (scapi
->magic
== MAGIC_API
) && scapi
->security
.vol
) {
5222 vol
= scapi
->security
.vol
;
5223 ntfs_close_secure(&scapi
->security
);
5225 if (!ntfs_umount(vol
, 0))