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-2015 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
44 #ifdef HAVE_SYS_STAT_H
67 * JPA NTFS constants or structs
68 * should be moved to layout.h
71 #define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */
72 #define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */
73 #define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */
74 #define FIRST_SECURITY_ID 0x100 /* Lowest security id */
76 /* Mask for attributes which can be forced */
77 #define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY \
81 | FILE_ATTR_TEMPORARY \
83 | FILE_ATTR_NOT_CONTENT_INDEXED )
85 struct SII
{ /* this is an image of an $SII index entry */
95 /* did not find official description for the following */
98 le32 dataoffsl
; /* documented as badly aligned */
103 struct SDH
{ /* this is an image of an $SDH index entry */
114 /* did not find official description for the following */
124 * A few useful constants
127 static ntfschar sii_stream
[] = { const_cpu_to_le16('$'),
128 const_cpu_to_le16('S'),
129 const_cpu_to_le16('I'),
130 const_cpu_to_le16('I'),
131 const_cpu_to_le16(0) };
132 static ntfschar sdh_stream
[] = { const_cpu_to_le16('$'),
133 const_cpu_to_le16('S'),
134 const_cpu_to_le16('D'),
135 const_cpu_to_le16('H'),
136 const_cpu_to_le16(0) };
142 extern const SID
*nullsid
;
148 static const GUID __zero_guid
= { const_cpu_to_le32(0), const_cpu_to_le16(0),
149 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
150 static const GUID
*const zero_guid
= &__zero_guid
;
153 * ntfs_guid_is_zero - check if a GUID is zero
154 * @guid: [IN] guid to check
156 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
157 * and FALSE otherwise.
159 BOOL
ntfs_guid_is_zero(const GUID
*guid
)
161 return (memcmp(guid
, zero_guid
, sizeof(*zero_guid
)));
165 * ntfs_guid_to_mbs - convert a GUID to a multi byte string
166 * @guid: [IN] guid to convert
167 * @guid_str: [OUT] string in which to return the GUID (optional)
169 * Convert the GUID pointed to by @guid to a multi byte string of the form
170 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
171 * needs to be able to store at least 37 bytes.
173 * If @guid_str is not NULL it will contain the converted GUID on return. If
174 * it is NULL a string will be allocated and this will be returned. The caller
175 * is responsible for free()ing the string in that case.
177 * On success return the converted string and on failure return NULL with errno
178 * set to the error code.
180 char *ntfs_guid_to_mbs(const GUID
*guid
, char *guid_str
)
189 _guid_str
= guid_str
;
191 _guid_str
= (char*)ntfs_malloc(37);
195 res
= snprintf(_guid_str
, 37,
196 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
197 (unsigned int)le32_to_cpu(guid
->data1
),
198 le16_to_cpu(guid
->data2
), le16_to_cpu(guid
->data3
),
199 guid
->data4
[0], guid
->data4
[1],
200 guid
->data4
[2], guid
->data4
[3], guid
->data4
[4],
201 guid
->data4
[5], guid
->data4
[6], guid
->data4
[7]);
211 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
212 * @sid: [IN] SID for which to determine the maximum string size
214 * Determine the maximum multi byte string size in bytes which is needed to
215 * store the standard textual representation of the SID pointed to by @sid.
216 * See ntfs_sid_to_mbs(), below.
218 * On success return the maximum number of bytes needed to store the multi byte
219 * string and on failure return -1 with errno set to the error code.
221 int ntfs_sid_to_mbs_size(const SID
*sid
)
225 if (!ntfs_valid_sid(sid
)) {
229 /* Start with "S-". */
232 * Add the SID_REVISION. Hopefully the compiler will optimize this
233 * away as SID_REVISION is a constant.
235 for (i
= SID_REVISION
; i
> 0; i
/= 10)
240 * Add the identifier authority. If it needs to be in decimal, the
241 * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
242 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
244 if (!sid
->identifier_authority
.high_part
)
249 * Finally, add the sub authorities. For each we have a "-" followed
250 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
252 size
+= (1 + 10) * sid
->sub_authority_count
;
253 /* We need the zero byte at the end, too. */
255 return size
* sizeof(char);
259 * ntfs_sid_to_mbs - convert a SID to a multi byte string
260 * @sid: [IN] SID to convert
261 * @sid_str: [OUT] string in which to return the SID (optional)
262 * @sid_str_size: [IN] size in bytes of @sid_str
264 * Convert the SID pointed to by @sid to its standard textual representation.
265 * @sid_str (if not NULL) needs to be able to store at least
266 * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
267 * @sid_str if @sid_str is not NULL.
269 * The standard textual representation of the SID is of the form:
272 * - The first "S" is the literal character 'S' identifying the following
274 * - R is the revision level of the SID expressed as a sequence of digits
276 * - I is the 48-bit identifier_authority, expressed as digits in decimal,
277 * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
278 * - S... is one or more sub_authority values, expressed as digits in
281 * If @sid_str is not NULL it will contain the converted SUID on return. If it
282 * is NULL a string will be allocated and this will be returned. The caller is
283 * responsible for free()ing the string in that case.
285 * On success return the converted string and on failure return NULL with errno
286 * set to the error code.
288 char *ntfs_sid_to_mbs(const SID
*sid
, char *sid_str
, size_t sid_str_size
)
296 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
297 * check @sid, too. 8 is the minimum SID string size.
299 if (sid_str
&& (sid_str_size
< 8 || !ntfs_valid_sid(sid
))) {
303 /* Allocate string if not provided. */
305 cnt
= ntfs_sid_to_mbs_size(sid
);
308 s
= (char*)ntfs_malloc(cnt
);
312 /* So we know we allocated it. */
318 /* Start with "S-R-". */
319 i
= snprintf(s
, cnt
, "S-%hhu-", (unsigned char)sid
->revision
);
320 if (i
< 0 || i
>= cnt
)
324 /* Add the identifier authority. */
325 for (u
= i
= 0, j
= 40; i
< 6; i
++, j
-= 8)
326 u
+= (u64
)sid
->identifier_authority
.value
[i
] << j
;
327 if (!sid
->identifier_authority
.high_part
)
328 i
= snprintf(s
, cnt
, "%lu", (unsigned long)u
);
330 i
= snprintf(s
, cnt
, "0x%llx", (unsigned long long)u
);
331 if (i
< 0 || i
>= cnt
)
335 /* Finally, add the sub authorities. */
336 for (j
= 0; j
< sid
->sub_authority_count
; j
++) {
337 leauth
= sid
->sub_authority
[j
];
338 i
= snprintf(s
, cnt
, "-%u", (unsigned int)
339 le32_to_cpu(leauth
));
340 if (i
< 0 || i
>= cnt
)
358 * ntfs_generate_guid - generatates a random current guid.
359 * @guid: [OUT] pointer to a GUID struct to hold the generated guid.
361 * perhaps not a very good random number generator though...
363 void ntfs_generate_guid(GUID
*guid
)
368 /* this is called at most once from mkntfs */
369 srandom(time((time_t*)NULL
) ^ (getpid() << 16));
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
)) {
517 * Make sure the data size for $SDS marks the end
518 * of the last security attribute. Windows uses
519 * this to determine where the next attribute will
520 * be written, which causes issues if chkdsk had
521 * previously deleted the last entries without
522 * adjusting the size.
524 res
= ntfs_attr_shrink_size(vol
->secure_ni
,STREAM_SDS
,
525 4, offs
- gap
+ ALIGN_SDS_BLOCK
+ fullsz
);
535 * Enter a new security descriptor in $Secure (indexes only)
537 * Should only be called by entersecurityattr() to ensure consistency
539 * Returns zero if sucessful
542 static int entersecurity_indexes(ntfs_volume
*vol
, s64 attrsz
,
543 le32 hash
, le32 keyid
, off_t offs
)
553 ntfs_index_context
*xsii
;
554 ntfs_index_context
*xsdh
;
559 /* enter a new $SII record */
561 xsii
= vol
->secure_xsii
;
562 ntfs_index_ctx_reinit(xsii
);
563 newsii
.offs
= const_cpu_to_le16(20);
564 newsii
.size
= const_cpu_to_le16(sizeof(struct SII
) - 20);
565 newsii
.fill1
= const_cpu_to_le32(0);
566 newsii
.indexsz
= const_cpu_to_le16(sizeof(struct SII
));
567 newsii
.indexksz
= const_cpu_to_le16(sizeof(SII_INDEX_KEY
));
568 newsii
.flags
= const_cpu_to_le16(0);
569 newsii
.fill2
= const_cpu_to_le16(0);
570 newsii
.keysecurid
= keyid
;
572 newsii
.securid
= keyid
;
573 realign
.all
= cpu_to_le64(offs
);
574 newsii
.dataoffsh
= realign
.parts
.dataoffsh
;
575 newsii
.dataoffsl
= realign
.parts
.dataoffsl
;
576 newsii
.datasize
= cpu_to_le32(attrsz
577 + sizeof(SECURITY_DESCRIPTOR_HEADER
));
578 if (!ntfs_ie_add(xsii
,(INDEX_ENTRY
*)&newsii
)) {
580 /* enter a new $SDH record */
582 xsdh
= vol
->secure_xsdh
;
583 ntfs_index_ctx_reinit(xsdh
);
584 newsdh
.offs
= const_cpu_to_le16(24);
585 newsdh
.size
= const_cpu_to_le16(
586 sizeof(SECURITY_DESCRIPTOR_HEADER
));
587 newsdh
.fill1
= const_cpu_to_le32(0);
588 newsdh
.indexsz
= const_cpu_to_le16(
590 newsdh
.indexksz
= const_cpu_to_le16(
591 sizeof(SDH_INDEX_KEY
));
592 newsdh
.flags
= const_cpu_to_le16(0);
593 newsdh
.fill2
= const_cpu_to_le16(0);
594 newsdh
.keyhash
= hash
;
595 newsdh
.keysecurid
= keyid
;
597 newsdh
.securid
= keyid
;
598 newsdh
.dataoffsh
= realign
.parts
.dataoffsh
;
599 newsdh
.dataoffsl
= realign
.parts
.dataoffsl
;
600 newsdh
.datasize
= cpu_to_le32(attrsz
601 + sizeof(SECURITY_DESCRIPTOR_HEADER
));
602 /* special filler value, Windows generally */
603 /* fills with 0x00490049, sometimes with zero */
604 newsdh
.fill3
= const_cpu_to_le32(0x00490049);
605 if (!ntfs_ie_add(xsdh
,(INDEX_ENTRY
*)&newsdh
))
612 * Enter a new security descriptor in $Secure (data and indexes)
613 * Returns id of entry, or zero if there is a problem.
614 * (should not be called for NTFS version < 3.0)
616 * important : calls have to be serialized, however no locking is
617 * needed while fuse is not multithreaded
620 static le32
entersecurityattr(ntfs_volume
*vol
,
621 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
,
641 ntfs_index_context
*xsii
;
646 /* find the first available securid beyond the last key */
647 /* in $Secure:$SII. This also determines the first */
648 /* available location in $Secure:$SDS, as this stream */
649 /* is always appended to and the id's are allocated */
652 securid
= const_cpu_to_le32(0);
653 xsii
= vol
->secure_xsii
;
654 ntfs_index_ctx_reinit(xsii
);
656 keyid
= const_cpu_to_le32(-1);
658 found
= !ntfs_index_lookup((char*)&keyid
,
659 sizeof(SII_INDEX_KEY
), xsii
);
660 if (!found
&& (errno
!= ENOENT
)) {
661 ntfs_log_perror("Inconsistency in index $SII");
662 psii
= (struct SII
*)NULL
;
664 /* restore errno to avoid misinterpretation */
667 psii
= (struct SII
*)xsii
->entry
;
671 * Get last entry in block, but must get first one
672 * one first, as we should already be beyond the
673 * last one. For some reason the search for the last
674 * entry sometimes does not return the last block...
675 * we assume this can only happen in root block
677 if (xsii
->is_in_root
)
678 entry
= ntfs_ie_get_first
679 ((INDEX_HEADER
*)&xsii
->ir
->index
);
681 entry
= ntfs_ie_get_first
682 ((INDEX_HEADER
*)&xsii
->ib
->index
);
684 * All index blocks should be at least half full
685 * so there always is a last entry but one,
686 * except when creating the first entry in index root.
687 * This was however found not to be true : chkdsk
688 * sometimes deletes all the (unused) keys in the last
689 * index block without rebalancing the tree.
690 * When this happens, a new search is restarted from
693 keyid
= const_cpu_to_le32(0);
696 next
= ntfs_index_next(entry
,xsii
);
698 psii
= (struct SII
*)next
;
699 /* save last key and */
700 /* available position */
701 keyid
= psii
->keysecurid
;
702 realign
.parts
.dataoffsh
704 realign
.parts
.dataoffsl
706 offs
= le64_to_cpu(realign
.all
);
707 size
= le32_to_cpu(psii
->datasize
);
710 if (!entry
&& !keyid
&& !retries
) {
711 /* search failed, retry from smallest key */
712 ntfs_index_ctx_reinit(xsii
);
713 found
= !ntfs_index_lookup((char*)&keyid
,
714 sizeof(SII_INDEX_KEY
), xsii
);
715 if (!found
&& (errno
!= ENOENT
)) {
716 ntfs_log_perror("Index $SII is broken");
717 psii
= (struct SII
*)NULL
;
722 psii
= (struct SII
*)entry
;
725 && !(psii
->flags
& INDEX_ENTRY_END
)) {
726 /* save first key and */
727 /* available position */
728 keyid
= psii
->keysecurid
;
729 realign
.parts
.dataoffsh
731 realign
.parts
.dataoffsl
733 offs
= le64_to_cpu(realign
.all
);
734 size
= le32_to_cpu(psii
->datasize
);
742 * could not find any entry, before creating the first
743 * entry, make a double check by making sure size of $SII
744 * is less than needed for one entry
746 securid
= const_cpu_to_le32(0);
747 na
= ntfs_attr_open(vol
->secure_ni
,AT_INDEX_ROOT
,sii_stream
,4);
749 if ((size_t)na
->data_size
< (sizeof(struct SII
)
750 + sizeof(INDEX_ENTRY_HEADER
))) {
751 ntfs_log_error("Creating the first security_id\n");
752 securid
= const_cpu_to_le32(FIRST_SECURITY_ID
);
757 ntfs_log_error("Error creating a security_id\n");
761 newkey
= le32_to_cpu(keyid
) + 1;
762 securid
= cpu_to_le32(newkey
);
765 * The security attr has to be written twice 256KB
766 * apart. This implies that offsets like
767 * 0x40000*odd_integer must be left available for
768 * the second copy. So align to next block when
769 * the last byte overflows on a wrong block.
773 gap
= (-size
) & (ALIGN_SDS_ENTRY
- 1);
775 if ((offs
+ attrsz
+ sizeof(SECURITY_DESCRIPTOR_HEADER
) - 1)
777 offs
= ((offs
+ attrsz
778 + sizeof(SECURITY_DESCRIPTOR_HEADER
) - 1)
779 | (ALIGN_SDS_BLOCK
- 1)) + 1;
781 if (!(offs
& (ALIGN_SDS_BLOCK
- 1)))
782 entersecurity_stuff(vol
, offs
);
784 * now write the security attr to storage :
785 * first data, then SII, then SDH
786 * If failure occurs while writing SDS, data will never
787 * be accessed through indexes, and will be overwritten
788 * by the next allocated descriptor
789 * If failure occurs while writing SII, the id has not
790 * recorded and will be reallocated later
791 * If failure occurs while writing SDH, the space allocated
792 * in SDS or SII will not be reused, an inconsistency
793 * will persist with no significant consequence
795 if (entersecurity_data(vol
, attr
, attrsz
, hash
, securid
, offs
, gap
)
796 || entersecurity_indexes(vol
, attrsz
, hash
, securid
, offs
))
797 securid
= const_cpu_to_le32(0);
799 /* inode now is dirty, synchronize it all */
800 ntfs_index_entry_mark_dirty(vol
->secure_xsii
);
801 ntfs_index_ctx_reinit(vol
->secure_xsii
);
802 ntfs_index_entry_mark_dirty(vol
->secure_xsdh
);
803 ntfs_index_ctx_reinit(vol
->secure_xsdh
);
804 NInoSetDirty(vol
->secure_ni
);
805 if (ntfs_inode_sync(vol
->secure_ni
))
806 ntfs_log_perror("Could not sync $Secure\n");
811 * Find a matching security descriptor in $Secure,
812 * if none, allocate a new id and write the descriptor to storage
813 * Returns id of entry, or zero if there is a problem.
815 * important : calls have to be serialized, however no locking is
816 * needed while fuse is not multithreaded
819 static le32
setsecurityattr(ntfs_volume
*vol
,
820 const SECURITY_DESCRIPTOR_RELATIVE
*attr
, s64 attrsz
)
822 struct SDH
*psdh
; /* this is an image of index (le) */
836 ntfs_index_context
*xsdh
;
844 hash
= ntfs_security_hash(attr
,attrsz
);
845 oldattr
= (char*)NULL
;
846 securid
= const_cpu_to_le32(0);
848 xsdh
= vol
->secure_xsdh
;
849 if (vol
->secure_ni
&& xsdh
&& !vol
->secure_reentry
++) {
850 ntfs_index_ctx_reinit(xsdh
);
852 * find the nearest key as (hash,0)
853 * (do not search for partial key : in case of collision,
854 * it could return a key which is not the first one which
858 key
.security_id
= const_cpu_to_le32(0);
860 found
= !ntfs_index_lookup((char*)&key
,
861 sizeof(SDH_INDEX_KEY
), xsdh
);
862 if (!found
&& (errno
!= ENOENT
))
863 ntfs_log_perror("Inconsistency in index $SDH");
865 /* restore errno to avoid misinterpretation */
870 * lookup() may return a node with no data,
873 if (entry
->ie_flags
& INDEX_ENTRY_END
)
874 entry
= ntfs_index_next(entry
,xsdh
);
877 psdh
= (struct SDH
*)entry
;
879 size
= (size_t) le32_to_cpu(psdh
->datasize
)
880 - sizeof(SECURITY_DESCRIPTOR_HEADER
);
882 /* if hash is not the same, the key is not present */
883 if (psdh
&& (size
> 0)
884 && (psdh
->keyhash
== hash
)) {
885 /* if hash is the same */
886 /* check the whole record */
887 realign
.parts
.dataoffsh
= psdh
->dataoffsh
;
888 realign
.parts
.dataoffsl
= psdh
->dataoffsl
;
889 offs
= le64_to_cpu(realign
.all
)
890 + sizeof(SECURITY_DESCRIPTOR_HEADER
);
891 oldattr
= (char*)ntfs_malloc(size
);
893 rdsize
= ntfs_attr_data_read(
896 oldattr
, size
, offs
);
897 found
= (rdsize
== size
)
898 && !memcmp(oldattr
,attr
,size
);
900 /* if the records do not compare */
901 /* (hash collision), try next one */
903 entry
= ntfs_index_next(
910 } while (collision
&& entry
);
912 securid
= psdh
->keysecurid
;
916 securid
= const_cpu_to_le32(0);
920 * have to build a new one
922 securid
= entersecurityattr(vol
,
928 if (--vol
->secure_reentry
)
929 ntfs_log_perror("Reentry error, check no multithreading\n");
935 * Update the security descriptor of a file
936 * Either as an attribute (complying with pre v3.x NTFS version)
937 * or, when possible, as an entry in $Secure (for NTFS v3.x)
939 * returns 0 if success
942 static int update_secur_descr(ntfs_volume
*vol
,
943 char *newattr
, ntfs_inode
*ni
)
950 newattrsz
= ntfs_attr_size(newattr
);
952 #if !FORCE_FORMAT_v1x
953 if ((vol
->major_ver
< 3) || !vol
->secure_ni
) {
956 /* update for NTFS format v1.x */
958 /* update the old security attribute */
959 na
= ntfs_attr_open(ni
, AT_SECURITY_DESCRIPTOR
, AT_UNNAMED
, 0);
961 /* resize attribute */
962 res
= ntfs_attr_truncate(na
, (s64
) newattrsz
);
963 /* overwrite value */
965 written
= (int)ntfs_attr_pwrite(na
, (s64
) 0,
966 (s64
) newattrsz
, newattr
);
967 if (written
!= newattrsz
) {
968 ntfs_log_error("Failed to update "
969 "a v1.x security descriptor\n");
976 /* if old security attribute was found, also */
977 /* truncate standard information attribute to v1.x */
978 /* this is needed when security data is wanted */
979 /* as v1.x though volume is formatted for v3.x */
980 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
983 clear_nino_flag(ni
, v3_Extensions
);
985 * Truncating the record does not sweep extensions
986 * from copy in memory. Clear security_id to be safe
988 ni
->security_id
= const_cpu_to_le32(0);
989 res
= ntfs_attr_truncate(na
, (s64
)48);
991 clear_nino_flag(ni
, v3_Extensions
);
995 * insert the new security attribute if there
998 res
= ntfs_attr_add(ni
, AT_SECURITY_DESCRIPTOR
,
999 AT_UNNAMED
, 0, (u8
*)newattr
,
1002 #if !FORCE_FORMAT_v1x
1005 /* update for NTFS format v3.x */
1009 securid
= setsecurityattr(vol
,
1010 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
1013 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
1017 if (!test_nino_flag(ni
, v3_Extensions
)) {
1018 /* expand standard information attribute to v3.x */
1019 res
= ntfs_attr_truncate(na
,
1020 (s64
)sizeof(STANDARD_INFORMATION
));
1021 ni
->owner_id
= const_cpu_to_le32(0);
1022 ni
->quota_charged
= const_cpu_to_le64(0);
1023 ni
->usn
= const_cpu_to_le64(0);
1024 ntfs_attr_remove(ni
,
1025 AT_SECURITY_DESCRIPTOR
,
1028 set_nino_flag(ni
, v3_Extensions
);
1029 ni
->security_id
= securid
;
1030 ntfs_attr_close(na
);
1032 ntfs_log_error("Failed to update "
1033 "standard informations\n");
1042 /* mark node as dirty */
1048 * Upgrade the security descriptor of a file
1049 * This is intended to allow graceful upgrades for files which
1050 * were created in previous versions, with a security attributes
1051 * and no security id.
1053 * It will allocate a security id and replace the individual
1054 * security attribute by a reference to the global one
1056 * Special files are not upgraded (currently / and files in
1059 * Though most code is similar to update_secur_desc() it has
1060 * been kept apart to facilitate the further processing of
1061 * special cases or even to remove it if found dangerous.
1063 * returns 0 if success,
1064 * 1 if not upgradable. This is not an error.
1065 * -1 if there is a problem
1068 static int upgrade_secur_desc(ntfs_volume
*vol
,
1069 const char *attr
, ntfs_inode
*ni
)
1077 * upgrade requires NTFS format v3.x
1078 * also refuse upgrading for special files
1079 * whose number is less than FILE_first_user
1082 if ((vol
->major_ver
>= 3)
1083 && (ni
->mft_no
>= FILE_first_user
)) {
1084 attrsz
= ntfs_attr_size(attr
);
1085 securid
= setsecurityattr(vol
,
1086 (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
,
1089 na
= ntfs_attr_open(ni
, AT_STANDARD_INFORMATION
,
1092 /* expand standard information attribute to v3.x */
1093 res
= ntfs_attr_truncate(na
,
1094 (s64
)sizeof(STANDARD_INFORMATION
));
1095 ni
->owner_id
= const_cpu_to_le32(0);
1096 ni
->quota_charged
= const_cpu_to_le64(0);
1097 ni
->usn
= const_cpu_to_le64(0);
1098 ntfs_attr_remove(ni
, AT_SECURITY_DESCRIPTOR
,
1100 set_nino_flag(ni
, v3_Extensions
);
1101 ni
->security_id
= securid
;
1102 ntfs_attr_close(na
);
1104 ntfs_log_error("Failed to upgrade "
1105 "standard informations\n");
1111 /* mark node as dirty */
1120 * Optional simplified checking of group membership
1122 * This only takes into account the groups defined in
1123 * /etc/group at initialization time.
1124 * It does not take into account the groups dynamically set by
1125 * setgroups() nor the changes in /etc/group since initialization
1127 * This optional method could be useful if standard checking
1128 * leads to a performance concern.
1130 * Should not be called for user root, however the group may be root
1134 static BOOL
staticgroupmember(struct SECURITY_CONTEXT
*scx
, uid_t uid
, gid_t gid
)
1139 struct MAPPING
*user
;
1143 user
= scx
->mapping
[MAPUSERS
];
1144 while (user
&& ((uid_t
)user
->xid
!= uid
))
1147 groups
= user
->groups
;
1148 grcnt
= user
->grcnt
;
1149 while ((--grcnt
>= 0) && (groups
[grcnt
] != gid
)) { }
1150 ingroup
= (grcnt
>= 0);
1156 #if defined(__sun) && defined (__SVR4)
1159 * Check whether current thread owner is member of file group
1160 * Solaris/OpenIndiana version
1161 * Should not be called for user root, however the group may be root
1163 * The group list is available in "/proc/$PID/cred"
1167 static BOOL
groupmember(struct SECURITY_CONTEXT
*scx
, uid_t uid
, gid_t gid
)
1169 typedef struct prcred
{
1170 uid_t pr_euid
; /* effective user id */
1171 uid_t pr_ruid
; /* real user id */
1172 uid_t pr_suid
; /* saved user id (from exec) */
1173 gid_t pr_egid
; /* effective group id */
1174 gid_t pr_rgid
; /* real group id */
1175 gid_t pr_sgid
; /* saved group id (from exec) */
1176 int pr_ngroups
; /* number of supplementary groups */
1177 gid_t pr_groups
[1]; /* array of supplementary groups */
1179 enum { readset
= 16 };
1182 gid_t groups
[readset
];
1192 if (scx
->vol
->secure_flags
& (1 << SECURITY_STATICGRPS
))
1193 ismember
= staticgroupmember(scx
, uid
, gid
);
1195 ismember
= FALSE
; /* default return */
1197 sprintf(filename
,"/proc/%u/cred",tid
);
1198 fd
= open(filename
,O_RDONLY
);
1200 got
= read(fd
, &basecreds
, sizeof(prcred_t
));
1201 if (got
== sizeof(prcred_t
)) {
1202 if (basecreds
.pr_egid
== gid
)
1204 p
= basecreds
.pr_groups
;
1208 && (k
< basecreds
.pr_ngroups
)
1215 got
= read(fd
, groups
,
1216 readset
*sizeof(gid_t
));
1217 cnt
= got
/sizeof(gid_t
);
1222 && (k
< basecreds
.pr_ngroups
))
1231 #else /* defined(__sun) && defined (__SVR4) */
1234 * Check whether current thread owner is member of file group
1236 * Should not be called for user root, however the group may be root
1238 * As indicated by Miklos Szeredi :
1240 * The group list is available in
1242 * /proc/$PID/task/$TID/status
1244 * and fuse supplies TID in get_fuse_context()->pid. The only problem is
1245 * finding out PID, for which I have no good solution, except to iterate
1246 * through all processes. This is rather slow, but may be speeded up
1247 * with caching and heuristics (for single threaded programs PID = TID).
1249 * The following implementation gets the group list from
1250 * /proc/$TID/task/$TID/status which apparently exists and
1251 * contains the same data.
1254 static BOOL
groupmember(struct SECURITY_CONTEXT
*scx
, uid_t uid
, gid_t gid
)
1256 static char key
[] = "\nGroups:";
1259 enum { INKEY
, INSEP
, INNUM
, INEND
} state
;
1269 if (scx
->vol
->secure_flags
& (1 << SECURITY_STATICGRPS
))
1270 ismember
= staticgroupmember(scx
, uid
, gid
);
1272 ismember
= FALSE
; /* default return */
1274 sprintf(filename
,"/proc/%u/task/%u/status",tid
,tid
);
1275 fd
= open(filename
,O_RDONLY
);
1277 got
= read(fd
, buf
, BUFSZ
);
1284 * A simple automaton to process lines like
1285 * Groups: 14 500 513
1291 got
= read(fd
, buf
, BUFSZ
);
1294 c
= *p
++; /* 0 at end of file */
1298 if (key
[matched
] == c
) {
1299 if (!key
[++matched
])
1308 if ((c
>= '0') && (c
<= '9')) {
1312 if ((c
!= ' ') && (c
!= '\t'))
1316 if ((c
>= '0') && (c
<= '9'))
1317 grp
= grp
*10 + c
- '0';
1319 ismember
= (grp
== gid
);
1320 if ((c
!= ' ') && (c
!= '\t'))
1328 } while (!ismember
&& c
&& (state
!= INEND
));
1331 ntfs_log_error("No group record found in %s\n",filename
);
1333 ntfs_log_error("Could not open %s\n",filename
);
1338 #endif /* defined(__sun) && defined (__SVR4) */
1343 * Extract the basic permissions from a Posix ACL
1345 * This is only to be used when Posix ACLs are compiled in,
1346 * but not enabled in the mount options.
1348 * it replaces the permission mask by the group permissions.
1349 * If special groups are mapped, they are also considered as world.
1352 static int ntfs_basic_perms(const struct SECURITY_CONTEXT
*scx
,
1353 const struct POSIX_SECURITY
*pxdesc
)
1357 const struct POSIX_ACE
*pace
;
1358 const struct MAPPING
* group
;
1361 perms
= pxdesc
->mode
;
1362 for (k
=0; k
< pxdesc
->acccnt
; k
++) {
1363 pace
= &pxdesc
->acl
.ace
[k
];
1364 if (pace
->tag
== POSIX_ACL_GROUP_OBJ
)
1365 perms
= (perms
& 07707)
1366 | ((pace
->perms
& 7) << 3);
1368 if (pace
->tag
== POSIX_ACL_GROUP
) {
1369 group
= scx
->mapping
[MAPGROUPS
];
1370 while (group
&& (group
->xid
!= pace
->id
))
1371 group
= group
->next
;
1372 if (group
&& group
->grcnt
1373 && (*(group
->groups
) == (gid_t
)pace
->id
))
1374 perms
|= pace
->perms
& 7;
1380 #endif /* POSIXACLS */
1383 * Cacheing is done two-way :
1384 * - from uid, gid and perm to securid (CACHED_SECURID)
1385 * - from a securid to uid, gid and perm (CACHED_PERMISSIONS)
1387 * CACHED_SECURID data is kept in a most-recent-first list
1388 * which should not be too long to be efficient. Its optimal
1389 * size is depends on usage and is hard to determine.
1391 * CACHED_PERMISSIONS data is kept in a two-level indexed array. It
1392 * is optimal at the expense of storage. Use of a most-recent-first
1393 * list would save memory and provide similar performances for
1394 * standard usage, but not for file servers with too many file
1397 * CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS
1398 * for legacy directories which were not allocated a security_id
1399 * it is organized in a most-recent-first list.
1401 * In main caches, data is never invalidated, as the meaning of
1402 * a security_id only changes when user mapping is changed, which
1403 * current implies remounting. However returned entries may be
1404 * overwritten at next update, so data has to be copied elsewhere
1405 * before another cache update is made.
1406 * In legacy cache, data has to be invalidated when protection is
1409 * Though the same data may be found in both list, they
1410 * must be kept separately : the interpretation of ACL
1411 * in both direction are approximations which could be non
1412 * reciprocal for some configuration of the user mapping data
1414 * During the process of recompiling ntfs-3g from a tgz archive,
1415 * security processing added 7.6% to the cpu time used by ntfs-3g
1416 * and 30% if the cache is disabled.
1419 static struct PERMISSIONS_CACHE
*create_caches(struct SECURITY_CONTEXT
*scx
,
1422 struct PERMISSIONS_CACHE
*cache
;
1423 unsigned int index1
;
1426 cache
= (struct PERMISSIONS_CACHE
*)NULL
;
1427 /* create the first permissions blocks */
1428 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1429 cache
= (struct PERMISSIONS_CACHE
*)
1430 ntfs_malloc(sizeof(struct PERMISSIONS_CACHE
)
1431 + index1
*sizeof(struct CACHED_PERMISSIONS
*));
1433 cache
->head
.last
= index1
;
1434 cache
->head
.p_reads
= 0;
1435 cache
->head
.p_hits
= 0;
1436 cache
->head
.p_writes
= 0;
1437 *scx
->pseccache
= cache
;
1438 for (i
=0; i
<=index1
; i
++)
1439 cache
->cachetable
[i
]
1440 = (struct CACHED_PERMISSIONS
*)NULL
;
1446 * Free memory used by caches
1447 * The only purpose is to facilitate the detection of memory leaks
1450 static void free_caches(struct SECURITY_CONTEXT
*scx
)
1452 unsigned int index1
;
1453 struct PERMISSIONS_CACHE
*pseccache
;
1455 pseccache
= *scx
->pseccache
;
1457 for (index1
=0; index1
<=pseccache
->head
.last
; index1
++)
1458 if (pseccache
->cachetable
[index1
]) {
1460 struct CACHED_PERMISSIONS
*cacheentry
;
1461 unsigned int index2
;
1463 for (index2
=0; index2
<(1<< CACHE_PERMISSIONS_BITS
); index2
++) {
1464 cacheentry
= &pseccache
->cachetable
[index1
][index2
];
1465 if (cacheentry
->valid
1466 && cacheentry
->pxdesc
)
1467 free(cacheentry
->pxdesc
);
1470 free(pseccache
->cachetable
[index1
]);
1476 static int compare(const struct CACHED_SECURID
*cached
,
1477 const struct CACHED_SECURID
*item
)
1483 /* only compare data and sizes */
1484 csize
= (cached
->variable
?
1485 sizeof(struct POSIX_ACL
)
1486 + (((struct POSIX_SECURITY
*)cached
->variable
)->acccnt
1487 + ((struct POSIX_SECURITY
*)cached
->variable
)->defcnt
)
1488 *sizeof(struct POSIX_ACE
) :
1490 isize
= (item
->variable
?
1491 sizeof(struct POSIX_ACL
)
1492 + (((struct POSIX_SECURITY
*)item
->variable
)->acccnt
1493 + ((struct POSIX_SECURITY
*)item
->variable
)->defcnt
)
1494 *sizeof(struct POSIX_ACE
) :
1496 return ((cached
->uid
!= item
->uid
)
1497 || (cached
->gid
!= item
->gid
)
1498 || (cached
->dmode
!= item
->dmode
)
1502 && memcmp(&((struct POSIX_SECURITY
*)cached
->variable
)->acl
,
1503 &((struct POSIX_SECURITY
*)item
->variable
)->acl
, csize
)));
1505 return ((cached
->uid
!= item
->uid
)
1506 || (cached
->gid
!= item
->gid
)
1507 || (cached
->dmode
!= item
->dmode
));
1511 static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY
*cached
,
1512 const struct CACHED_PERMISSIONS_LEGACY
*item
)
1514 return (cached
->mft_no
!= item
->mft_no
);
1518 * Resize permission cache table
1519 * do not call unless resizing is needed
1521 * If allocation fails, the cache size is not updated
1522 * Lack of memory is not considered as an error, the cache is left
1523 * consistent and errno is not set.
1526 static void resize_cache(struct SECURITY_CONTEXT
*scx
,
1529 struct PERMISSIONS_CACHE
*oldcache
;
1530 struct PERMISSIONS_CACHE
*newcache
;
1533 unsigned int index1
;
1536 oldcache
= *scx
->pseccache
;
1537 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1538 newcnt
= index1
+ 1;
1539 if (newcnt
<= ((CACHE_PERMISSIONS_SIZE
1540 + (1 << CACHE_PERMISSIONS_BITS
)
1541 - 1) >> CACHE_PERMISSIONS_BITS
)) {
1542 /* expand cache beyond current end, do not use realloc() */
1543 /* to avoid losing data when there is no more memory */
1544 oldcnt
= oldcache
->head
.last
+ 1;
1545 newcache
= (struct PERMISSIONS_CACHE
*)
1547 sizeof(struct PERMISSIONS_CACHE
)
1548 + (newcnt
- 1)*sizeof(struct CACHED_PERMISSIONS
*));
1550 memcpy(newcache
,oldcache
,
1551 sizeof(struct PERMISSIONS_CACHE
)
1552 + (oldcnt
- 1)*sizeof(struct CACHED_PERMISSIONS
*));
1554 /* mark new entries as not valid */
1555 for (i
=newcache
->head
.last
+1; i
<=index1
; i
++)
1556 newcache
->cachetable
[i
]
1557 = (struct CACHED_PERMISSIONS
*)NULL
;
1558 newcache
->head
.last
= index1
;
1559 *scx
->pseccache
= newcache
;
1565 * Enter uid, gid and mode into cache, if possible
1567 * returns the updated or created cache entry,
1568 * or NULL if not possible (typically if there is no
1569 * security id associated)
1573 static struct CACHED_PERMISSIONS
*enter_cache(struct SECURITY_CONTEXT
*scx
,
1574 ntfs_inode
*ni
, uid_t uid
, gid_t gid
,
1575 struct POSIX_SECURITY
*pxdesc
)
1577 static struct CACHED_PERMISSIONS
*enter_cache(struct SECURITY_CONTEXT
*scx
,
1578 ntfs_inode
*ni
, uid_t uid
, gid_t gid
, mode_t mode
)
1581 struct CACHED_PERMISSIONS
*cacheentry
;
1582 struct CACHED_PERMISSIONS
*cacheblock
;
1583 struct PERMISSIONS_CACHE
*pcache
;
1587 struct POSIX_SECURITY
*pxcached
;
1589 unsigned int index1
;
1590 unsigned int index2
;
1593 /* cacheing is only possible if a security_id has been defined */
1594 if (test_nino_flag(ni
, v3_Extensions
)
1595 && ni
->security_id
) {
1597 * Immediately test the most frequent situation
1598 * where the entry exists
1600 securindex
= le32_to_cpu(ni
->security_id
);
1601 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1602 index2
= securindex
& ((1 << CACHE_PERMISSIONS_BITS
) - 1);
1603 pcache
= *scx
->pseccache
;
1605 && (pcache
->head
.last
>= index1
)
1606 && pcache
->cachetable
[index1
]) {
1607 cacheentry
= &pcache
->cachetable
[index1
][index2
];
1608 cacheentry
->uid
= uid
;
1609 cacheentry
->gid
= gid
;
1611 if (cacheentry
->valid
&& cacheentry
->pxdesc
)
1612 free(cacheentry
->pxdesc
);
1614 pxsize
= sizeof(struct POSIX_SECURITY
)
1615 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1616 pxcached
= (struct POSIX_SECURITY
*)malloc(pxsize
);
1618 memcpy(pxcached
, pxdesc
, pxsize
);
1619 cacheentry
->pxdesc
= pxcached
;
1621 cacheentry
->valid
= 0;
1622 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1624 cacheentry
->mode
= pxdesc
->mode
& 07777;
1626 cacheentry
->pxdesc
= (struct POSIX_SECURITY
*)NULL
;
1628 cacheentry
->mode
= mode
& 07777;
1630 cacheentry
->inh_fileid
= const_cpu_to_le32(0);
1631 cacheentry
->inh_dirid
= const_cpu_to_le32(0);
1632 cacheentry
->valid
= 1;
1633 pcache
->head
.p_writes
++;
1636 /* create the first cache block */
1637 pcache
= create_caches(scx
, securindex
);
1639 if (index1
> pcache
->head
.last
) {
1640 resize_cache(scx
, securindex
);
1641 pcache
= *scx
->pseccache
;
1644 /* allocate block, if cache table was allocated */
1645 if (pcache
&& (index1
<= pcache
->head
.last
)) {
1646 cacheblock
= (struct CACHED_PERMISSIONS
*)
1647 malloc(sizeof(struct CACHED_PERMISSIONS
)
1648 << CACHE_PERMISSIONS_BITS
);
1649 pcache
->cachetable
[index1
] = cacheblock
;
1650 for (i
=0; i
<(1 << CACHE_PERMISSIONS_BITS
); i
++)
1651 cacheblock
[i
].valid
= 0;
1652 cacheentry
= &cacheblock
[index2
];
1654 cacheentry
->uid
= uid
;
1655 cacheentry
->gid
= gid
;
1658 pxsize
= sizeof(struct POSIX_SECURITY
)
1659 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1660 pxcached
= (struct POSIX_SECURITY
*)malloc(pxsize
);
1662 memcpy(pxcached
, pxdesc
, pxsize
);
1663 cacheentry
->pxdesc
= pxcached
;
1665 cacheentry
->valid
= 0;
1666 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1668 cacheentry
->mode
= pxdesc
->mode
& 07777;
1670 cacheentry
->pxdesc
= (struct POSIX_SECURITY
*)NULL
;
1672 cacheentry
->mode
= mode
& 07777;
1674 cacheentry
->inh_fileid
= const_cpu_to_le32(0);
1675 cacheentry
->inh_dirid
= const_cpu_to_le32(0);
1676 cacheentry
->valid
= 1;
1677 pcache
->head
.p_writes
++;
1680 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1683 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1684 #if CACHE_LEGACY_SIZE
1685 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
1686 struct CACHED_PERMISSIONS_LEGACY wanted
;
1687 struct CACHED_PERMISSIONS_LEGACY
*legacy
;
1689 wanted
.perm
.uid
= uid
;
1690 wanted
.perm
.gid
= gid
;
1692 wanted
.perm
.mode
= pxdesc
->mode
& 07777;
1693 wanted
.perm
.inh_fileid
= const_cpu_to_le32(0);
1694 wanted
.perm
.inh_dirid
= const_cpu_to_le32(0);
1695 wanted
.mft_no
= ni
->mft_no
;
1696 wanted
.variable
= (void*)pxdesc
;
1697 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
1698 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
1700 wanted
.perm
.mode
= mode
& 07777;
1701 wanted
.perm
.inh_fileid
= const_cpu_to_le32(0);
1702 wanted
.perm
.inh_dirid
= const_cpu_to_le32(0);
1703 wanted
.mft_no
= ni
->mft_no
;
1704 wanted
.variable
= (void*)NULL
;
1707 legacy
= (struct CACHED_PERMISSIONS_LEGACY
*)ntfs_enter_cache(
1708 scx
->vol
->legacy_cache
, GENERIC(&wanted
),
1709 (cache_compare
)leg_compare
);
1711 cacheentry
= &legacy
->perm
;
1714 * give direct access to the cached pxdesc
1715 * in the permissions structure
1717 cacheentry
->pxdesc
= legacy
->variable
;
1723 return (cacheentry
);
1727 * Fetch owner, group and permission of a file, if cached
1729 * Beware : do not use the returned entry after a cache update :
1730 * the cache may be relocated making the returned entry meaningless
1732 * returns the cache entry, or NULL if not available
1735 static struct CACHED_PERMISSIONS
*fetch_cache(struct SECURITY_CONTEXT
*scx
,
1738 struct CACHED_PERMISSIONS
*cacheentry
;
1739 struct PERMISSIONS_CACHE
*pcache
;
1741 unsigned int index1
;
1742 unsigned int index2
;
1744 /* cacheing is only possible if a security_id has been defined */
1745 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1746 if (test_nino_flag(ni
, v3_Extensions
)
1747 && (ni
->security_id
)) {
1748 securindex
= le32_to_cpu(ni
->security_id
);
1749 index1
= securindex
>> CACHE_PERMISSIONS_BITS
;
1750 index2
= securindex
& ((1 << CACHE_PERMISSIONS_BITS
) - 1);
1751 pcache
= *scx
->pseccache
;
1753 && (pcache
->head
.last
>= index1
)
1754 && pcache
->cachetable
[index1
]) {
1755 cacheentry
= &pcache
->cachetable
[index1
][index2
];
1756 /* reject if entry is not valid */
1757 if (!cacheentry
->valid
)
1758 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1760 pcache
->head
.p_hits
++;
1762 pcache
->head
.p_reads
++;
1765 #if CACHE_LEGACY_SIZE
1767 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1768 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
1769 struct CACHED_PERMISSIONS_LEGACY wanted
;
1770 struct CACHED_PERMISSIONS_LEGACY
*legacy
;
1772 wanted
.mft_no
= ni
->mft_no
;
1773 wanted
.variable
= (void*)NULL
;
1775 legacy
= (struct CACHED_PERMISSIONS_LEGACY
*)ntfs_fetch_cache(
1776 scx
->vol
->legacy_cache
, GENERIC(&wanted
),
1777 (cache_compare
)leg_compare
);
1778 if (legacy
) cacheentry
= &legacy
->perm
;
1783 if (cacheentry
&& !cacheentry
->pxdesc
) {
1784 ntfs_log_error("No Posix descriptor in cache\n");
1785 cacheentry
= (struct CACHED_PERMISSIONS
*)NULL
;
1788 return (cacheentry
);
1792 * Retrieve a security attribute from $Secure
1795 static char *retrievesecurityattr(ntfs_volume
*vol
, SII_INDEX_KEY id
)
1810 ntfs_index_context
*xsii
;
1813 securattr
= (char*)NULL
;
1814 ni
= vol
->secure_ni
;
1815 xsii
= vol
->secure_xsii
;
1817 ntfs_index_ctx_reinit(xsii
);
1819 !ntfs_index_lookup((char*)&id
,
1820 sizeof(SII_INDEX_KEY
), xsii
);
1822 psii
= (struct SII
*)xsii
->entry
;
1824 (size_t) le32_to_cpu(psii
->datasize
)
1825 - sizeof(SECURITY_DESCRIPTOR_HEADER
);
1826 /* work around bad alignment problem */
1827 realign
.parts
.dataoffsh
= psii
->dataoffsh
;
1828 realign
.parts
.dataoffsl
= psii
->dataoffsl
;
1829 offs
= le64_to_cpu(realign
.all
)
1830 + sizeof(SECURITY_DESCRIPTOR_HEADER
);
1832 securattr
= (char*)ntfs_malloc(size
);
1834 rdsize
= ntfs_attr_data_read(
1836 securattr
, size
, offs
);
1837 if ((rdsize
!= size
)
1838 || !ntfs_valid_descr(securattr
,
1840 /* error to be logged by caller */
1842 securattr
= (char*)NULL
;
1846 if (errno
!= ENOENT
)
1847 ntfs_log_perror("Inconsistency in index $SII");
1850 ntfs_log_error("Failed to retrieve a security descriptor\n");
1857 * Get the security descriptor associated to a file
1860 * - read the security descriptor attribute (v1.x format)
1861 * - or find the descriptor in $Secure:$SDS (v3.x format)
1863 * in both case, sanity checks are done on the attribute and
1864 * the descriptor can be assumed safe
1866 * The returned descriptor is dynamically allocated and has to be freed
1869 static char *getsecurityattr(ntfs_volume
*vol
, ntfs_inode
*ni
)
1871 SII_INDEX_KEY securid
;
1876 * Warning : in some situations, after fixing by chkdsk,
1877 * v3_Extensions are marked present (long standard informations)
1878 * with a default security descriptor inserted in an
1881 if (test_nino_flag(ni
, v3_Extensions
)
1882 && vol
->secure_ni
&& ni
->security_id
) {
1883 /* get v3.x descriptor in $Secure */
1884 securid
.security_id
= ni
->security_id
;
1885 securattr
= retrievesecurityattr(vol
,securid
);
1887 ntfs_log_error("Bad security descriptor for 0x%lx\n",
1888 (long)le32_to_cpu(ni
->security_id
));
1890 /* get v1.x security attribute */
1892 securattr
= ntfs_attr_readall(ni
, AT_SECURITY_DESCRIPTOR
,
1893 AT_UNNAMED
, 0, &readallsz
);
1894 if (securattr
&& !ntfs_valid_descr(securattr
, readallsz
)) {
1895 ntfs_log_error("Bad security descriptor for inode %lld\n",
1896 (long long)ni
->mft_no
);
1898 securattr
= (char*)NULL
;
1903 * in some situations, there is no security
1904 * descriptor, and chkdsk does not detect or fix
1905 * anything. This could be a normal situation.
1906 * When this happens, simulate a descriptor with
1907 * minimum rights, so that a real descriptor can
1908 * be created by chown or chmod
1910 ntfs_log_error("No security descriptor found for inode %lld\n",
1911 (long long)ni
->mft_no
);
1912 securattr
= ntfs_build_descr(0, 0, adminsid
, adminsid
);
1920 * Determine which access types to a file are allowed
1921 * according to the relation of current process to the file
1923 * When Posix ACLs are compiled in but not enabled in the mount
1924 * options POSIX_ACL_USER, POSIX_ACL_GROUP and POSIX_ACL_MASK
1928 static int access_check_posix(struct SECURITY_CONTEXT
*scx
,
1929 struct POSIX_SECURITY
*pxdesc
, mode_t request
,
1930 uid_t uid
, gid_t gid
)
1932 struct POSIX_ACE
*pxace
;
1942 noacl
= !(scx
->vol
->secure_flags
& (1 << SECURITY_ACL
));
1944 perms
= ntfs_basic_perms(scx
, pxdesc
);
1946 perms
= pxdesc
->mode
;
1947 /* owner and root access */
1948 if (!scx
->uid
|| (uid
== scx
->uid
)) {
1950 /* root access if owner or other execution */
1954 /* root access if some group execution */
1957 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1958 pxace
= &pxdesc
->acl
.ace
[i
];
1959 switch (pxace
->tag
) {
1960 case POSIX_ACL_USER_OBJ
:
1961 case POSIX_ACL_GROUP_OBJ
:
1962 groupperms
|= pxace
->perms
;
1964 case POSIX_ACL_GROUP
:
1969 case POSIX_ACL_MASK
:
1971 mask
= pxace
->perms
& 7;
1977 perms
= (groupperms
& mask
& 1) | 6;
1983 * analyze designated users, get mask
1984 * and identify whether we need to check
1985 * the group memberships. The groups are
1986 * not needed when all groups have the
1987 * same permissions as other for the
1994 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
1995 pxace
= &pxdesc
->acl
.ace
[i
];
1996 switch (pxace
->tag
) {
1997 case POSIX_ACL_USER
:
1999 && ((uid_t
)pxace
->id
== scx
->uid
))
2000 userperms
= pxace
->perms
;
2002 case POSIX_ACL_MASK
:
2004 mask
= pxace
->perms
& 7;
2006 case POSIX_ACL_GROUP_OBJ
:
2007 if (((pxace
->perms
& mask
) ^ perms
)
2008 & (request
>> 6) & 7)
2011 case POSIX_ACL_GROUP
:
2013 && (((pxace
->perms
& mask
) ^ perms
)
2014 & (request
>> 6) & 7))
2021 /* designated users */
2023 perms
= (perms
& 07000) + (userperms
& mask
);
2024 else if (!needgroups
)
2028 if (!(~(perms
>> 3) & request
& mask
)
2029 && ((gid
== scx
->gid
)
2030 || groupmember(scx
, scx
->uid
, gid
)))
2036 for (i
=pxdesc
->acccnt
-1; i
>=0 ; i
--) {
2037 pxace
= &pxdesc
->acl
.ace
[i
];
2038 if ((pxace
->tag
== POSIX_ACL_GROUP
)
2039 && groupmember(scx
, scx
->uid
, pxace
->id
)) {
2040 if (!(~pxace
->perms
& request
& mask
))
2041 groupperms
= pxace
->perms
;
2045 if (groupperms
>= 0)
2046 perms
= (perms
& 07000) + (groupperms
& mask
);
2060 * Get permissions to access a file
2061 * Takes into account the relation of user to file (owner, group, ...)
2062 * Do no use as mode of the file
2063 * Do no call if default_permissions is set
2065 * returns -1 if there is a problem
2068 static int ntfs_get_perm(struct SECURITY_CONTEXT
*scx
,
2069 ntfs_inode
* ni
, mode_t request
)
2071 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2072 const struct CACHED_PERMISSIONS
*cached
;
2074 const SID
*usid
; /* owner of file/directory */
2075 const SID
*gsid
; /* group of file/directory */
2080 struct POSIX_SECURITY
*pxdesc
;
2082 if (!scx
->mapping
[MAPUSERS
])
2085 /* check whether available in cache */
2086 cached
= fetch_cache(scx
,ni
);
2090 perm
= access_check_posix(scx
,cached
->pxdesc
,request
,uid
,gid
);
2092 perm
= 0; /* default to no permission */
2093 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2094 != const_cpu_to_le16(0);
2095 securattr
= getsecurityattr(scx
->vol
, ni
);
2097 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2099 gsid
= (const SID
*)&
2100 securattr
[le32_to_cpu(phead
->group
)];
2101 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2103 usid
= ntfs_acl_owner(securattr
);
2104 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2107 perm
= pxdesc
->mode
& 07777;
2110 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2112 usid
= (const SID
*)&
2113 securattr
[le32_to_cpu(phead
->owner
)];
2114 pxdesc
= ntfs_build_permissions_posix(scx
,securattr
,
2117 perm
= pxdesc
->mode
& 07777;
2120 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2121 uid
= find_tenant(scx
, securattr
);
2125 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2128 * Create a security id if there were none
2129 * and upgrade option is selected
2131 if (!test_nino_flag(ni
, v3_Extensions
)
2133 && (scx
->vol
->secure_flags
2134 & (1 << SECURITY_ADDSECURIDS
))) {
2135 upgrade_secur_desc(scx
->vol
,
2138 * fetch owner and group for cacheing
2139 * if there is a securid
2142 if (test_nino_flag(ni
, v3_Extensions
)
2144 enter_cache(scx
, ni
, uid
,
2148 perm
= access_check_posix(scx
,pxdesc
,request
,uid
,gid
);
2164 * returns size or -errno if there is a problem
2165 * if size was too small, no copy is done and errno is not set,
2166 * the caller is expected to issue a new call
2169 int ntfs_get_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2170 const char *name
, char *value
, size_t size
)
2172 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2173 struct POSIX_SECURITY
*pxdesc
;
2174 const struct CACHED_PERMISSIONS
*cached
;
2176 const SID
*usid
; /* owner of file/directory */
2177 const SID
*gsid
; /* group of file/directory */
2183 outsize
= 0; /* default to error */
2184 if (!scx
->mapping
[MAPUSERS
])
2187 /* check whether available in cache */
2188 cached
= fetch_cache(scx
,ni
);
2190 pxdesc
= cached
->pxdesc
;
2192 securattr
= getsecurityattr(scx
->vol
, ni
);
2193 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2194 != const_cpu_to_le16(0);
2197 (const SECURITY_DESCRIPTOR_RELATIVE
*)
2199 gsid
= (const SID
*)&
2200 securattr
[le32_to_cpu(phead
->group
)];
2202 usid
= ntfs_acl_owner(securattr
);
2204 usid
= (const SID
*)&
2205 securattr
[le32_to_cpu(phead
->owner
)];
2207 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2211 * fetch owner and group for cacheing
2215 * Create a security id if there were none
2216 * and upgrade option is selected
2218 if (!test_nino_flag(ni
, v3_Extensions
)
2219 && (scx
->vol
->secure_flags
2220 & (1 << SECURITY_ADDSECURIDS
))) {
2221 upgrade_secur_desc(scx
->vol
,
2225 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2227 if (!(pxdesc
->mode
& 07777)
2228 && ntfs_same_sid(usid
, adminsid
)) {
2229 uid
= find_tenant(scx
,
2232 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2234 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2235 if (pxdesc
->tagsset
& POSIX_ACL_EXTENSIONS
)
2236 enter_cache(scx
, ni
, uid
,
2241 pxdesc
= (struct POSIX_SECURITY
*)NULL
;
2245 if (ntfs_valid_posix(pxdesc
)) {
2246 if (!strcmp(name
,"system.posix_acl_default")) {
2248 & MFT_RECORD_IS_DIRECTORY
)
2249 outsize
= sizeof(struct POSIX_ACL
)
2250 + pxdesc
->defcnt
*sizeof(struct POSIX_ACE
);
2253 * getting default ACL from plain file :
2254 * return EACCES if size > 0 as
2255 * indicated in the man, but return ok
2256 * if size == 0, so that ls does not
2263 outsize
= sizeof(struct POSIX_ACL
);
2265 if (outsize
&& (outsize
<= size
)) {
2266 memcpy(value
,&pxdesc
->acl
,sizeof(struct POSIX_ACL
));
2267 memcpy(&value
[sizeof(struct POSIX_ACL
)],
2268 &pxdesc
->acl
.ace
[pxdesc
->firstdef
],
2269 outsize
-sizeof(struct POSIX_ACL
));
2272 outsize
= sizeof(struct POSIX_ACL
)
2273 + pxdesc
->acccnt
*sizeof(struct POSIX_ACE
);
2274 if (outsize
<= size
)
2275 memcpy(value
,&pxdesc
->acl
,outsize
);
2280 ntfs_log_error("Invalid Posix ACL built\n");
2287 return (outsize
? (int)outsize
: -errno
);
2290 #else /* POSIXACLS */
2294 * Get permissions to access a file
2295 * Takes into account the relation of user to file (owner, group, ...)
2296 * Do no use as mode of the file
2298 * returns -1 if there is a problem
2301 static int ntfs_get_perm(struct SECURITY_CONTEXT
*scx
,
2302 ntfs_inode
*ni
, mode_t request
)
2304 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2305 const struct CACHED_PERMISSIONS
*cached
;
2307 const SID
*usid
; /* owner of file/directory */
2308 const SID
*gsid
; /* group of file/directory */
2314 if (!scx
->mapping
[MAPUSERS
] || (!scx
->uid
&& !(request
& S_IEXEC
)))
2317 /* check whether available in cache */
2318 cached
= fetch_cache(scx
,ni
);
2320 perm
= cached
->mode
;
2324 perm
= 0; /* default to no permission */
2325 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2326 != const_cpu_to_le16(0);
2327 securattr
= getsecurityattr(scx
->vol
, ni
);
2329 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2331 gsid
= (const SID
*)&
2332 securattr
[le32_to_cpu(phead
->group
)];
2333 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2335 usid
= ntfs_acl_owner(securattr
);
2336 perm
= ntfs_build_permissions(securattr
,
2338 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2340 usid
= (const SID
*)&
2341 securattr
[le32_to_cpu(phead
->owner
)];
2342 perm
= ntfs_build_permissions(securattr
,
2344 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2345 uid
= find_tenant(scx
, securattr
);
2349 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2352 * Create a security id if there were none
2353 * and upgrade option is selected
2355 if (!test_nino_flag(ni
, v3_Extensions
)
2357 && (scx
->vol
->secure_flags
2358 & (1 << SECURITY_ADDSECURIDS
))) {
2359 upgrade_secur_desc(scx
->vol
,
2362 * fetch owner and group for cacheing
2363 * if there is a securid
2366 if (test_nino_flag(ni
, v3_Extensions
)
2368 enter_cache(scx
, ni
, uid
,
2379 /* root access and execution */
2385 if (uid
== scx
->uid
)
2389 * avoid checking group membership
2390 * when the requested perms for group
2391 * are the same as perms for other
2393 if ((gid
== scx
->gid
)
2394 || ((((perm
>> 3) ^ perm
)
2395 & (request
>> 6) & 7)
2396 && groupmember(scx
, scx
->uid
, gid
)))
2405 #endif /* POSIXACLS */
2410 * Returns size or -errno if there is a problem
2411 * if size was too small, no copy is done and errno is not set,
2412 * the caller is expected to issue a new call
2415 int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2416 char *value
, size_t size
)
2421 outsize
= 0; /* default to no data and no error */
2422 securattr
= getsecurityattr(scx
->vol
, ni
);
2424 outsize
= ntfs_attr_size(securattr
);
2425 if (outsize
<= size
) {
2426 memcpy(value
,securattr
,outsize
);
2430 return (outsize
? (int)outsize
: -errno
);
2434 * Get owner, group and permissions in an stat structure
2435 * returns permissions, or -1 if there is a problem
2438 int ntfs_get_owner_mode(struct SECURITY_CONTEXT
*scx
,
2439 ntfs_inode
* ni
, struct stat
*stbuf
)
2441 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2443 const SID
*usid
; /* owner of file/directory */
2444 const SID
*gsid
; /* group of file/directory */
2445 const struct CACHED_PERMISSIONS
*cached
;
2449 struct POSIX_SECURITY
*pxdesc
;
2452 if (!scx
->mapping
[MAPUSERS
])
2455 /* check whether available in cache */
2456 cached
= fetch_cache(scx
,ni
);
2459 if (!(scx
->vol
->secure_flags
& (1 << SECURITY_ACL
))
2461 perm
= ntfs_basic_perms(scx
,cached
->pxdesc
);
2464 perm
= cached
->mode
;
2465 stbuf
->st_uid
= cached
->uid
;
2466 stbuf
->st_gid
= cached
->gid
;
2467 stbuf
->st_mode
= (stbuf
->st_mode
& ~07777) + perm
;
2469 perm
= -1; /* default to error */
2470 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
2471 != const_cpu_to_le16(0);
2472 securattr
= getsecurityattr(scx
->vol
, ni
);
2475 (const SECURITY_DESCRIPTOR_RELATIVE
*)
2477 gsid
= (const SID
*)&
2478 securattr
[le32_to_cpu(phead
->group
)];
2480 usid
= ntfs_acl_owner(securattr
);
2482 usid
= (const SID
*)&
2483 securattr
[le32_to_cpu(phead
->owner
)];
2486 pxdesc
= ntfs_build_permissions_posix(
2487 scx
->mapping
, securattr
,
2490 if (!(scx
->vol
->secure_flags
2491 & (1 << SECURITY_ACL
)))
2492 perm
= ntfs_basic_perms(scx
,
2495 perm
= pxdesc
->mode
& 07777;
2499 perm
= ntfs_build_permissions(securattr
,
2503 * fetch owner and group for cacheing
2507 * Create a security id if there were none
2508 * and upgrade option is selected
2510 if (!test_nino_flag(ni
, v3_Extensions
)
2511 && (scx
->vol
->secure_flags
2512 & (1 << SECURITY_ADDSECURIDS
))) {
2513 upgrade_secur_desc(scx
->vol
,
2517 stbuf
->st_uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2519 if (!perm
&& ntfs_same_sid(usid
, adminsid
)) {
2526 stbuf
->st_uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2528 stbuf
->st_gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2530 (stbuf
->st_mode
& ~07777) + perm
;
2532 enter_cache(scx
, ni
, stbuf
->st_uid
,
2533 stbuf
->st_gid
, pxdesc
);
2536 enter_cache(scx
, ni
, stbuf
->st_uid
,
2537 stbuf
->st_gid
, perm
);
2550 * Get the base for a Posix inheritance and
2551 * build an inherited Posix descriptor
2554 static struct POSIX_SECURITY
*inherit_posix(struct SECURITY_CONTEXT
*scx
,
2555 ntfs_inode
*dir_ni
, mode_t mode
, BOOL isdir
)
2557 const struct CACHED_PERMISSIONS
*cached
;
2558 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
2559 struct POSIX_SECURITY
*pxdesc
;
2560 struct POSIX_SECURITY
*pydesc
;
2567 pydesc
= (struct POSIX_SECURITY
*)NULL
;
2568 /* check whether parent directory is available in cache */
2569 cached
= fetch_cache(scx
,dir_ni
);
2573 pxdesc
= cached
->pxdesc
;
2575 if (scx
->vol
->secure_flags
& (1 << SECURITY_ACL
))
2576 pydesc
= ntfs_build_inherited_posix(pxdesc
,
2577 mode
, scx
->umask
, isdir
);
2579 pydesc
= ntfs_build_basic_posix(pxdesc
,
2580 mode
, scx
->umask
, isdir
);
2583 securattr
= getsecurityattr(scx
->vol
, dir_ni
);
2585 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
2587 gsid
= (const SID
*)&
2588 securattr
[le32_to_cpu(phead
->group
)];
2589 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
2591 usid
= ntfs_acl_owner(securattr
);
2592 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2594 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2596 usid
= (const SID
*)&
2597 securattr
[le32_to_cpu(phead
->owner
)];
2598 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
,securattr
,
2600 if (pxdesc
&& ntfs_same_sid(usid
, adminsid
)) {
2601 uid
= find_tenant(scx
, securattr
);
2603 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
2607 * Create a security id if there were none
2608 * and upgrade option is selected
2610 if (!test_nino_flag(dir_ni
, v3_Extensions
)
2611 && (scx
->vol
->secure_flags
2612 & (1 << SECURITY_ADDSECURIDS
))) {
2613 upgrade_secur_desc(scx
->vol
,
2616 * fetch owner and group for cacheing
2617 * if there is a securid
2620 if (test_nino_flag(dir_ni
, v3_Extensions
)) {
2621 enter_cache(scx
, dir_ni
, uid
,
2624 if (scx
->vol
->secure_flags
2625 & (1 << SECURITY_ACL
))
2626 pydesc
= ntfs_build_inherited_posix(
2630 pydesc
= ntfs_build_basic_posix(
2642 * Allocate a security_id for a file being created
2644 * Returns zero if not possible (NTFS v3.x required)
2647 le32
ntfs_alloc_securid(struct SECURITY_CONTEXT
*scx
,
2648 uid_t uid
, gid_t gid
, ntfs_inode
*dir_ni
,
2649 mode_t mode
, BOOL isdir
)
2651 #if !FORCE_FORMAT_v1x
2652 const struct CACHED_SECURID
*cached
;
2653 struct CACHED_SECURID wanted
;
2654 struct POSIX_SECURITY
*pxdesc
;
2664 securid
= const_cpu_to_le32(0);
2666 #if !FORCE_FORMAT_v1x
2668 pxdesc
= inherit_posix(scx
, dir_ni
, mode
, isdir
);
2670 /* check whether target securid is known in cache */
2674 wanted
.dmode
= pxdesc
->mode
& mode
& 07777;
2675 if (isdir
) wanted
.dmode
|= 0x10000;
2676 wanted
.variable
= (void*)pxdesc
;
2677 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
2678 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2679 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2680 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2681 (cache_compare
)compare
);
2682 /* quite simple, if we are lucky */
2684 securid
= cached
->securid
;
2686 /* not in cache : make sure we can create ids */
2688 if (!cached
&& (scx
->vol
->major_ver
>= 3)) {
2689 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2690 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2691 if (!usid
|| !gsid
) {
2692 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2693 (int)uid
, (int)gid
);
2694 usid
= gsid
= adminsid
;
2696 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2699 newattrsz
= ntfs_attr_size(newattr
);
2700 securid
= setsecurityattr(scx
->vol
,
2701 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
2704 /* update cache, for subsequent use */
2705 wanted
.securid
= securid
;
2706 ntfs_enter_cache(scx
->vol
->securid_cache
,
2708 (cache_compare
)compare
);
2713 * could not build new security attribute
2714 * errno set by ntfs_build_descr()
2725 * Apply Posix inheritance to a newly created file
2726 * (for NTFS 1.x only : no securid)
2729 int ntfs_set_inherited_posix(struct SECURITY_CONTEXT
*scx
,
2730 ntfs_inode
*ni
, uid_t uid
, gid_t gid
,
2731 ntfs_inode
*dir_ni
, mode_t mode
)
2733 struct POSIX_SECURITY
*pxdesc
;
2743 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2744 pxdesc
= inherit_posix(scx
, dir_ni
, mode
, isdir
);
2746 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2747 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2748 if (!usid
|| !gsid
) {
2749 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2750 (int)uid
, (int)gid
);
2751 usid
= gsid
= adminsid
;
2753 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2756 /* Adjust Windows read-only flag */
2757 res
= update_secur_descr(scx
->vol
, newattr
, ni
);
2758 if (!res
&& !isdir
) {
2760 ni
->flags
&= ~FILE_ATTR_READONLY
;
2762 ni
->flags
|= FILE_ATTR_READONLY
;
2764 #if CACHE_LEGACY_SIZE
2765 /* also invalidate legacy cache */
2766 if (isdir
&& !ni
->security_id
) {
2767 struct CACHED_PERMISSIONS_LEGACY legacy
;
2769 legacy
.mft_no
= ni
->mft_no
;
2770 legacy
.variable
= pxdesc
;
2771 legacy
.varsize
= sizeof(struct POSIX_SECURITY
)
2772 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2773 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
2775 (cache_compare
)leg_compare
,0);
2782 * could not build new security attribute
2783 * errno set by ntfs_build_descr()
2792 le32
ntfs_alloc_securid(struct SECURITY_CONTEXT
*scx
,
2793 uid_t uid
, gid_t gid
, mode_t mode
, BOOL isdir
)
2795 #if !FORCE_FORMAT_v1x
2796 const struct CACHED_SECURID
*cached
;
2797 struct CACHED_SECURID wanted
;
2807 securid
= const_cpu_to_le32(0);
2809 #if !FORCE_FORMAT_v1x
2810 /* check whether target securid is known in cache */
2814 wanted
.dmode
= mode
& 07777;
2815 if (isdir
) wanted
.dmode
|= 0x10000;
2816 wanted
.variable
= (void*)NULL
;
2818 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2819 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2820 (cache_compare
)compare
);
2821 /* quite simple, if we are lucky */
2823 securid
= cached
->securid
;
2825 /* not in cache : make sure we can create ids */
2827 if (!cached
&& (scx
->vol
->major_ver
>= 3)) {
2828 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2829 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2830 if (!usid
|| !gsid
) {
2831 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2832 (int)uid
, (int)gid
);
2833 usid
= gsid
= adminsid
;
2835 newattr
= ntfs_build_descr(mode
, isdir
, usid
, gsid
);
2837 newattrsz
= ntfs_attr_size(newattr
);
2838 securid
= setsecurityattr(scx
->vol
,
2839 (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
,
2842 /* update cache, for subsequent use */
2843 wanted
.securid
= securid
;
2844 ntfs_enter_cache(scx
->vol
->securid_cache
,
2846 (cache_compare
)compare
);
2851 * could not build new security attribute
2852 * errno set by ntfs_build_descr()
2863 * Update ownership and mode of a file, reusing an existing
2864 * security descriptor when possible
2866 * Returns zero if successful
2870 int ntfs_set_owner_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2871 uid_t uid
, gid_t gid
, mode_t mode
,
2872 struct POSIX_SECURITY
*pxdesc
)
2874 int ntfs_set_owner_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
2875 uid_t uid
, gid_t gid
, mode_t mode
)
2879 const struct CACHED_SECURID
*cached
;
2880 struct CACHED_SECURID wanted
;
2890 /* check whether target securid is known in cache */
2892 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
2895 wanted
.dmode
= mode
& 07777;
2896 if (isdir
) wanted
.dmode
|= 0x10000;
2898 wanted
.variable
= (void*)pxdesc
;
2900 wanted
.varsize
= sizeof(struct POSIX_SECURITY
)
2901 + (pxdesc
->acccnt
+ pxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
2905 wanted
.variable
= (void*)NULL
;
2908 if (test_nino_flag(ni
, v3_Extensions
)) {
2909 cached
= (const struct CACHED_SECURID
*)ntfs_fetch_cache(
2910 scx
->vol
->securid_cache
, GENERIC(&wanted
),
2911 (cache_compare
)compare
);
2912 /* quite simple, if we are lucky */
2914 ni
->security_id
= cached
->securid
;
2916 /* adjust Windows read-only flag */
2919 ni
->flags
&= ~FILE_ATTR_READONLY
;
2921 ni
->flags
|= FILE_ATTR_READONLY
;
2922 NInoFileNameSetDirty(ni
);
2925 } else cached
= (struct CACHED_SECURID
*)NULL
;
2929 * Do not use usid and gsid from former attributes,
2930 * but recompute them to get repeatable results
2931 * which can be kept in cache.
2933 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
],uid
,(SID
*)&defusid
);
2934 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
],gid
,(SID
*)&defgsid
);
2935 if (!usid
|| !gsid
) {
2936 ntfs_log_error("File made owned by an unmapped user/group %d/%d\n",
2938 usid
= gsid
= adminsid
;
2942 newattr
= ntfs_build_descr_posix(scx
->mapping
, pxdesc
,
2945 newattr
= ntfs_build_descr(mode
,
2948 newattr
= ntfs_build_descr(mode
,
2952 res
= update_secur_descr(scx
->vol
, newattr
, ni
);
2954 /* adjust Windows read-only flag */
2957 ni
->flags
&= ~FILE_ATTR_READONLY
;
2959 ni
->flags
|= FILE_ATTR_READONLY
;
2960 NInoFileNameSetDirty(ni
);
2962 /* update cache, for subsequent use */
2963 if (test_nino_flag(ni
, v3_Extensions
)) {
2964 wanted
.securid
= ni
->security_id
;
2965 ntfs_enter_cache(scx
->vol
->securid_cache
,
2967 (cache_compare
)compare
);
2969 #if CACHE_LEGACY_SIZE
2970 /* also invalidate legacy cache */
2971 if (isdir
&& !ni
->security_id
) {
2972 struct CACHED_PERMISSIONS_LEGACY legacy
;
2974 legacy
.mft_no
= ni
->mft_no
;
2976 legacy
.variable
= wanted
.variable
;
2977 legacy
.varsize
= wanted
.varsize
;
2979 legacy
.variable
= (void*)NULL
;
2982 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
2984 (cache_compare
)leg_compare
,0);
2991 * could not build new security attribute
2992 * errno set by ntfs_build_descr()
3001 * Check whether user has ownership rights on a file
3003 * Returns TRUE if allowed
3004 * if not, errno tells why
3007 BOOL
ntfs_allowed_as_owner(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
)
3009 const struct CACHED_PERMISSIONS
*cached
;
3017 processuid
= scx
->uid
;
3018 /* TODO : use CAP_FOWNER process capability */
3020 * Always allow for root
3021 * Also always allow if no mapping has been defined
3023 if (!scx
->mapping
[MAPUSERS
] || !processuid
)
3026 gotowner
= FALSE
; /* default */
3027 /* get the owner, either from cache or from old attribute */
3028 cached
= fetch_cache(scx
, ni
);
3033 oldattr
= getsecurityattr(scx
->vol
, ni
);
3036 usid
= ntfs_acl_owner(oldattr
);
3038 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3040 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
3042 usid
= (const SID
*)&oldattr
3043 [le32_to_cpu(phead
->owner
)];
3045 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],
3051 /* TODO : use CAP_FOWNER process capability */
3053 && (!processuid
|| (processuid
== uid
)))
3067 * Set a new access or default Posix ACL to a file
3068 * (or remove ACL if no input data)
3069 * Validity of input data is checked after merging
3071 * Returns 0, or -1 if there is a problem which errno describes
3074 int ntfs_set_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3075 const char *name
, const char *value
, size_t size
,
3078 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3079 const struct CACHED_PERMISSIONS
*cached
;
3091 struct POSIX_SECURITY
*oldpxdesc
;
3092 struct POSIX_SECURITY
*newpxdesc
;
3094 /* get the current pxsec, either from cache or from old attribute */
3096 deflt
= !strcmp(name
,"system.posix_acl_default");
3098 count
= (size
- sizeof(struct POSIX_ACL
)) / sizeof(struct POSIX_ACE
);
3101 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
3102 newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3104 || (((const struct POSIX_ACL
*)value
)->version
== POSIX_VERSION
))
3105 && (!deflt
|| isdir
|| (!size
&& !value
))) {
3106 cached
= fetch_cache(scx
, ni
);
3110 oldpxdesc
= cached
->pxdesc
;
3112 newpxdesc
= ntfs_replace_acl(oldpxdesc
,
3113 (const struct POSIX_ACL
*)value
,count
,deflt
);
3116 oldattr
= getsecurityattr(scx
->vol
, ni
);
3118 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
3120 usid
= ntfs_acl_owner(oldattr
);
3122 usid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->owner
)];
3124 gsid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->group
)];
3125 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3126 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3127 oldpxdesc
= ntfs_build_permissions_posix(scx
->mapping
,
3128 oldattr
, usid
, gsid
, isdir
);
3131 exist
= oldpxdesc
->defcnt
> 0;
3133 exist
= oldpxdesc
->acccnt
> 3;
3134 if ((exist
&& (flags
& XATTR_CREATE
))
3135 || (!exist
&& (flags
& XATTR_REPLACE
))) {
3136 errno
= (exist
? EEXIST
: ENODATA
);
3138 newpxdesc
= ntfs_replace_acl(oldpxdesc
,
3139 (const struct POSIX_ACL
*)value
,count
,deflt
);
3150 processuid
= scx
->uid
;
3151 /* TODO : use CAP_FOWNER process capability */
3152 if (!processuid
|| (uid
== processuid
)) {
3154 * clear setgid if file group does
3155 * not match process group
3157 if (processuid
&& (gid
!= scx
->gid
)
3158 && !groupmember(scx
, scx
->uid
, gid
)) {
3159 newpxdesc
->mode
&= ~S_ISGID
;
3161 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3162 newpxdesc
->mode
, newpxdesc
);
3167 return (res
? -1 : 0);
3171 * Remove a default Posix ACL from a file
3173 * Returns 0, or -1 if there is a problem which errno describes
3176 int ntfs_remove_posix_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3179 return (ntfs_set_posix_acl(scx
, ni
, name
,
3180 (const char*)NULL
, 0, 0));
3186 * Set a new NTFS ACL to a file
3188 * Returns 0, or -1 if there is a problem
3191 int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3192 const char *value
, size_t size
, int flags
)
3199 && !(flags
& XATTR_CREATE
)
3200 && ntfs_valid_descr(value
,size
)
3201 && (ntfs_attr_size(value
) == size
)) {
3202 /* need copying in order to write */
3203 attr
= (char*)ntfs_malloc(size
);
3205 memcpy(attr
,value
,size
);
3206 res
= update_secur_descr(scx
->vol
, attr
, ni
);
3208 * No need to invalidate standard caches :
3209 * the relation between a securid and
3210 * the associated protection is unchanged,
3211 * only the relation between a file and
3212 * its securid and protection is changed.
3214 #if CACHE_LEGACY_SIZE
3216 * we must however invalidate the legacy
3217 * cache, which is based on inode numbers.
3218 * For safety, invalidate even if updating
3221 if ((ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3222 && !ni
->security_id
) {
3223 struct CACHED_PERMISSIONS_LEGACY legacy
;
3225 legacy
.mft_no
= ni
->mft_no
;
3226 legacy
.variable
= (char*)NULL
;
3228 ntfs_invalidate_cache(scx
->vol
->legacy_cache
,
3230 (cache_compare
)leg_compare
,0);
3238 return (res
? -1 : 0);
3243 * Set new permissions to a file
3244 * Checks user mapping has been defined before request for setting
3246 * rejected if request is not originated by owner or root
3248 * returns 0 on success
3249 * -1 on failure, with errno = EIO
3252 int ntfs_set_mode(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
, mode_t mode
)
3254 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3255 const struct CACHED_PERMISSIONS
*cached
;
3266 const struct POSIX_SECURITY
*oldpxdesc
;
3267 struct POSIX_SECURITY
*newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3270 /* get the current owner, either from cache or from old attribute */
3272 cached
= fetch_cache(scx
, ni
);
3277 oldpxdesc
= cached
->pxdesc
;
3279 /* must copy before merging */
3280 pxsize
= sizeof(struct POSIX_SECURITY
)
3281 + (oldpxdesc
->acccnt
+ oldpxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
3282 newpxdesc
= (struct POSIX_SECURITY
*)malloc(pxsize
);
3284 memcpy(newpxdesc
, oldpxdesc
, pxsize
);
3285 if (ntfs_merge_mode_posix(newpxdesc
, mode
))
3290 newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3293 oldattr
= getsecurityattr(scx
->vol
, ni
);
3295 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
3297 usid
= ntfs_acl_owner(oldattr
);
3299 usid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->owner
)];
3301 gsid
= (const SID
*)&oldattr
[le32_to_cpu(phead
->group
)];
3302 uid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3303 gid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3305 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) != const_cpu_to_le16(0);
3306 newpxdesc
= ntfs_build_permissions_posix(scx
->mapping
,
3307 oldattr
, usid
, gsid
, isdir
);
3308 if (!newpxdesc
|| ntfs_merge_mode_posix(newpxdesc
, mode
))
3317 processuid
= scx
->uid
;
3318 /* TODO : use CAP_FOWNER process capability */
3319 if (!processuid
|| (uid
== processuid
)) {
3321 * clear setgid if file group does
3322 * not match process group
3324 if (processuid
&& (gid
!= scx
->gid
)
3325 && !groupmember(scx
, scx
->uid
, gid
))
3329 newpxdesc
->mode
= mode
;
3330 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3333 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3336 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3340 res
= -1; /* neither owner nor root */
3344 * Should not happen : a default descriptor is generated
3345 * by getsecurityattr() when there are none
3347 ntfs_log_error("File has no security descriptor\n");
3352 if (newpxdesc
) free(newpxdesc
);
3354 return (res
? -1 : 0);
3358 * Create a default security descriptor for files whose descriptor
3359 * cannot be inherited
3362 int ntfs_sd_add_everyone(ntfs_inode
*ni
)
3364 /* JPA SECURITY_DESCRIPTOR_ATTR *sd; */
3365 SECURITY_DESCRIPTOR_RELATIVE
*sd
;
3367 ACCESS_ALLOWED_ACE
*ace
;
3371 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
3373 * Calculate security descriptor length. We have 2 sub-authorities in
3374 * owner and group SIDs, but structure SID contain only one, so add
3375 * 4 bytes to every SID.
3377 sd_len
= sizeof(SECURITY_DESCRIPTOR_ATTR
) + 2 * (sizeof(SID
) + 4) +
3378 sizeof(ACL
) + sizeof(ACCESS_ALLOWED_ACE
);
3379 sd
= (SECURITY_DESCRIPTOR_RELATIVE
*)ntfs_calloc(sd_len
);
3383 sd
->revision
= SECURITY_DESCRIPTOR_REVISION
;
3384 sd
->control
= SE_DACL_PRESENT
| SE_SELF_RELATIVE
;
3386 sid
= (SID
*)((u8
*)sd
+ sizeof(SECURITY_DESCRIPTOR_ATTR
));
3387 sid
->revision
= SID_REVISION
;
3388 sid
->sub_authority_count
= 2;
3389 sid
->sub_authority
[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID
);
3390 sid
->sub_authority
[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS
);
3391 sid
->identifier_authority
.value
[5] = 5;
3392 sd
->owner
= cpu_to_le32((u8
*)sid
- (u8
*)sd
);
3394 sid
= (SID
*)((u8
*)sid
+ sizeof(SID
) + 4);
3395 sid
->revision
= SID_REVISION
;
3396 sid
->sub_authority_count
= 2;
3397 sid
->sub_authority
[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID
);
3398 sid
->sub_authority
[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS
);
3399 sid
->identifier_authority
.value
[5] = 5;
3400 sd
->group
= cpu_to_le32((u8
*)sid
- (u8
*)sd
);
3402 acl
= (ACL
*)((u8
*)sid
+ sizeof(SID
) + 4);
3403 acl
->revision
= ACL_REVISION
;
3404 acl
->size
= const_cpu_to_le16(sizeof(ACL
) + sizeof(ACCESS_ALLOWED_ACE
));
3405 acl
->ace_count
= const_cpu_to_le16(1);
3406 sd
->dacl
= cpu_to_le32((u8
*)acl
- (u8
*)sd
);
3408 ace
= (ACCESS_ALLOWED_ACE
*)((u8
*)acl
+ sizeof(ACL
));
3409 ace
->type
= ACCESS_ALLOWED_ACE_TYPE
;
3410 ace
->flags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
;
3411 ace
->size
= const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE
));
3412 ace
->mask
= const_cpu_to_le32(0x1f01ff); /* FIXME */
3413 ace
->sid
.revision
= SID_REVISION
;
3414 ace
->sid
.sub_authority_count
= 1;
3415 ace
->sid
.sub_authority
[0] = const_cpu_to_le32(0);
3416 ace
->sid
.identifier_authority
.value
[5] = 1;
3418 ret
= ntfs_attr_add(ni
, AT_SECURITY_DESCRIPTOR
, AT_UNNAMED
, 0, (u8
*)sd
,
3421 ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR");
3428 * Check whether user can access a file in a specific way
3430 * Returns 1 if access is allowed, including user is root or no
3431 * user mapping defined
3432 * 2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX
3433 * 0 and sets errno if there is a problem or if access
3436 * This is used for Posix ACL and checking creation of DOS file names
3439 int ntfs_allowed_access(struct SECURITY_CONTEXT
*scx
,
3441 int accesstype
) /* access type required (S_Ixxx values) */
3449 * Always allow for root unless execution is requested.
3450 * (was checked by fuse until kernel 2.6.29)
3451 * Also always allow if no mapping has been defined
3453 if (!scx
->mapping
[MAPUSERS
]
3455 && (!(accesstype
& S_IEXEC
)
3456 || (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
))))
3459 perm
= ntfs_get_perm(scx
, ni
, accesstype
);
3462 switch (accesstype
) {
3464 allow
= (perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0;
3467 allow
= (perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0;
3469 case S_IWRITE
+ S_IEXEC
:
3470 allow
= ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3471 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3474 allow
= (perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0;
3476 case S_IREAD
+ S_IEXEC
:
3477 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3478 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3480 case S_IREAD
+ S_IWRITE
:
3481 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3482 && ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0);
3484 case S_IWRITE
+ S_IEXEC
+ S_ISVTX
:
3485 if (perm
& S_ISVTX
) {
3486 if ((ntfs_get_owner_mode(scx
,ni
,&stbuf
) >= 0)
3487 && (stbuf
.st_uid
== scx
->uid
))
3492 allow
= ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3493 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3495 case S_IREAD
+ S_IWRITE
+ S_IEXEC
:
3496 allow
= ((perm
& (S_IRUSR
| S_IRGRP
| S_IROTH
)) != 0)
3497 && ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3498 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3514 * Check whether user can create a file (or directory)
3516 * Returns TRUE if access is allowed,
3517 * Also returns the gid and dsetgid applicable to the created file
3520 int ntfs_allowed_create(struct SECURITY_CONTEXT
*scx
,
3521 ntfs_inode
*dir_ni
, gid_t
*pgid
, mode_t
*pdsetgid
)
3529 * Always allow for root.
3530 * Also always allow if no mapping has been defined
3532 if (!scx
->mapping
[MAPUSERS
])
3535 perm
= ntfs_get_perm(scx
, dir_ni
, S_IWRITE
+ S_IEXEC
);
3536 if (!scx
->mapping
[MAPUSERS
]
3540 perm
= ntfs_get_perm(scx
, dir_ni
, S_IWRITE
+ S_IEXEC
);
3543 allow
= ((perm
& (S_IWUSR
| S_IWGRP
| S_IWOTH
)) != 0)
3544 && ((perm
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) != 0);
3552 /* return directory group if S_ISGID is set */
3553 if (allow
&& (perm
& S_ISGID
)) {
3554 if (ntfs_get_owner_mode(scx
, dir_ni
, &stbuf
) >= 0) {
3555 *pdsetgid
= stbuf
.st_mode
& S_ISGID
;
3557 *pgid
= stbuf
.st_gid
;
3563 #if 0 /* not needed any more */
3566 * Check whether user can access the parent directory
3567 * of a file in a specific way
3569 * Returns true if access is allowed, including user is root and
3570 * no user mapping defined
3572 * Sets errno if there is a problem or if not allowed
3574 * This is used for Posix ACL and checking creation of DOS file names
3577 BOOL
old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT
*scx
,
3578 const char *path
, int accesstype
)
3588 dirpath
= strdup(path
);
3590 /* the root of file system is seen as a parent of itself */
3591 /* is that correct ? */
3592 name
= strrchr(dirpath
, '/');
3594 dir_ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, dirpath
);
3596 allow
= ntfs_allowed_access(scx
,
3597 dir_ni
, accesstype
);
3598 ntfs_inode_close(dir_ni
);
3600 * for an not-owned sticky directory, have to
3601 * check whether file itself is owned
3603 if ((accesstype
== (S_IWRITE
+ S_IEXEC
+ S_ISVTX
))
3605 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
,
3609 allow
= (ntfs_get_owner_mode(scx
,ni
,&stbuf
) >= 0)
3610 && (stbuf
.st_uid
== scx
->uid
);
3611 ntfs_inode_close(ni
);
3617 return (allow
); /* errno is set if not allowed */
3623 * Define a new owner/group to a file
3625 * returns zero if successful
3628 int ntfs_set_owner(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3629 uid_t uid
, gid_t gid
)
3631 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3632 const struct CACHED_PERMISSIONS
*cached
;
3643 struct POSIX_SECURITY
*pxdesc
;
3644 BOOL pxdescbuilt
= FALSE
;
3648 /* get the current owner and mode from cache or security attributes */
3649 oldattr
= (char*)NULL
;
3650 cached
= fetch_cache(scx
,ni
);
3652 fileuid
= cached
->uid
;
3653 filegid
= cached
->gid
;
3654 mode
= cached
->mode
;
3656 pxdesc
= cached
->pxdesc
;
3664 oldattr
= getsecurityattr(scx
->vol
, ni
);
3666 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3667 != const_cpu_to_le16(0);
3668 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
3671 &oldattr
[le32_to_cpu(phead
->group
)];
3673 usid
= ntfs_acl_owner(oldattr
);
3676 &oldattr
[le32_to_cpu(phead
->owner
)];
3679 pxdesc
= ntfs_build_permissions_posix(scx
->mapping
, oldattr
,
3683 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3684 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3685 mode
= perm
= pxdesc
->mode
;
3689 mode
= perm
= ntfs_build_permissions(oldattr
,
3692 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3693 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3702 /* check requested by root */
3703 /* or chgrp requested by owner to an owned group */
3705 || ((((int)uid
< 0) || (uid
== fileuid
))
3706 && ((gid
== scx
->gid
) || groupmember(scx
, scx
->uid
, gid
))
3707 && (fileuid
== scx
->uid
))) {
3708 /* replace by the new usid and gsid */
3709 /* or reuse old gid and sid for cacheing */
3714 #if !defined(__sun) || !defined (__SVR4)
3715 /* clear setuid and setgid if owner has changed */
3716 /* unless request originated by root */
3717 if (uid
&& (fileuid
!= uid
))
3721 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3724 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3727 res
= -1; /* neither owner nor root */
3736 * Should not happen : a default descriptor is generated
3737 * by getsecurityattr() when there are none
3739 ntfs_log_error("File has no security descriptor\n");
3743 return (res
? -1 : 0);
3747 * Define new owner/group and mode to a file
3749 * returns zero if successful
3752 int ntfs_set_ownmod(struct SECURITY_CONTEXT
*scx
, ntfs_inode
*ni
,
3753 uid_t uid
, gid_t gid
, const mode_t mode
)
3755 const struct CACHED_PERMISSIONS
*cached
;
3761 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
3765 const struct POSIX_SECURITY
*oldpxdesc
;
3766 struct POSIX_SECURITY
*newpxdesc
= (struct POSIX_SECURITY
*)NULL
;
3771 /* get the current owner and mode from cache or security attributes */
3772 oldattr
= (char*)NULL
;
3773 cached
= fetch_cache(scx
,ni
);
3775 fileuid
= cached
->uid
;
3776 filegid
= cached
->gid
;
3778 oldpxdesc
= cached
->pxdesc
;
3780 /* must copy before merging */
3781 pxsize
= sizeof(struct POSIX_SECURITY
)
3782 + (oldpxdesc
->acccnt
+ oldpxdesc
->defcnt
)*sizeof(struct POSIX_ACE
);
3783 newpxdesc
= (struct POSIX_SECURITY
*)malloc(pxsize
);
3785 memcpy(newpxdesc
, oldpxdesc
, pxsize
);
3786 if (ntfs_merge_mode_posix(newpxdesc
, mode
))
3795 oldattr
= getsecurityattr(scx
->vol
, ni
);
3798 isdir
= (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
3799 != const_cpu_to_le16(0);
3800 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)
3803 &oldattr
[le32_to_cpu(phead
->group
)];
3805 usid
= ntfs_acl_owner(oldattr
);
3808 &oldattr
[le32_to_cpu(phead
->owner
)];
3810 newpxdesc
= ntfs_build_permissions_posix(scx
->mapping
, oldattr
,
3812 if (!newpxdesc
|| ntfs_merge_mode_posix(newpxdesc
, mode
))
3815 fileuid
= ntfs_find_user(scx
->mapping
[MAPUSERS
],usid
);
3816 filegid
= ntfs_find_group(scx
->mapping
[MAPGROUPS
],gsid
);
3824 /* check requested by root */
3825 /* or chgrp requested by owner to an owned group */
3827 || ((((int)uid
< 0) || (uid
== fileuid
))
3828 && ((gid
== scx
->gid
) || groupmember(scx
, scx
->uid
, gid
))
3829 && (fileuid
== scx
->uid
))) {
3830 /* replace by the new usid and gsid */
3831 /* or reuse old gid and sid for cacheing */
3837 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
,
3840 res
= ntfs_set_owner_mode(scx
, ni
, uid
, gid
, mode
);
3843 res
= -1; /* neither owner nor root */
3848 * Should not happen : a default descriptor is generated
3849 * by getsecurityattr() when there are none
3851 ntfs_log_error("File has no security descriptor\n");
3858 return (res
? -1 : 0);
3862 * Build a security id for a descriptor inherited from
3863 * parent directory the Windows way
3866 static le32
build_inherited_id(struct SECURITY_CONTEXT
*scx
,
3867 const char *parentattr
, BOOL fordir
)
3869 const SECURITY_DESCRIPTOR_RELATIVE
*pphead
;
3877 SECURITY_DESCRIPTOR_RELATIVE
*pnhead
;
3888 parentattrsz
= ntfs_attr_size(parentattr
);
3889 pphead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)parentattr
;
3890 if (scx
->mapping
[MAPUSERS
]) {
3891 usid
= ntfs_find_usid(scx
->mapping
[MAPUSERS
], scx
->uid
, (SID
*)&defusid
);
3892 gsid
= ntfs_find_gsid(scx
->mapping
[MAPGROUPS
], scx
->gid
, (SID
*)&defgsid
);
3894 /* Get approximation of parent owner when cannot map */
3898 usid
= ntfs_acl_owner(parentattr
);
3899 if (!ntfs_is_user_sid(gsid
))
3903 /* Define owner as root when cannot map */
3911 * If there is no user mapping and this is not a root
3912 * user, we have to get owner and group from somewhere,
3913 * and the parent directory has to contribute.
3914 * Windows never has to do that, because it can always
3915 * rely on a user mapping
3921 usid
= ntfs_acl_owner(parentattr
);
3925 offowner
= le32_to_cpu(pphead
->owner
);
3926 usid
= (const SID
*)&parentattr
[offowner
];
3932 offgroup
= le32_to_cpu(pphead
->group
);
3933 gsid
= (const SID
*)&parentattr
[offgroup
];
3937 * new attribute is smaller than parent's
3938 * except for differences in SIDs which appear in
3939 * owner, group and possible grants and denials in
3940 * generic creator-owner and creator-group ACEs.
3941 * For directories, an ACE may be duplicated for
3942 * access and inheritance, so we double the count.
3944 usidsz
= ntfs_sid_size(usid
);
3945 gsidsz
= ntfs_sid_size(gsid
);
3946 newattrsz
= parentattrsz
+ 3*usidsz
+ 3*gsidsz
;
3949 newattr
= (char*)ntfs_malloc(newattrsz
);
3951 pnhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)newattr
;
3952 pnhead
->revision
= SECURITY_DESCRIPTOR_REVISION
;
3953 pnhead
->alignment
= 0;
3954 pnhead
->control
= (pphead
->control
3955 & (SE_DACL_AUTO_INHERITED
| SE_SACL_AUTO_INHERITED
))
3957 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
3959 * locate and inherit DACL
3960 * do not test SE_DACL_PRESENT (wrong for "DR Watson")
3962 pnhead
->dacl
= const_cpu_to_le32(0);
3964 offpacl
= le32_to_cpu(pphead
->dacl
);
3965 ppacl
= (const ACL
*)&parentattr
[offpacl
];
3966 pnacl
= (ACL
*)&newattr
[pos
];
3967 aclsz
= ntfs_inherit_acl(ppacl
, pnacl
, usid
, gsid
,
3968 fordir
, pphead
->control
3969 & SE_DACL_AUTO_INHERITED
);
3971 pnhead
->dacl
= cpu_to_le32(pos
);
3973 pnhead
->control
|= SE_DACL_PRESENT
;
3977 * locate and inherit SACL
3979 pnhead
->sacl
= const_cpu_to_le32(0);
3981 offpacl
= le32_to_cpu(pphead
->sacl
);
3982 ppacl
= (const ACL
*)&parentattr
[offpacl
];
3983 pnacl
= (ACL
*)&newattr
[pos
];
3984 aclsz
= ntfs_inherit_acl(ppacl
, pnacl
, usid
, gsid
,
3985 fordir
, pphead
->control
3986 & SE_SACL_AUTO_INHERITED
);
3988 pnhead
->sacl
= cpu_to_le32(pos
);
3990 pnhead
->control
|= SE_SACL_PRESENT
;
3994 * inherit or redefine owner
3996 memcpy(&newattr
[pos
],usid
,usidsz
);
3997 pnhead
->owner
= cpu_to_le32(pos
);
4000 * inherit or redefine group
4002 memcpy(&newattr
[pos
],gsid
,gsidsz
);
4003 pnhead
->group
= cpu_to_le32(pos
);
4005 securid
= setsecurityattr(scx
->vol
,
4006 (SECURITY_DESCRIPTOR_RELATIVE
*)newattr
, pos
);
4009 securid
= const_cpu_to_le32(0);
4014 * Get an inherited security id
4016 * For Windows compatibility, the normal initial permission setting
4017 * may be inherited from the parent directory instead of being
4018 * defined by the creation arguments.
4020 * The following creates an inherited id for that purpose.
4022 * Note : the owner and group of parent directory are also
4023 * inherited (which is not the case on Windows) if no user mapping
4026 * Returns the inherited id, or zero if not possible (eg on NTFS 1.x)
4029 le32
ntfs_inherited_id(struct SECURITY_CONTEXT
*scx
,
4030 ntfs_inode
*dir_ni
, BOOL fordir
)
4032 struct CACHED_PERMISSIONS
*cached
;
4036 securid
= const_cpu_to_le32(0);
4037 cached
= (struct CACHED_PERMISSIONS
*)NULL
;
4039 * Try to get inherited id from cache, possible when
4040 * the current process owns the parent directory
4042 if (test_nino_flag(dir_ni
, v3_Extensions
)
4043 && dir_ni
->security_id
) {
4044 cached
= fetch_cache(scx
, dir_ni
);
4046 && (cached
->uid
== scx
->uid
) && (cached
->gid
== scx
->gid
))
4047 securid
= (fordir
? cached
->inh_dirid
4048 : cached
->inh_fileid
);
4051 * Not cached or not available in cache, compute it all
4052 * Note : if parent directory has no id, it is not cacheable
4055 parentattr
= getsecurityattr(scx
->vol
, dir_ni
);
4057 securid
= build_inherited_id(scx
,
4058 parentattr
, fordir
);
4061 * Store the result into cache for further use
4062 * if the current process owns the parent directory
4065 cached
= fetch_cache(scx
, dir_ni
);
4067 && (cached
->uid
== scx
->uid
)
4068 && (cached
->gid
== scx
->gid
)) {
4070 cached
->inh_dirid
= securid
;
4072 cached
->inh_fileid
= securid
;
4081 * Link a group to a member of group
4083 * Returns 0 if OK, -1 (and errno set) if error
4086 static int link_single_group(struct MAPPING
*usermapping
, struct passwd
*user
,
4089 struct group
*group
;
4096 group
= getgrgid(gid
);
4097 if (group
&& group
->gr_mem
) {
4098 grcnt
= usermapping
->grcnt
;
4099 groups
= usermapping
->groups
;
4100 grmem
= group
->gr_mem
;
4101 while (*grmem
&& strcmp(user
->pw_name
, *grmem
))
4105 groups
= (gid_t
*)malloc(sizeof(gid_t
));
4107 groups
= (gid_t
*)realloc(groups
,
4108 (grcnt
+1)*sizeof(gid_t
));
4110 groups
[grcnt
++] = gid
;
4116 usermapping
->grcnt
= grcnt
;
4117 usermapping
->groups
= groups
;
4124 * Statically link group to users
4125 * This is based on groups defined in /etc/group and does not take
4126 * the groups dynamically set by setgroups() nor any changes in
4127 * /etc/group into account
4129 * Only mapped groups and root group are linked to mapped users
4131 * Returns 0 if OK, -1 (and errno set) if error
4135 static int link_group_members(struct SECURITY_CONTEXT
*scx
)
4137 struct MAPPING
*usermapping
;
4138 struct MAPPING
*groupmapping
;
4139 struct passwd
*user
;
4143 for (usermapping
=scx
->mapping
[MAPUSERS
]; usermapping
&& !res
;
4144 usermapping
=usermapping
->next
) {
4145 usermapping
->grcnt
= 0;
4146 usermapping
->groups
= (gid_t
*)NULL
;
4147 user
= getpwuid(usermapping
->xid
);
4148 if (user
&& user
->pw_name
) {
4149 for (groupmapping
=scx
->mapping
[MAPGROUPS
];
4150 groupmapping
&& !res
;
4151 groupmapping
=groupmapping
->next
) {
4152 if (link_single_group(usermapping
, user
,
4156 if (!res
&& link_single_group(usermapping
,
4165 * Apply default single user mapping
4166 * returns zero if successful
4169 static int ntfs_do_default_mapping(struct SECURITY_CONTEXT
*scx
,
4170 uid_t uid
, gid_t gid
, const SID
*usid
)
4172 struct MAPPING
*usermapping
;
4173 struct MAPPING
*groupmapping
;
4179 sidsz
= ntfs_sid_size(usid
);
4180 sid
= (SID
*)ntfs_malloc(sidsz
);
4182 memcpy(sid
,usid
,sidsz
);
4183 usermapping
= (struct MAPPING
*)ntfs_malloc(sizeof(struct MAPPING
));
4185 groupmapping
= (struct MAPPING
*)ntfs_malloc(sizeof(struct MAPPING
));
4187 usermapping
->sid
= sid
;
4188 usermapping
->xid
= uid
;
4189 usermapping
->next
= (struct MAPPING
*)NULL
;
4190 groupmapping
->sid
= sid
;
4191 groupmapping
->xid
= gid
;
4192 groupmapping
->next
= (struct MAPPING
*)NULL
;
4193 scx
->mapping
[MAPUSERS
] = usermapping
;
4194 scx
->mapping
[MAPGROUPS
] = groupmapping
;
4203 * Make sure there are no ambiguous mapping
4204 * Ambiguous mapping may lead to undesired configurations and
4205 * we had rather be safe until the consequences are understood
4208 #if 0 /* not activated for now */
4210 static BOOL
check_mapping(const struct MAPPING
*usermapping
,
4211 const struct MAPPING
*groupmapping
)
4213 const struct MAPPING
*mapping1
;
4214 const struct MAPPING
*mapping2
;
4218 for (mapping1
=usermapping
; mapping1
; mapping1
=mapping1
->next
)
4219 for (mapping2
=mapping1
->next
; mapping2
; mapping1
=mapping2
->next
)
4220 if (ntfs_same_sid(mapping1
->sid
,mapping2
->sid
)) {
4221 if (mapping1
->xid
!= mapping2
->xid
)
4224 if (mapping1
->xid
== mapping2
->xid
)
4227 for (mapping1
=groupmapping
; mapping1
; mapping1
=mapping1
->next
)
4228 for (mapping2
=mapping1
->next
; mapping2
; mapping1
=mapping2
->next
)
4229 if (ntfs_same_sid(mapping1
->sid
,mapping2
->sid
)) {
4230 if (mapping1
->xid
!= mapping2
->xid
)
4233 if (mapping1
->xid
== mapping2
->xid
)
4241 #if 0 /* not used any more */
4244 * Try and apply default single user mapping
4245 * returns zero if successful
4248 static int ntfs_default_mapping(struct SECURITY_CONTEXT
*scx
)
4250 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4257 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, "/.");
4259 securattr
= getsecurityattr(scx
->vol
, ni
);
4261 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)securattr
;
4262 usid
= (SID
*)&securattr
[le32_to_cpu(phead
->owner
)];
4263 if (ntfs_is_user_sid(usid
))
4264 res
= ntfs_do_default_mapping(scx
,
4265 scx
->uid
, scx
->gid
, usid
);
4268 ntfs_inode_close(ni
);
4276 * Basic read from a user mapping file on another volume
4279 static int basicread(void *fileid
, char *buf
, size_t size
, off_t offs
__attribute__((unused
)))
4281 return (read(*(int*)fileid
, buf
, size
));
4286 * Read from a user mapping file on current NTFS partition
4289 static int localread(void *fileid
, char *buf
, size_t size
, off_t offs
)
4291 return (ntfs_attr_data_read((ntfs_inode
*)fileid
,
4292 AT_UNNAMED
, 0, buf
, size
, offs
));
4296 * Build the user mapping
4297 * - according to a mapping file if defined (or default present),
4298 * - or try default single user mapping if possible
4300 * The mapping is specific to a mounted device
4301 * No locking done, mounting assumed non multithreaded
4303 * returns zero if mapping is successful
4304 * (failure should not be interpreted as an error)
4307 int ntfs_build_mapping(struct SECURITY_CONTEXT
*scx
, const char *usermap_path
,
4310 struct MAPLIST
*item
;
4311 struct MAPLIST
*firstitem
;
4312 struct MAPPING
*usermapping
;
4313 struct MAPPING
*groupmapping
;
4327 1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5),
4328 const_cpu_to_le32(21),
4329 const_cpu_to_le32(DEFSECAUTH1
), const_cpu_to_le32(DEFSECAUTH2
),
4330 const_cpu_to_le32(DEFSECAUTH3
), const_cpu_to_le32(DEFSECBASE
)
4333 /* be sure not to map anything until done */
4334 scx
->mapping
[MAPUSERS
] = (struct MAPPING
*)NULL
;
4335 scx
->mapping
[MAPGROUPS
] = (struct MAPPING
*)NULL
;
4337 if (!usermap_path
) usermap_path
= MAPPINGFILE
;
4338 if (usermap_path
[0] == '/') {
4339 fd
= open(usermap_path
,O_RDONLY
);
4341 firstitem
= ntfs_read_mapping(basicread
, (void*)&fd
);
4344 firstitem
= (struct MAPLIST
*)NULL
;
4346 ni
= ntfs_pathname_to_inode(scx
->vol
, NULL
, usermap_path
);
4348 firstitem
= ntfs_read_mapping(localread
, ni
);
4349 ntfs_inode_close(ni
);
4351 firstitem
= (struct MAPLIST
*)NULL
;
4356 usermapping
= ntfs_do_user_mapping(firstitem
);
4357 groupmapping
= ntfs_do_group_mapping(firstitem
);
4358 if (usermapping
&& groupmapping
) {
4359 scx
->mapping
[MAPUSERS
] = usermapping
;
4360 scx
->mapping
[MAPGROUPS
] = groupmapping
;
4362 ntfs_log_error("There were no valid user or no valid group\n");
4363 /* now we can free the memory copy of input text */
4364 /* and rely on internal representation */
4366 item
= firstitem
->next
;
4371 /* no mapping file, try a default mapping */
4373 if (!ntfs_do_default_mapping(scx
,
4374 0, 0, (const SID
*)&defmap
))
4375 ntfs_log_info("Using default user mapping\n");
4378 return (!scx
->mapping
[MAPUSERS
] || link_group_members(scx
));
4383 * Get the ntfs attribute into an extended attribute
4384 * The attribute is returned according to cpu endianness
4387 int ntfs_get_ntfs_attrib(ntfs_inode
*ni
, char *value
, size_t size
)
4392 outsize
= 0; /* default to no data and no error */
4394 attrib
= le32_to_cpu(ni
->flags
);
4395 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
4396 attrib
|= const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4398 attrib
&= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
4400 attrib
|= const_le32_to_cpu(FILE_ATTR_NORMAL
);
4401 outsize
= sizeof(FILE_ATTR_FLAGS
);
4402 if (size
>= outsize
) {
4404 memcpy(value
,&attrib
,outsize
);
4409 return (outsize
? (int)outsize
: -errno
);
4413 * Return the ntfs attribute into an extended attribute
4414 * The attribute is expected according to cpu endianness
4416 * Returns 0, or -1 if there is a problem
4419 int ntfs_set_ntfs_attrib(ntfs_inode
*ni
,
4420 const char *value
, size_t size
, int flags
)
4424 ATTR_FLAGS dirflags
;
4428 if (ni
&& value
&& (size
>= sizeof(FILE_ATTR_FLAGS
))) {
4429 if (!(flags
& XATTR_CREATE
)) {
4430 /* copy to avoid alignment problems */
4431 memcpy(&attrib
,value
,sizeof(FILE_ATTR_FLAGS
));
4432 settable
= FILE_ATTR_SETTABLE
;
4434 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
4436 * Accept changing compression for a directory
4437 * and set index root accordingly
4439 settable
|= FILE_ATTR_COMPRESSED
;
4440 if ((ni
->flags
^ cpu_to_le32(attrib
))
4441 & FILE_ATTR_COMPRESSED
) {
4442 if (ni
->flags
& FILE_ATTR_COMPRESSED
)
4443 dirflags
= const_cpu_to_le16(0);
4445 dirflags
= ATTR_IS_COMPRESSED
;
4446 res
= ntfs_attr_set_flags(ni
,
4450 ATTR_COMPRESSION_MASK
);
4454 ni
->flags
= (ni
->flags
& ~settable
)
4455 | (cpu_to_le32(attrib
) & settable
);
4456 NInoFileNameSetDirty(ni
);
4463 return (res
? -1 : 0);
4468 * Open the volume's security descriptor index ($Secure)
4470 * returns 0 if it succeeds
4471 * -1 with errno set if it fails and the volume is NTFS v3.0+
4473 int ntfs_open_secure(ntfs_volume
*vol
)
4476 ntfs_index_context
*sii
;
4477 ntfs_index_context
*sdh
;
4479 if (vol
->secure_ni
) /* Already open? */
4482 ni
= ntfs_pathname_to_inode(vol
, NULL
, "$Secure");
4486 if (ni
->mft_no
!= FILE_Secure
) {
4487 ntfs_log_error("$Secure does not have expected inode number!");
4492 /* Allocate the needed index contexts. */
4493 sii
= ntfs_index_ctx_get(ni
, sii_stream
, 4);
4497 sdh
= ntfs_index_ctx_get(ni
, sdh_stream
, 4);
4501 vol
->secure_xsdh
= sdh
;
4502 vol
->secure_xsii
= sii
;
4503 vol
->secure_ni
= ni
;
4507 ntfs_index_ctx_put(sii
);
4509 ntfs_inode_close(ni
);
4511 /* Failing on NTFS pre-v3.0 is expected. */
4512 if (vol
->major_ver
< 3)
4514 ntfs_log_perror("Failed to open $Secure");
4519 * Close the volume's security descriptor index ($Secure)
4521 * returns 0 if it succeeds
4522 * -1 with errno set if it fails
4524 int ntfs_close_secure(ntfs_volume
*vol
)
4528 if (vol
->secure_ni
) {
4529 ntfs_index_ctx_put(vol
->secure_xsdh
);
4530 ntfs_index_ctx_put(vol
->secure_xsii
);
4531 res
= ntfs_inode_close(vol
->secure_ni
);
4532 vol
->secure_ni
= NULL
;
4538 * Destroy a security context
4539 * Allocated memory is freed to facilitate the detection of memory leaks
4541 void ntfs_destroy_security_context(struct SECURITY_CONTEXT
*scx
)
4543 ntfs_free_mapping(scx
->mapping
);
4548 * API for direct access to security descriptors
4549 * based on Win32 API
4554 * Selective feeding of a security descriptor into user buffer
4556 * Returns TRUE if successful
4559 static BOOL
feedsecurityattr(const char *attr
, u32 selection
,
4560 char *buf
, u32 buflen
, u32
*psize
)
4562 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4563 SECURITY_DESCRIPTOR_RELATIVE
*pnhead
;
4568 unsigned int offdacl
;
4569 unsigned int offsacl
;
4570 unsigned int offowner
;
4571 unsigned int offgroup
;
4572 unsigned int daclsz
;
4573 unsigned int saclsz
;
4574 unsigned int usidsz
;
4575 unsigned int gsidsz
;
4576 unsigned int size
; /* size of requested attributes */
4583 control
= SE_SELF_RELATIVE
;
4584 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
;
4585 size
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4587 /* locate DACL if requested and available */
4588 if (phead
->dacl
&& (selection
& DACL_SECURITY_INFORMATION
)) {
4589 offdacl
= le32_to_cpu(phead
->dacl
);
4590 pdacl
= (const ACL
*)&attr
[offdacl
];
4591 daclsz
= le16_to_cpu(pdacl
->size
);
4593 avail
|= DACL_SECURITY_INFORMATION
;
4595 offdacl
= daclsz
= 0;
4597 /* locate owner if requested and available */
4598 offowner
= le32_to_cpu(phead
->owner
);
4599 if (offowner
&& (selection
& OWNER_SECURITY_INFORMATION
)) {
4600 /* find end of USID */
4601 pusid
= (const SID
*)&attr
[offowner
];
4602 usidsz
= ntfs_sid_size(pusid
);
4604 avail
|= OWNER_SECURITY_INFORMATION
;
4606 offowner
= usidsz
= 0;
4608 /* locate group if requested and available */
4609 offgroup
= le32_to_cpu(phead
->group
);
4610 if (offgroup
&& (selection
& GROUP_SECURITY_INFORMATION
)) {
4611 /* find end of GSID */
4612 pgsid
= (const SID
*)&attr
[offgroup
];
4613 gsidsz
= ntfs_sid_size(pgsid
);
4615 avail
|= GROUP_SECURITY_INFORMATION
;
4617 offgroup
= gsidsz
= 0;
4619 /* locate SACL if requested and available */
4620 if (phead
->sacl
&& (selection
& SACL_SECURITY_INFORMATION
)) {
4621 /* find end of SACL */
4622 offsacl
= le32_to_cpu(phead
->sacl
);
4623 psacl
= (const ACL
*)&attr
[offsacl
];
4624 saclsz
= le16_to_cpu(psacl
->size
);
4626 avail
|= SACL_SECURITY_INFORMATION
;
4628 offsacl
= saclsz
= 0;
4631 * Check having enough size in destination buffer
4632 * (required size is returned nevertheless so that
4633 * the request can be reissued with adequate size)
4635 if (size
> buflen
) {
4640 if (selection
& OWNER_SECURITY_INFORMATION
)
4641 control
|= phead
->control
& SE_OWNER_DEFAULTED
;
4642 if (selection
& GROUP_SECURITY_INFORMATION
)
4643 control
|= phead
->control
& SE_GROUP_DEFAULTED
;
4644 if (selection
& DACL_SECURITY_INFORMATION
)
4645 control
|= phead
->control
4648 | SE_DACL_AUTO_INHERITED
4649 | SE_DACL_PROTECTED
);
4650 if (selection
& SACL_SECURITY_INFORMATION
)
4651 control
|= phead
->control
4654 | SE_SACL_AUTO_INHERITED
4655 | SE_SACL_PROTECTED
);
4657 * copy header and feed new flags, even if no detailed data
4659 memcpy(buf
,attr
,sizeof(SECURITY_DESCRIPTOR_RELATIVE
));
4660 pnhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)buf
;
4661 pnhead
->control
= control
;
4662 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4664 /* copy DACL if requested and available */
4665 if (selection
& avail
& DACL_SECURITY_INFORMATION
) {
4666 pnhead
->dacl
= cpu_to_le32(pos
);
4667 memcpy(&buf
[pos
],&attr
[offdacl
],daclsz
);
4670 pnhead
->dacl
= const_cpu_to_le32(0);
4672 /* copy SACL if requested and available */
4673 if (selection
& avail
& SACL_SECURITY_INFORMATION
) {
4674 pnhead
->sacl
= cpu_to_le32(pos
);
4675 memcpy(&buf
[pos
],&attr
[offsacl
],saclsz
);
4678 pnhead
->sacl
= const_cpu_to_le32(0);
4680 /* copy owner if requested and available */
4681 if (selection
& avail
& OWNER_SECURITY_INFORMATION
) {
4682 pnhead
->owner
= cpu_to_le32(pos
);
4683 memcpy(&buf
[pos
],&attr
[offowner
],usidsz
);
4686 pnhead
->owner
= const_cpu_to_le32(0);
4688 /* copy group if requested and available */
4689 if (selection
& avail
& GROUP_SECURITY_INFORMATION
) {
4690 pnhead
->group
= cpu_to_le32(pos
);
4691 memcpy(&buf
[pos
],&attr
[offgroup
],gsidsz
);
4694 pnhead
->group
= const_cpu_to_le32(0);
4696 ntfs_log_error("Error in security descriptor size\n");
4705 * Merge a new security descriptor into the old one
4706 * and assign to designated file
4708 * Returns TRUE if successful
4711 static BOOL
mergesecurityattr(ntfs_volume
*vol
, const char *oldattr
,
4712 const char *newattr
, u32 selection
, ntfs_inode
*ni
)
4714 const SECURITY_DESCRIPTOR_RELATIVE
*oldhead
;
4715 const SECURITY_DESCRIPTOR_RELATIVE
*newhead
;
4716 SECURITY_DESCRIPTOR_RELATIVE
*targhead
;
4733 ok
= FALSE
; /* default return */
4734 oldhead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)oldattr
;
4735 newhead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)newattr
;
4736 oldattrsz
= ntfs_attr_size(oldattr
);
4737 newattrsz
= ntfs_attr_size(newattr
);
4738 target
= (char*)ntfs_malloc(oldattrsz
+ newattrsz
);
4740 targhead
= (SECURITY_DESCRIPTOR_RELATIVE
*)target
;
4741 pos
= sizeof(SECURITY_DESCRIPTOR_RELATIVE
);
4742 control
= SE_SELF_RELATIVE
;
4744 * copy new DACL if selected
4745 * or keep old DACL if any
4747 if ((selection
& DACL_SECURITY_INFORMATION
) ?
4748 newhead
->dacl
: oldhead
->dacl
) {
4749 if (selection
& DACL_SECURITY_INFORMATION
) {
4750 offdacl
= le32_to_cpu(newhead
->dacl
);
4751 pdacl
= (const ACL
*)&newattr
[offdacl
];
4753 offdacl
= le32_to_cpu(oldhead
->dacl
);
4754 pdacl
= (const ACL
*)&oldattr
[offdacl
];
4756 size
= le16_to_cpu(pdacl
->size
);
4757 memcpy(&target
[pos
], pdacl
, size
);
4758 targhead
->dacl
= cpu_to_le32(pos
);
4761 targhead
->dacl
= const_cpu_to_le32(0);
4762 if (selection
& DACL_SECURITY_INFORMATION
) {
4763 control
|= newhead
->control
4766 | SE_DACL_PROTECTED
);
4767 if (newhead
->control
& SE_DACL_AUTO_INHERIT_REQ
)
4768 control
|= SE_DACL_AUTO_INHERITED
;
4770 control
|= oldhead
->control
4773 | SE_DACL_AUTO_INHERITED
4774 | SE_DACL_PROTECTED
);
4776 * copy new SACL if selected
4777 * or keep old SACL if any
4779 if ((selection
& SACL_SECURITY_INFORMATION
) ?
4780 newhead
->sacl
: oldhead
->sacl
) {
4781 if (selection
& SACL_SECURITY_INFORMATION
) {
4782 offsacl
= le32_to_cpu(newhead
->sacl
);
4783 psacl
= (const ACL
*)&newattr
[offsacl
];
4785 offsacl
= le32_to_cpu(oldhead
->sacl
);
4786 psacl
= (const ACL
*)&oldattr
[offsacl
];
4788 size
= le16_to_cpu(psacl
->size
);
4789 memcpy(&target
[pos
], psacl
, size
);
4790 targhead
->sacl
= cpu_to_le32(pos
);
4793 targhead
->sacl
= const_cpu_to_le32(0);
4794 if (selection
& SACL_SECURITY_INFORMATION
) {
4795 control
|= newhead
->control
4798 | SE_SACL_PROTECTED
);
4799 if (newhead
->control
& SE_SACL_AUTO_INHERIT_REQ
)
4800 control
|= SE_SACL_AUTO_INHERITED
;
4802 control
|= oldhead
->control
4805 | SE_SACL_AUTO_INHERITED
4806 | SE_SACL_PROTECTED
);
4808 * copy new OWNER if selected
4809 * or keep old OWNER if any
4811 if ((selection
& OWNER_SECURITY_INFORMATION
) ?
4812 newhead
->owner
: oldhead
->owner
) {
4813 if (selection
& OWNER_SECURITY_INFORMATION
) {
4814 offowner
= le32_to_cpu(newhead
->owner
);
4815 powner
= (const SID
*)&newattr
[offowner
];
4817 offowner
= le32_to_cpu(oldhead
->owner
);
4818 powner
= (const SID
*)&oldattr
[offowner
];
4820 size
= ntfs_sid_size(powner
);
4821 memcpy(&target
[pos
], powner
, size
);
4822 targhead
->owner
= cpu_to_le32(pos
);
4825 targhead
->owner
= const_cpu_to_le32(0);
4826 if (selection
& OWNER_SECURITY_INFORMATION
)
4827 control
|= newhead
->control
& SE_OWNER_DEFAULTED
;
4829 control
|= oldhead
->control
& SE_OWNER_DEFAULTED
;
4831 * copy new GROUP if selected
4832 * or keep old GROUP if any
4834 if ((selection
& GROUP_SECURITY_INFORMATION
) ?
4835 newhead
->group
: oldhead
->group
) {
4836 if (selection
& GROUP_SECURITY_INFORMATION
) {
4837 offgroup
= le32_to_cpu(newhead
->group
);
4838 pgroup
= (const SID
*)&newattr
[offgroup
];
4839 control
|= newhead
->control
4840 & SE_GROUP_DEFAULTED
;
4842 offgroup
= le32_to_cpu(oldhead
->group
);
4843 pgroup
= (const SID
*)&oldattr
[offgroup
];
4844 control
|= oldhead
->control
4845 & SE_GROUP_DEFAULTED
;
4847 size
= ntfs_sid_size(pgroup
);
4848 memcpy(&target
[pos
], pgroup
, size
);
4849 targhead
->group
= cpu_to_le32(pos
);
4852 targhead
->group
= const_cpu_to_le32(0);
4853 if (selection
& GROUP_SECURITY_INFORMATION
)
4854 control
|= newhead
->control
& SE_GROUP_DEFAULTED
;
4856 control
|= oldhead
->control
& SE_GROUP_DEFAULTED
;
4857 targhead
->revision
= SECURITY_DESCRIPTOR_REVISION
;
4858 targhead
->alignment
= 0;
4859 targhead
->control
= control
;
4860 ok
= !update_secur_descr(vol
, target
, ni
);
4867 * Return the security descriptor of a file
4868 * This is intended to be similar to GetFileSecurity() from Win32
4869 * in order to facilitate the development of portable tools
4871 * returns zero if unsuccessful (following Win32 conventions)
4873 * the securid if any
4875 * The Win32 API is :
4877 * BOOL WINAPI GetFileSecurity(
4878 * __in LPCTSTR lpFileName,
4879 * __in SECURITY_INFORMATION RequestedInformation,
4880 * __out_opt PSECURITY_DESCRIPTOR pSecurityDescriptor,
4881 * __in DWORD nLength,
4882 * __out LPDWORD lpnLengthNeeded
4887 int ntfs_get_file_security(struct SECURITY_API
*scapi
,
4888 const char *path
, u32 selection
,
4889 char *buf
, u32 buflen
, u32
*psize
)
4895 res
= 0; /* default return */
4896 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
4897 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
4899 attr
= getsecurityattr(scapi
->security
.vol
, ni
);
4901 if (feedsecurityattr(attr
,selection
,
4902 buf
,buflen
,psize
)) {
4903 if (test_nino_flag(ni
, v3_Extensions
)
4912 ntfs_inode_close(ni
);
4915 if (!res
) *psize
= 0;
4917 errno
= EINVAL
; /* do not clear *psize */
4923 * Set the security descriptor of a file or directory
4924 * This is intended to be similar to SetFileSecurity() from Win32
4925 * in order to facilitate the development of portable tools
4927 * returns zero if unsuccessful (following Win32 conventions)
4929 * the securid if any
4931 * The Win32 API is :
4933 * BOOL WINAPI SetFileSecurity(
4934 * __in LPCTSTR lpFileName,
4935 * __in SECURITY_INFORMATION SecurityInformation,
4936 * __in PSECURITY_DESCRIPTOR pSecurityDescriptor
4940 int ntfs_set_file_security(struct SECURITY_API
*scapi
,
4941 const char *path
, u32 selection
, const char *attr
)
4943 const SECURITY_DESCRIPTOR_RELATIVE
*phead
;
4950 res
= 0; /* default return */
4951 if (scapi
&& (scapi
->magic
== MAGIC_API
) && attr
) {
4952 phead
= (const SECURITY_DESCRIPTOR_RELATIVE
*)attr
;
4953 attrsz
= ntfs_attr_size(attr
);
4954 /* if selected, owner and group must be present or defaulted */
4955 missing
= ((selection
& OWNER_SECURITY_INFORMATION
)
4957 && !(phead
->control
& SE_OWNER_DEFAULTED
))
4958 || ((selection
& GROUP_SECURITY_INFORMATION
)
4960 && !(phead
->control
& SE_GROUP_DEFAULTED
));
4962 && (phead
->control
& SE_SELF_RELATIVE
)
4963 && ntfs_valid_descr(attr
, attrsz
)) {
4964 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
,
4967 oldattr
= getsecurityattr(scapi
->security
.vol
,
4970 if (mergesecurityattr(
4971 scapi
->security
.vol
,
4974 if (test_nino_flag(ni
,
4983 ntfs_inode_close(ni
);
4994 * Return the attributes of a file
4995 * This is intended to be similar to GetFileAttributes() from Win32
4996 * in order to facilitate the development of portable tools
4998 * returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES)
5000 * The Win32 API is :
5002 * DWORD WINAPI GetFileAttributes(
5003 * __in LPCTSTR lpFileName
5007 int ntfs_get_file_attributes(struct SECURITY_API
*scapi
, const char *path
)
5012 attrib
= -1; /* default return */
5013 if (scapi
&& (scapi
->magic
== MAGIC_API
) && path
) {
5014 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
5016 attrib
= le32_to_cpu(ni
->flags
);
5017 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
)
5018 attrib
|= const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
5020 attrib
&= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY
);
5022 attrib
|= const_le32_to_cpu(FILE_ATTR_NORMAL
);
5024 ntfs_inode_close(ni
);
5028 errno
= EINVAL
; /* do not clear *psize */
5034 * Set attributes to a file or directory
5035 * This is intended to be similar to SetFileAttributes() from Win32
5036 * in order to facilitate the development of portable tools
5038 * Only a few flags can be set (same list as Win32)
5040 * returns zero if unsuccessful (following Win32 conventions)
5041 * nonzero if successful
5043 * The Win32 API is :
5045 * BOOL WINAPI SetFileAttributes(
5046 * __in LPCTSTR lpFileName,
5047 * __in DWORD dwFileAttributes
5051 BOOL
ntfs_set_file_attributes(struct SECURITY_API
*scapi
,
5052 const char *path
, s32 attrib
)
5056 ATTR_FLAGS dirflags
;
5059 res
= 0; /* default return */
5060 if (scapi
&& (scapi
->magic
== MAGIC_API
) && path
) {
5061 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
5063 settable
= FILE_ATTR_SETTABLE
;
5064 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
5066 * Accept changing compression for a directory
5067 * and set index root accordingly
5069 settable
|= FILE_ATTR_COMPRESSED
;
5070 if ((ni
->flags
^ cpu_to_le32(attrib
))
5071 & FILE_ATTR_COMPRESSED
) {
5072 if (ni
->flags
& FILE_ATTR_COMPRESSED
)
5073 dirflags
= const_cpu_to_le16(0);
5075 dirflags
= ATTR_IS_COMPRESSED
;
5076 res
= ntfs_attr_set_flags(ni
,
5080 ATTR_COMPRESSION_MASK
);
5084 ni
->flags
= (ni
->flags
& ~settable
)
5085 | (cpu_to_le32(attrib
) & settable
);
5087 NInoFileNameSetDirty(ni
);
5089 if (!ntfs_inode_close(ni
))
5098 BOOL
ntfs_read_directory(struct SECURITY_API
*scapi
,
5099 const char *path
, ntfs_filldir_t callback
, void *context
)
5105 ok
= FALSE
; /* default return */
5106 if (scapi
&& (scapi
->magic
== MAGIC_API
) && callback
) {
5107 ni
= ntfs_pathname_to_inode(scapi
->security
.vol
, NULL
, path
);
5109 if (ni
->mrec
->flags
& MFT_RECORD_IS_DIRECTORY
) {
5111 ntfs_readdir(ni
,&pos
,context
,callback
);
5112 ok
= !ntfs_inode_close(ni
);
5114 ntfs_inode_close(ni
);
5120 errno
= EINVAL
; /* do not clear *psize */
5125 * read $SDS (for auditing security data)
5127 * Returns the number or read bytes, or -1 if there is an error
5130 int ntfs_read_sds(struct SECURITY_API
*scapi
,
5131 char *buf
, u32 size
, u32 offset
)
5135 got
= -1; /* default return */
5136 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
5137 if (scapi
->security
.vol
->secure_ni
)
5138 got
= ntfs_attr_data_read(scapi
->security
.vol
->secure_ni
,
5139 STREAM_SDS
, 4, buf
, size
, offset
);
5148 * read $SII (for auditing security data)
5150 * Returns next entry, or NULL if there is an error
5153 INDEX_ENTRY
*ntfs_read_sii(struct SECURITY_API
*scapi
,
5159 ntfs_index_context
*xsii
;
5161 ret
= (INDEX_ENTRY
*)NULL
; /* default return */
5162 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
5163 xsii
= scapi
->security
.vol
->secure_xsii
;
5166 key
.security_id
= const_cpu_to_le32(0);
5167 found
= !ntfs_index_lookup((char*)&key
,
5168 sizeof(SII_INDEX_KEY
), xsii
);
5169 /* not supposed to find */
5170 if (!found
&& (errno
== ENOENT
))
5173 ret
= ntfs_index_next(entry
,xsii
);
5184 * read $SDH (for auditing security data)
5186 * Returns next entry, or NULL if there is an error
5189 INDEX_ENTRY
*ntfs_read_sdh(struct SECURITY_API
*scapi
,
5195 ntfs_index_context
*xsdh
;
5197 ret
= (INDEX_ENTRY
*)NULL
; /* default return */
5198 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
5199 xsdh
= scapi
->security
.vol
->secure_xsdh
;
5202 key
.hash
= const_cpu_to_le32(0);
5203 key
.security_id
= const_cpu_to_le32(0);
5204 found
= !ntfs_index_lookup((char*)&key
,
5205 sizeof(SDH_INDEX_KEY
), xsdh
);
5206 /* not supposed to find */
5207 if (!found
&& (errno
== ENOENT
))
5210 ret
= ntfs_index_next(entry
,xsdh
);
5213 } else errno
= ENOTSUP
;
5220 * Get the mapped user SID
5221 * A buffer of 40 bytes has to be supplied
5223 * returns the size of the SID, or zero and errno set if not found
5226 int ntfs_get_usid(struct SECURITY_API
*scapi
, uid_t uid
, char *buf
)
5233 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
5234 usid
= ntfs_find_usid(scapi
->security
.mapping
[MAPUSERS
], uid
, (SID
*)&defusid
);
5236 size
= ntfs_sid_size(usid
);
5237 memcpy(buf
,usid
,size
);
5246 * Get the mapped group SID
5247 * A buffer of 40 bytes has to be supplied
5249 * returns the size of the SID, or zero and errno set if not found
5252 int ntfs_get_gsid(struct SECURITY_API
*scapi
, gid_t gid
, char *buf
)
5259 if (scapi
&& (scapi
->magic
== MAGIC_API
)) {
5260 gsid
= ntfs_find_gsid(scapi
->security
.mapping
[MAPGROUPS
], gid
, (SID
*)&defgsid
);
5262 size
= ntfs_sid_size(gsid
);
5263 memcpy(buf
,gsid
,size
);
5272 * Get the user mapped to a SID
5274 * returns the uid, or -1 if not found
5277 int ntfs_get_user(struct SECURITY_API
*scapi
, const SID
*usid
)
5282 if (scapi
&& (scapi
->magic
== MAGIC_API
) && ntfs_valid_sid(usid
)) {
5283 if (ntfs_same_sid(usid
,adminsid
))
5286 uid
= ntfs_find_user(scapi
->security
.mapping
[MAPUSERS
], usid
);
5298 * Get the group mapped to a SID
5300 * returns the uid, or -1 if not found
5303 int ntfs_get_group(struct SECURITY_API
*scapi
, const SID
*gsid
)
5308 if (scapi
&& (scapi
->magic
== MAGIC_API
) && ntfs_valid_sid(gsid
)) {
5309 if (ntfs_same_sid(gsid
,adminsid
))
5312 gid
= ntfs_find_group(scapi
->security
.mapping
[MAPGROUPS
], gsid
);
5324 * Initializations before calling ntfs_get_file_security()
5325 * ntfs_set_file_security() and ntfs_read_directory()
5327 * Only allowed for root
5329 * Returns an (obscured) struct SECURITY_API* needed for further calls
5330 * NULL if not root (EPERM) or device is mounted (EBUSY)
5333 struct SECURITY_API
*ntfs_initialize_file_security(const char *device
,
5334 unsigned long flags
)
5337 unsigned long mntflag
;
5339 struct SECURITY_API
*scapi
;
5340 struct SECURITY_CONTEXT
*scx
;
5342 scapi
= (struct SECURITY_API
*)NULL
;
5343 mnt
= ntfs_check_if_mounted(device
, &mntflag
);
5344 if (!mnt
&& !(mntflag
& NTFS_MF_MOUNTED
) && !getuid()) {
5345 vol
= ntfs_mount(device
, flags
);
5347 scapi
= (struct SECURITY_API
*)
5348 ntfs_malloc(sizeof(struct SECURITY_API
));
5349 if (!ntfs_volume_get_free_space(vol
)
5351 scapi
->magic
= MAGIC_API
;
5352 scapi
->seccache
= (struct PERMISSIONS_CACHE
*)NULL
;
5353 scx
= &scapi
->security
;
5355 scx
->uid
= getuid();
5356 scx
->gid
= getgid();
5357 scx
->pseccache
= &scapi
->seccache
;
5358 scx
->vol
->secure_flags
= 0;
5359 /* accept no mapping and no $Secure */
5360 ntfs_build_mapping(scx
,(const char*)NULL
,TRUE
);
5366 mnt
= ntfs_umount(vol
,FALSE
);
5367 scapi
= (struct SECURITY_API
*)NULL
;
5379 * Leaving after ntfs_initialize_file_security()
5381 * Returns FALSE if FAILED
5384 BOOL
ntfs_leave_file_security(struct SECURITY_API
*scapi
)
5390 if (scapi
&& (scapi
->magic
== MAGIC_API
) && scapi
->security
.vol
) {
5391 vol
= scapi
->security
.vol
;
5392 ntfs_destroy_security_context(&scapi
->security
);
5394 if (!ntfs_umount(vol
, 0))