2 * security.c - Handling security/ACLs in NTFS. Originated from the Linux-NTFS project.
4 * Copyright (c) 2004 Anton Altaparmakov
5 * Copyright (c) 2005-2006 Szabolcs Szakacsits
6 * Copyright (c) 2006 Yura Pakhuchiy
7 * Copyright (c) 2007-2010 Jean-Pierre Andre
9 * This program/include file is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program/include file is distributed in the hope that it will be
15 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (in the main directory of the NTFS-3G
21 * distribution in the file COPYING); if not, write to the Free Software
22 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
41 #include <sys/xattr.h>
43 #ifdef HAVE_SYS_STAT_H
51 #include <ntfs-3g/param.h>
52 #include <ntfs-3g/types.h>
53 #include <ntfs-3g/layout.h>
54 #include <ntfs-3g/attrib.h>
55 #include <ntfs-3g/index.h>
56 #include <ntfs-3g/dir.h>
57 #include <ntfs-3g/bitmap.h>
58 #include <ntfs-3g/security.h>
59 #include <ntfs-3g/acls.h>
60 #include <ntfs-3g/cache.h>
61 #include <ntfs-3g/misc.h>
64 * JPA NTFS constants or structs
65 * should be moved to layout.h
68 #define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */
69 #define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */
70 #define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */
71 #define FIRST_SECURITY_ID 0x100 /* Lowest security id */
73 /* Mask for attributes which can be forced */
74 #define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY \
78 | FILE_ATTR_TEMPORARY \
80 | FILE_ATTR_NOT_CONTENT_INDEXED )
82 struct SII { /* this is an image of an $SII index entry */
92 /* did not find official description for the following */
95 le32 dataoffsl; /* documented as badly aligned */
100 struct SDH { /* this is an image of an $SDH index entry */
111 /* did not find official description for the following */
121 * A few useful constants
124 static ntfschar sii_stream[] = { const_cpu_to_le16('$'),
125 const_cpu_to_le16('S'),
126 const_cpu_to_le16('I'),
127 const_cpu_to_le16('I'),
128 const_cpu_to_le16(0) };
129 static ntfschar sdh_stream[] = { const_cpu_to_le16('$'),
130 const_cpu_to_le16('S'),
131 const_cpu_to_le16('D'),
132 const_cpu_to_le16('H'),
133 const_cpu_to_le16(0) };
139 extern const SID *nullsid;
145 static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
146 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
147 static const GUID *const zero_guid = &__zero_guid;
150 * ntfs_guid_is_zero - check if a GUID is zero
151 * @guid: [IN] guid to check
153 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
154 * and FALSE otherwise.
156 BOOL ntfs_guid_is_zero(const GUID *guid)
158 return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
162 * ntfs_guid_to_mbs - convert a GUID to a multi byte string
163 * @guid: [IN] guid to convert
164 * @guid_str: [OUT] string in which to return the GUID (optional)
166 * Convert the GUID pointed to by @guid to a multi byte string of the form
167 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
168 * needs to be able to store at least 37 bytes.
170 * If @guid_str is not NULL it will contain the converted GUID on return. If
171 * it is NULL a string will be allocated and this will be returned. The caller
172 * is responsible for free()ing the string in that case.
174 * On success return the converted string and on failure return NULL with errno
175 * set to the error code.
177 char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
186 _guid_str = guid_str;
188 _guid_str = (char*)ntfs_malloc(37);
192 res = snprintf(_guid_str, 37,
193 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
194 (unsigned int)le32_to_cpu(guid->data1),
195 le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
196 guid->data4[0], guid->data4[1],
197 guid->data4[2], guid->data4[3], guid->data4[4],
198 guid->data4[5], guid->data4[6], guid->data4[7]);
208 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
209 * @sid: [IN] SID for which to determine the maximum string size
211 * Determine the maximum multi byte string size in bytes which is needed to
212 * store the standard textual representation of the SID pointed to by @sid.
213 * See ntfs_sid_to_mbs(), below.
215 * On success return the maximum number of bytes needed to store the multi byte
216 * string and on failure return -1 with errno set to the error code.
218 int ntfs_sid_to_mbs_size(const SID *sid)
222 if (!ntfs_sid_is_valid(sid)) {
226 /* Start with "S-". */
229 * Add the SID_REVISION. Hopefully the compiler will optimize this
230 * away as SID_REVISION is a constant.
232 for (i = SID_REVISION; i > 0; i /= 10)
237 * Add the identifier authority. If it needs to be in decimal, the
238 * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
239 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
241 if (!sid->identifier_authority.high_part)
246 * Finally, add the sub authorities. For each we have a "-" followed
247 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
249 size += (1 + 10) * sid->sub_authority_count;
250 /* We need the zero byte at the end, too. */
252 return size * sizeof(char);
256 * ntfs_sid_to_mbs - convert a SID to a multi byte string
257 * @sid: [IN] SID to convert
258 * @sid_str: [OUT] string in which to return the SID (optional)
259 * @sid_str_size: [IN] size in bytes of @sid_str
261 * Convert the SID pointed to by @sid to its standard textual representation.
262 * @sid_str (if not NULL) needs to be able to store at least
263 * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
264 * @sid_str if @sid_str is not NULL.
266 * The standard textual representation of the SID is of the form:
269 * - The first "S" is the literal character 'S' identifying the following
271 * - R is the revision level of the SID expressed as a sequence of digits
273 * - I is the 48-bit identifier_authority, expressed as digits in decimal,
274 * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
275 * - S... is one or more sub_authority values, expressed as digits in
278 * If @sid_str is not NULL it will contain the converted SUID on return. If it
279 * is NULL a string will be allocated and this will be returned. The caller is
280 * responsible for free()ing the string in that case.
282 * On success return the converted string and on failure return NULL with errno
283 * set to the error code.
285 char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
293 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
294 * check @sid, too. 8 is the minimum SID string size.
296 if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
300 /* Allocate string if not provided. */
302 cnt = ntfs_sid_to_mbs_size(sid);
305 s = (char*)ntfs_malloc(cnt);
309 /* So we know we allocated it. */
315 /* Start with "S-R-". */
316 i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
317 if (i < 0 || i >= cnt)
321 /* Add the identifier authority. */
322 for (u = i = 0, j = 40; i < 6; i++, j -= 8)
323 u += (u64)sid->identifier_authority.value[i] << j;
324 if (!sid->identifier_authority.high_part)
325 i = snprintf(s, cnt, "%lu", (unsigned long)u);
327 i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
328 if (i < 0 || i >= cnt)
332 /* Finally, add the sub authorities. */
333 for (j = 0; j < sid->sub_authority_count; j++) {
334 leauth = sid->sub_authority[j];
335 i = snprintf(s, cnt, "-%u", (unsigned int)
336 le32_to_cpu(leauth));
337 if (i < 0 || i >= cnt)
355 * ntfs_generate_guid - generatates a random current guid.
356 * @guid: [OUT] pointer to a GUID struct to hold the generated guid.
358 * perhaps not a very good random number generator though...
360 void ntfs_generate_guid(GUID *guid)
365 for (i = 0; i < sizeof(GUID); i++) {
366 p[i] = (u8)(random() & 0xFF);
368 p[7] = (p[7] & 0x0F) | 0x40;
370 p[8] = (p[8] & 0x3F) | 0x80;
375 * ntfs_security_hash - calculate the hash of a security descriptor
376 * @sd: self-relative security descriptor whose hash to calculate
377 * @length: size in bytes of the security descritor @sd
379 * Calculate the hash of the self-relative security descriptor @sd of length
382 * This hash is used in the $Secure system file as the primary key for the $SDH
383 * index and is also stored in the header of each security descriptor in the
384 * $SDS data stream as well as in the index data of both the $SII and $SDH
385 * indexes. In all three cases it forms part of the SDS_ENTRY_HEADER
388 * Return the calculated security hash in little endian.
390 le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len)
392 const le32 *pos = (const le32*)sd;
393 const le32 *end = pos + (len >> 2);
397 hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3);
400 return cpu_to_le32(hash);
404 * Get the first entry of current index block
405 * cut and pasted form ntfs_ie_get_first() in index.c
408 static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih)
410 return (INDEX_ENTRY*)((u8*)ih + le32_to_cpu(ih->entries_offset));
414 * Stuff a 256KB block into $SDS before writing descriptors
417 * This prevents $SDS from being automatically declared as sparse
418 * when the second copy of the first security descriptor is written
419 * 256KB further ahead.
421 * Having $SDS declared as a sparse file is not wrong by itself
422 * and chkdsk leaves it as a sparse file. It does however complain
423 * and add a sparse flag (0x0200) into field file_attributes of
424 * STANDARD_INFORMATION of $Secure. This probably means that a
425 * sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse
426 * files (FILE_ATTR_SPARSE_FILE).
428 * Windows normally does not convert to sparse attribute or sparse
429 * file. Stuffing is just a way to get to the same result.
432 static int entersecurity_stuff(ntfs_volume *vol, off_t offs)
441 stuff = (char*)ntfs_malloc(STUFFSZ);
443 memset(stuff, 0, STUFFSZ);
445 written = ntfs_attr_data_write(vol->secure_ni,
446 STREAM_SDS, 4, stuff, STUFFSZ, offs);
447 if (written == STUFFSZ) {
454 } while (!res && (total < ALIGN_SDS_BLOCK));
464 * Enter a new security descriptor into $Secure (data only)
465 * it has to be written twice with an offset of 256KB
467 * Should only be called by entersecurityattr() to ensure consistency
469 * Returns zero if sucessful
472 static int entersecurity_data(ntfs_volume *vol,
473 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
474 le32 hash, le32 keyid, off_t offs, int gap)
481 SECURITY_DESCRIPTOR_HEADER *phsds;
484 fullsz = attrsz + gap + sizeof(SECURITY_DESCRIPTOR_HEADER);
485 fullattr = (char*)ntfs_malloc(fullsz);
488 * Clear the gap from previous descriptor
489 * this could be useful for appending the second
490 * copy to the end of file. When creating a new
491 * 256K block, the gap is cleared while writing
495 memset(fullattr,0,gap);
496 memcpy(&fullattr[gap + sizeof(SECURITY_DESCRIPTOR_HEADER)],
498 phsds = (SECURITY_DESCRIPTOR_HEADER*)&fullattr[gap];
500 phsds->security_id = keyid;
501 phsds->offset = cpu_to_le64(offs);
502 phsds->length = cpu_to_le32(fullsz - gap);
503 written1 = ntfs_attr_data_write(vol->secure_ni,
504 STREAM_SDS, 4, fullattr, fullsz,
506 written2 = ntfs_attr_data_write(vol->secure_ni,
507 STREAM_SDS, 4, fullattr, fullsz,
508 offs - gap + ALIGN_SDS_BLOCK);
509 if ((written1 == fullsz)
510 && (written2 == written1))
521 * Enter a new security descriptor in $Secure (indexes only)
523 * Should only be called by entersecurityattr() to ensure consistency
525 * Returns zero if sucessful
528 static int entersecurity_indexes(ntfs_volume *vol, s64 attrsz,
529 le32 hash, le32 keyid, off_t offs)
539 ntfs_index_context *xsii;
540 ntfs_index_context *xsdh;
545 /* enter a new $SII record */
547 xsii = vol->secure_xsii;
548 ntfs_index_ctx_reinit(xsii);
549 newsii.offs = const_cpu_to_le16(20);
550 newsii.size = const_cpu_to_le16(sizeof(struct SII) - 20);
551 newsii.fill1 = const_cpu_to_le32(0);
552 newsii.indexsz = const_cpu_to_le16(sizeof(struct SII));
553 newsii.indexksz = const_cpu_to_le16(sizeof(SII_INDEX_KEY));
554 newsii.flags = const_cpu_to_le16(0);
555 newsii.fill2 = const_cpu_to_le16(0);
556 newsii.keysecurid = keyid;
558 newsii.securid = keyid;
559 realign.all = cpu_to_le64(offs);
560 newsii.dataoffsh = realign.parts.dataoffsh;
561 newsii.dataoffsl = realign.parts.dataoffsl;
562 newsii.datasize = cpu_to_le32(attrsz
563 + sizeof(SECURITY_DESCRIPTOR_HEADER));
564 if (!ntfs_ie_add(xsii,(INDEX_ENTRY*)&newsii)) {
566 /* enter a new $SDH record */
568 xsdh = vol->secure_xsdh;
569 ntfs_index_ctx_reinit(xsdh);
570 newsdh.offs = const_cpu_to_le16(24);
571 newsdh.size = const_cpu_to_le16(
572 sizeof(SECURITY_DESCRIPTOR_HEADER));
573 newsdh.fill1 = const_cpu_to_le32(0);
574 newsdh.indexsz = const_cpu_to_le16(
576 newsdh.indexksz = const_cpu_to_le16(
577 sizeof(SDH_INDEX_KEY));
578 newsdh.flags = const_cpu_to_le16(0);
579 newsdh.fill2 = const_cpu_to_le16(0);
580 newsdh.keyhash = hash;
581 newsdh.keysecurid = keyid;
583 newsdh.securid = keyid;
584 newsdh.dataoffsh = realign.parts.dataoffsh;
585 newsdh.dataoffsl = realign.parts.dataoffsl;
586 newsdh.datasize = cpu_to_le32(attrsz
587 + sizeof(SECURITY_DESCRIPTOR_HEADER));
588 /* special filler value, Windows generally */
589 /* fills with 0x00490049, sometimes with zero */
590 newsdh.fill3 = const_cpu_to_le32(0x00490049);
591 if (!ntfs_ie_add(xsdh,(INDEX_ENTRY*)&newsdh))
598 * Enter a new security descriptor in $Secure (data and indexes)
599 * Returns id of entry, or zero if there is a problem.
600 * (should not be called for NTFS version < 3.0)
602 * important : calls have to be serialized, however no locking is
603 * needed while fuse is not multithreaded
606 static le32 entersecurityattr(ntfs_volume *vol,
607 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
627 ntfs_index_context *xsii;
632 /* find the first available securid beyond the last key */
633 /* in $Secure:$SII. This also determines the first */
634 /* available location in $Secure:$SDS, as this stream */
635 /* is always appended to and the id's are allocated */
638 securid = const_cpu_to_le32(0);
639 xsii = vol->secure_xsii;
640 ntfs_index_ctx_reinit(xsii);
642 keyid = const_cpu_to_le32(-1);
644 found = !ntfs_index_lookup((char*)&keyid,
645 sizeof(SII_INDEX_KEY), xsii);
646 if (!found && (errno != ENOENT)) {
647 ntfs_log_perror("Inconsistency in index $SII");
648 psii = (struct SII*)NULL;
650 /* restore errno to avoid misinterpretation */
653 psii = (struct SII*)xsii->entry;
657 * Get last entry in block, but must get first one
658 * one first, as we should already be beyond the
659 * last one. For some reason the search for the last
660 * entry sometimes does not return the last block...
661 * we assume this can only happen in root block
663 if (xsii->is_in_root)
664 entry = ntfs_ie_get_first
665 ((INDEX_HEADER*)&xsii->ir->index);
667 entry = ntfs_ie_get_first
668 ((INDEX_HEADER*)&xsii->ib->index);
670 * All index blocks should be at least half full
671 * so there always is a last entry but one,
672 * except when creating the first entry in index root.
673 * This was however found not to be true : chkdsk
674 * sometimes deletes all the (unused) keys in the last
675 * index block without rebalancing the tree.
676 * When this happens, a new search is restarted from
679 keyid = const_cpu_to_le32(0);
682 next = ntfs_index_next(entry,xsii);
684 psii = (struct SII*)next;
685 /* save last key and */
686 /* available position */
687 keyid = psii->keysecurid;
688 realign.parts.dataoffsh
690 realign.parts.dataoffsl
692 offs = le64_to_cpu(realign.all);
693 size = le32_to_cpu(psii->datasize);
696 if (!entry && !keyid && !retries) {
697 /* search failed, retry from smallest key */
698 ntfs_index_ctx_reinit(xsii);
699 found = !ntfs_index_lookup((char*)&keyid,
700 sizeof(SII_INDEX_KEY), xsii);
701 if (!found && (errno != ENOENT)) {
702 ntfs_log_perror("Index $SII is broken");
714 * could not find any entry, before creating the first
715 * entry, make a double check by making sure size of $SII
716 * is less than needed for one entry
718 securid = const_cpu_to_le32(0);
719 na = ntfs_attr_open(vol->secure_ni,AT_INDEX_ROOT,sii_stream,4);
721 if ((size_t)na->data_size < sizeof(struct SII)) {
722 ntfs_log_error("Creating the first security_id\n");
723 securid = const_cpu_to_le32(FIRST_SECURITY_ID);
728 ntfs_log_error("Error creating a security_id\n");
732 newkey = le32_to_cpu(keyid) + 1;
733 securid = cpu_to_le32(newkey);
736 * The security attr has to be written twice 256KB
737 * apart. This implies that offsets like
738 * 0x40000*odd_integer must be left available for
739 * the second copy. So align to next block when
740 * the last byte overflows on a wrong block.
744 gap = (-size) & (ALIGN_SDS_ENTRY - 1);
746 if ((offs + attrsz + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
748 offs = ((offs + attrsz
749 + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
750 | (ALIGN_SDS_BLOCK - 1)) + 1;
752 if (!(offs & (ALIGN_SDS_BLOCK - 1)))
753 entersecurity_stuff(vol, offs);
755 * now write the security attr to storage :
756 * first data, then SII, then SDH
757 * If failure occurs while writing SDS, data will never
758 * be accessed through indexes, and will be overwritten
759 * by the next allocated descriptor
760 * If failure occurs while writing SII, the id has not
761 * recorded and will be reallocated later
762 * If failure occurs while writing SDH, the space allocated
763 * in SDS or SII will not be reused, an inconsistency
764 * will persist with no significant consequence
766 if (entersecurity_data(vol, attr, attrsz, hash, securid, offs, gap)
767 || entersecurity_indexes(vol, attrsz, hash, securid, offs))
768 securid = const_cpu_to_le32(0);
770 /* inode now is dirty, synchronize it all */
771 ntfs_index_entry_mark_dirty(vol->secure_xsii);
772 ntfs_index_ctx_reinit(vol->secure_xsii);
773 ntfs_index_entry_mark_dirty(vol->secure_xsdh);
774 ntfs_index_ctx_reinit(vol->secure_xsdh);
775 NInoSetDirty(vol->secure_ni);
776 if (ntfs_inode_sync(vol->secure_ni))
777 ntfs_log_perror("Could not sync $Secure\n");
782 * Find a matching security descriptor in $Secure,
783 * if none, allocate a new id and write the descriptor to storage
784 * Returns id of entry, or zero if there is a problem.
786 * important : calls have to be serialized, however no locking is
787 * needed while fuse is not multithreaded
790 static le32 setsecurityattr(ntfs_volume *vol,
791 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz)
793 struct SDH *psdh; /* this is an image of index (le) */
807 ntfs_index_context *xsdh;
815 hash = ntfs_security_hash(attr,attrsz);
816 oldattr = (char*)NULL;
817 securid = const_cpu_to_le32(0);
819 xsdh = vol->secure_xsdh;
820 if (vol->secure_ni && xsdh && !vol->secure_reentry++) {
821 ntfs_index_ctx_reinit(xsdh);
823 * find the nearest key as (hash,0)
824 * (do not search for partial key : in case of collision,
825 * it could return a key which is not the first one which
829 key.security_id = const_cpu_to_le32(0);
831 found = !ntfs_index_lookup((char*)&key,
832 sizeof(SDH_INDEX_KEY), xsdh);
833 if (!found && (errno != ENOENT))
834 ntfs_log_perror("Inconsistency in index $SDH");
836 /* restore errno to avoid misinterpretation */
841 * lookup() may return a node with no data,
844 if (entry->ie_flags & INDEX_ENTRY_END)
845 entry = ntfs_index_next(entry,xsdh);
848 psdh = (struct SDH*)entry;
850 size = (size_t) le32_to_cpu(psdh->datasize)
851 - sizeof(SECURITY_DESCRIPTOR_HEADER);
853 /* if hash is not the same, the key is not present */
854 if (psdh && (size > 0)
855 && (psdh->keyhash == hash)) {
856 /* if hash is the same */
857 /* check the whole record */
858 realign.parts.dataoffsh = psdh->dataoffsh;
859 realign.parts.dataoffsl = psdh->dataoffsl;
860 offs = le64_to_cpu(realign.all)
861 + sizeof(SECURITY_DESCRIPTOR_HEADER);
862 oldattr = (char*)ntfs_malloc(size);
864 rdsize = ntfs_attr_data_read(
867 oldattr, size, offs);
868 found = (rdsize == size)
869 && !memcmp(oldattr,attr,size);
871 /* if the records do not compare */
872 /* (hash collision), try next one */
874 entry = ntfs_index_next(
881 } while (collision && entry);
883 securid = psdh->keysecurid;
887 securid = const_cpu_to_le32(0);
891 * have to build a new one
893 securid = entersecurityattr(vol,
899 if (--vol->secure_reentry)
900 ntfs_log_perror("Reentry error, check no multithreading\n");
906 * Update the security descriptor of a file
907 * Either as an attribute (complying with pre v3.x NTFS version)
908 * or, when possible, as an entry in $Secure (for NTFS v3.x)
910 * returns 0 if success
913 static int update_secur_descr(ntfs_volume *vol,
914 char *newattr, ntfs_inode *ni)
921 newattrsz = ntfs_attr_size(newattr);
923 #if !FORCE_FORMAT_v1x
924 if ((vol->major_ver < 3) || !vol->secure_ni) {
927 /* update for NTFS format v1.x */
929 /* update the old security attribute */
930 na = ntfs_attr_open(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0);
932 /* resize attribute */
933 res = ntfs_attr_truncate(na, (s64) newattrsz);
934 /* overwrite value */
936 written = (int)ntfs_attr_pwrite(na, (s64) 0,
937 (s64) newattrsz, newattr);
938 if (written != newattrsz) {
939 ntfs_log_error("Failed to update "
940 "a v1.x security descriptor\n");
947 /* if old security attribute was found, also */
948 /* truncate standard information attribute to v1.x */
949 /* this is needed when security data is wanted */
950 /* as v1.x though volume is formatted for v3.x */
951 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
954 clear_nino_flag(ni, v3_Extensions);
956 * Truncating the record does not sweep extensions
957 * from copy in memory. Clear security_id to be safe
959 ni->security_id = const_cpu_to_le32(0);
960 res = ntfs_attr_truncate(na, (s64)48);
962 clear_nino_flag(ni, v3_Extensions);
966 * insert the new security attribute if there
969 res = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR,
970 AT_UNNAMED, 0, (u8*)newattr,
973 #if !FORCE_FORMAT_v1x
976 /* update for NTFS format v3.x */
980 securid = setsecurityattr(vol,
981 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
984 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
988 if (!test_nino_flag(ni, v3_Extensions)) {
989 /* expand standard information attribute to v3.x */
990 res = ntfs_attr_truncate(na,
991 (s64)sizeof(STANDARD_INFORMATION));
992 ni->owner_id = const_cpu_to_le32(0);
993 ni->quota_charged = const_cpu_to_le64(0);
994 ni->usn = const_cpu_to_le64(0);
996 AT_SECURITY_DESCRIPTOR,
999 set_nino_flag(ni, v3_Extensions);
1000 ni->security_id = securid;
1001 ntfs_attr_close(na);
1003 ntfs_log_error("Failed to update "
1004 "standard informations\n");
1013 /* mark node as dirty */
1019 * Upgrade the security descriptor of a file
1020 * This is intended to allow graceful upgrades for files which
1021 * were created in previous versions, with a security attributes
1022 * and no security id.
1024 * It will allocate a security id and replace the individual
1025 * security attribute by a reference to the global one
1027 * Special files are not upgraded (currently / and files in
1030 * Though most code is similar to update_secur_desc() it has
1031 * been kept apart to facilitate the further processing of
1032 * special cases or even to remove it if found dangerous.
1034 * returns 0 if success,
1035 * 1 if not upgradable. This is not an error.
1036 * -1 if there is a problem
1039 static int upgrade_secur_desc(ntfs_volume *vol,
1040 const char *attr, ntfs_inode *ni)
1048 * upgrade requires NTFS format v3.x
1049 * also refuse upgrading for special files
1050 * whose number is less than FILE_first_user
1053 if ((vol->major_ver >= 3)
1054 && (ni->mft_no >= FILE_first_user)) {
1055 attrsz = ntfs_attr_size(attr);
1056 securid = setsecurityattr(vol,
1057 (const SECURITY_DESCRIPTOR_RELATIVE*)attr,
1060 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
1063 /* expand standard information attribute to v3.x */
1064 res = ntfs_attr_truncate(na,
1065 (s64)sizeof(STANDARD_INFORMATION));
1066 ni->owner_id = const_cpu_to_le32(0);
1067 ni->quota_charged = const_cpu_to_le64(0);
1068 ni->usn = const_cpu_to_le64(0);
1069 ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR,
1071 set_nino_flag(ni, v3_Extensions);
1072 ni->security_id = securid;
1073 ntfs_attr_close(na);
1075 ntfs_log_error("Failed to upgrade "
1076 "standard informations\n");
1082 /* mark node as dirty */
1091 * Optional simplified checking of group membership
1093 * This only takes into account the groups defined in
1094 * /etc/group at initialization time.
1095 * It does not take into account the groups dynamically set by
1096 * setgroups() nor the changes in /etc/group since initialization
1098 * This optional method could be useful if standard checking
1099 * leads to a performance concern.
1101 * Should not be called for user root, however the group may be root
1105 static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1110 struct MAPPING *user;
1114 user = scx->mapping[MAPUSERS];
1115 while (user && ((uid_t)user->xid != uid))
1118 groups = user->groups;
1119 grcnt = user->grcnt;
1120 while ((--grcnt >= 0) && (groups[grcnt] != gid)) { }
1121 ingroup = (grcnt >= 0);
1129 * Check whether current thread owner is member of file group
1131 * Should not be called for user root, however the group may be root
1133 * As indicated by Miklos Szeredi :
1135 * The group list is available in
1137 * /proc/$PID/task/$TID/status
1139 * and fuse supplies TID in get_fuse_context()->pid. The only problem is
1140 * finding out PID, for which I have no good solution, except to iterate
1141 * through all processes. This is rather slow, but may be speeded up
1142 * with caching and heuristics (for single threaded programs PID = TID).
1144 * The following implementation gets the group list from
1145 * /proc/$TID/task/$TID/status which apparently exists and
1146 * contains the same data.
1149 static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1151 static char key[] = "\nGroups:";
1154 enum { INKEY, INSEP, INNUM, INEND } state;
1164 if (scx->vol->secure_flags & (1 << SECURITY_STATICGRPS))
1165 ismember = staticgroupmember(scx, uid, gid);
1167 ismember = FALSE; /* default return */
1169 sprintf(filename,"/proc/%u/task/%u/status",tid,tid);
1170 fd = open(filename,O_RDONLY);
1172 got = read(fd, buf, BUFSZ);
1179 * A simple automaton to process lines like
1180 * Groups: 14 500 513
1186 got = read(fd, buf, BUFSZ);
1189 c = *p++; /* 0 at end of file */
1193 if (key[matched] == c) {
1194 if (!key[++matched])
1203 if ((c >= '0') && (c <= '9')) {
1207 if ((c != ' ') && (c != '\t'))
1211 if ((c >= '0') && (c <= '9'))
1212 grp = grp*10 + c - '0';
1214 ismember = (grp == gid);
1215 if ((c != ' ') && (c != '\t'))
1223 } while (!ismember && c && (state != INEND));
1226 ntfs_log_error("No group record found in %s\n",filename);
1228 ntfs_log_error("Could not open %s\n",filename);
1234 * Cacheing is done two-way :
1235 * - from uid, gid and perm to securid (CACHED_SECURID)
1236 * - from a securid to uid, gid and perm (CACHED_PERMISSIONS)
1238 * CACHED_SECURID data is kept in a most-recent-first list
1239 * which should not be too long to be efficient. Its optimal
1240 * size is depends on usage and is hard to determine.
1242 * CACHED_PERMISSIONS data is kept in a two-level indexed array. It
1243 * is optimal at the expense of storage. Use of a most-recent-first
1244 * list would save memory and provide similar performances for
1245 * standard usage, but not for file servers with too many file
1248 * CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS
1249 * for legacy directories which were not allocated a security_id
1250 * it is organized in a most-recent-first list.
1252 * In main caches, data is never invalidated, as the meaning of
1253 * a security_id only changes when user mapping is changed, which
1254 * current implies remounting. However returned entries may be
1255 * overwritten at next update, so data has to be copied elsewhere
1256 * before another cache update is made.
1257 * In legacy cache, data has to be invalidated when protection is
1260 * Though the same data may be found in both list, they
1261 * must be kept separately : the interpretation of ACL
1262 * in both direction are approximations which could be non
1263 * reciprocal for some configuration of the user mapping data
1265 * During the process of recompiling ntfs-3g from a tgz archive,
1266 * security processing added 7.6% to the cpu time used by ntfs-3g
1267 * and 30% if the cache is disabled.
1270 static struct PERMISSIONS_CACHE *create_caches(struct SECURITY_CONTEXT *scx,
1273 struct PERMISSIONS_CACHE *cache;
1274 unsigned int index1;
1277 cache = (struct PERMISSIONS_CACHE*)NULL;
1278 /* create the first permissions blocks */
1279 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1280 cache = (struct PERMISSIONS_CACHE*)
1281 ntfs_malloc(sizeof(struct PERMISSIONS_CACHE)
1282 + index1*sizeof(struct CACHED_PERMISSIONS*));
1284 cache->head.last = index1;
1285 cache->head.p_reads = 0;
1286 cache->head.p_hits = 0;
1287 cache->head.p_writes = 0;
1288 *scx->pseccache = cache;
1289 for (i=0; i<=index1; i++)
1290 cache->cachetable[i]
1291 = (struct CACHED_PERMISSIONS*)NULL;
1297 * Free memory used by caches
1298 * The only purpose is to facilitate the detection of memory leaks
1301 static void free_caches(struct SECURITY_CONTEXT *scx)
1303 unsigned int index1;
1304 struct PERMISSIONS_CACHE *pseccache;
1306 pseccache = *scx->pseccache;
1308 for (index1=0; index1<=pseccache->head.last; index1++)
1309 if (pseccache->cachetable[index1]) {
1311 struct CACHED_PERMISSIONS *cacheentry;
1312 unsigned int index2;
1314 for (index2=0; index2<(1<< CACHE_PERMISSIONS_BITS); index2++) {
1315 cacheentry = &pseccache->cachetable[index1][index2];
1316 if (cacheentry->valid
1317 && cacheentry->pxdesc)
1318 free(cacheentry->pxdesc);
1321 free(pseccache->cachetable[index1]);
1327 static int compare(const struct CACHED_SECURID *cached,
1328 const struct CACHED_SECURID *item)
1334 /* only compare data and sizes */
1335 csize = (cached->variable ?
1336 sizeof(struct POSIX_ACL)
1337 + (((struct POSIX_SECURITY*)cached->variable)->acccnt
1338 + ((struct POSIX_SECURITY*)cached->variable)->defcnt)
1339 *sizeof(struct POSIX_ACE) :
1341 isize = (item->variable ?
1342 sizeof(struct POSIX_ACL)
1343 + (((struct POSIX_SECURITY*)item->variable)->acccnt
1344 + ((struct POSIX_SECURITY*)item->variable)->defcnt)
1345 *sizeof(struct POSIX_ACE) :
1347 return ((cached->uid != item->uid)
1348 || (cached->gid != item->gid)
1349 || (cached->dmode != item->dmode)
1353 && memcmp(&((struct POSIX_SECURITY*)cached->variable)->acl,
1354 &((struct POSIX_SECURITY*)item->variable)->acl, csize)));
1356 return ((cached->uid != item->uid)
1357 || (cached->gid != item->gid)
1358 || (cached->dmode != item->dmode));
1362 static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached,
1363 const struct CACHED_PERMISSIONS_LEGACY *item)
1365 return (cached->mft_no != item->mft_no);
1369 * Resize permission cache table
1370 * do not call unless resizing is needed
1372 * If allocation fails, the cache size is not updated
1373 * Lack of memory is not considered as an error, the cache is left
1374 * consistent and errno is not set.
1377 static void resize_cache(struct SECURITY_CONTEXT *scx,
1380 struct PERMISSIONS_CACHE *oldcache;
1381 struct PERMISSIONS_CACHE *newcache;
1384 unsigned int index1;
1387 oldcache = *scx->pseccache;
1388 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1389 newcnt = index1 + 1;
1390 if (newcnt <= ((CACHE_PERMISSIONS_SIZE
1391 + (1 << CACHE_PERMISSIONS_BITS)
1392 - 1) >> CACHE_PERMISSIONS_BITS)) {
1393 /* expand cache beyond current end, do not use realloc() */
1394 /* to avoid losing data when there is no more memory */
1395 oldcnt = oldcache->head.last + 1;
1396 newcache = (struct PERMISSIONS_CACHE*)
1398 sizeof(struct PERMISSIONS_CACHE)
1399 + (newcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
1401 memcpy(newcache,oldcache,
1402 sizeof(struct PERMISSIONS_CACHE)
1403 + (oldcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
1405 /* mark new entries as not valid */
1406 for (i=newcache->head.last+1; i<=index1; i++)
1407 newcache->cachetable[i]
1408 = (struct CACHED_PERMISSIONS*)NULL;
1409 newcache->head.last = index1;
1410 *scx->pseccache = newcache;
1416 * Enter uid, gid and mode into cache, if possible
1418 * returns the updated or created cache entry,
1419 * or NULL if not possible (typically if there is no
1420 * security id associated)
1424 static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
1425 ntfs_inode *ni, uid_t uid, gid_t gid,
1426 struct POSIX_SECURITY *pxdesc)
1428 static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
1429 ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode)
1432 struct CACHED_PERMISSIONS *cacheentry;
1433 struct CACHED_PERMISSIONS *cacheblock;
1434 struct PERMISSIONS_CACHE *pcache;
1438 struct POSIX_SECURITY *pxcached;
1440 unsigned int index1;
1441 unsigned int index2;
1444 /* cacheing is only possible if a security_id has been defined */
1445 if (test_nino_flag(ni, v3_Extensions)
1446 && ni->security_id) {
1448 * Immediately test the most frequent situation
1449 * where the entry exists
1451 securindex = le32_to_cpu(ni->security_id);
1452 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1453 index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
1454 pcache = *scx->pseccache;
1456 && (pcache->head.last >= index1)
1457 && pcache->cachetable[index1]) {
1458 cacheentry = &pcache->cachetable[index1][index2];
1459 cacheentry->uid = uid;
1460 cacheentry->gid = gid;
1462 if (cacheentry->valid && cacheentry->pxdesc)
1463 free(cacheentry->pxdesc);
1465 pxsize = sizeof(struct POSIX_SECURITY)
1466 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1467 pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
1469 memcpy(pxcached, pxdesc, pxsize);
1470 cacheentry->pxdesc = pxcached;
1472 cacheentry->valid = 0;
1473 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1475 cacheentry->mode = pxdesc->mode & 07777;
1477 cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
1479 cacheentry->mode = mode & 07777;
1481 cacheentry->inh_fileid = const_cpu_to_le32(0);
1482 cacheentry->inh_dirid = const_cpu_to_le32(0);
1483 cacheentry->valid = 1;
1484 pcache->head.p_writes++;
1487 /* create the first cache block */
1488 pcache = create_caches(scx, securindex);
1490 if (index1 > pcache->head.last) {
1491 resize_cache(scx, securindex);
1492 pcache = *scx->pseccache;
1495 /* allocate block, if cache table was allocated */
1496 if (pcache && (index1 <= pcache->head.last)) {
1497 cacheblock = (struct CACHED_PERMISSIONS*)
1498 malloc(sizeof(struct CACHED_PERMISSIONS)
1499 << CACHE_PERMISSIONS_BITS);
1500 pcache->cachetable[index1] = cacheblock;
1501 for (i=0; i<(1 << CACHE_PERMISSIONS_BITS); i++)
1502 cacheblock[i].valid = 0;
1503 cacheentry = &cacheblock[index2];
1505 cacheentry->uid = uid;
1506 cacheentry->gid = gid;
1509 pxsize = sizeof(struct POSIX_SECURITY)
1510 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1511 pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
1513 memcpy(pxcached, pxdesc, pxsize);
1514 cacheentry->pxdesc = pxcached;
1516 cacheentry->valid = 0;
1517 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1519 cacheentry->mode = pxdesc->mode & 07777;
1521 cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
1523 cacheentry->mode = mode & 07777;
1525 cacheentry->inh_fileid = const_cpu_to_le32(0);
1526 cacheentry->inh_dirid = const_cpu_to_le32(0);
1527 cacheentry->valid = 1;
1528 pcache->head.p_writes++;
1531 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1534 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1535 #if CACHE_LEGACY_SIZE
1536 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1537 struct CACHED_PERMISSIONS_LEGACY wanted;
1538 struct CACHED_PERMISSIONS_LEGACY *legacy;
1540 wanted.perm.uid = uid;
1541 wanted.perm.gid = gid;
1543 wanted.perm.mode = pxdesc->mode & 07777;
1544 wanted.perm.inh_fileid = const_cpu_to_le32(0);
1545 wanted.perm.inh_dirid = const_cpu_to_le32(0);
1546 wanted.mft_no = ni->mft_no;
1547 wanted.variable = (void*)pxdesc;
1548 wanted.varsize = sizeof(struct POSIX_SECURITY)
1549 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1551 wanted.perm.mode = mode & 07777;
1552 wanted.perm.inh_fileid = const_cpu_to_le32(0);
1553 wanted.perm.inh_dirid = const_cpu_to_le32(0);
1554 wanted.mft_no = ni->mft_no;
1555 wanted.variable = (void*)NULL;
1558 legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_enter_cache(
1559 scx->vol->legacy_cache, GENERIC(&wanted),
1560 (cache_compare)leg_compare);
1562 cacheentry = &legacy->perm;
1565 * give direct access to the cached pxdesc
1566 * in the permissions structure
1568 cacheentry->pxdesc = legacy->variable;
1574 return (cacheentry);
1578 * Fetch owner, group and permission of a file, if cached
1580 * Beware : do not use the returned entry after a cache update :
1581 * the cache may be relocated making the returned entry meaningless
1583 * returns the cache entry, or NULL if not available
1586 static struct CACHED_PERMISSIONS *fetch_cache(struct SECURITY_CONTEXT *scx,
1589 struct CACHED_PERMISSIONS *cacheentry;
1590 struct PERMISSIONS_CACHE *pcache;
1592 unsigned int index1;
1593 unsigned int index2;
1595 /* cacheing is only possible if a security_id has been defined */
1596 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1597 if (test_nino_flag(ni, v3_Extensions)
1598 && (ni->security_id)) {
1599 securindex = le32_to_cpu(ni->security_id);
1600 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1601 index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
1602 pcache = *scx->pseccache;
1604 && (pcache->head.last >= index1)
1605 && pcache->cachetable[index1]) {
1606 cacheentry = &pcache->cachetable[index1][index2];
1607 /* reject if entry is not valid */
1608 if (!cacheentry->valid)
1609 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1611 pcache->head.p_hits++;
1613 pcache->head.p_reads++;
1616 #if CACHE_LEGACY_SIZE
1618 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1619 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1620 struct CACHED_PERMISSIONS_LEGACY wanted;
1621 struct CACHED_PERMISSIONS_LEGACY *legacy;
1623 wanted.mft_no = ni->mft_no;
1624 wanted.variable = (void*)NULL;
1626 legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_fetch_cache(
1627 scx->vol->legacy_cache, GENERIC(&wanted),
1628 (cache_compare)leg_compare);
1629 if (legacy) cacheentry = &legacy->perm;
1634 if (cacheentry && !cacheentry->pxdesc) {
1635 ntfs_log_error("No Posix descriptor in cache\n");
1636 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1639 return (cacheentry);
1643 * Retrieve a security attribute from $Secure
1646 static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id)
1661 ntfs_index_context *xsii;
1664 securattr = (char*)NULL;
1665 ni = vol->secure_ni;
1666 xsii = vol->secure_xsii;
1668 ntfs_index_ctx_reinit(xsii);
1670 !ntfs_index_lookup((char*)&id,
1671 sizeof(SII_INDEX_KEY), xsii);
1673 psii = (struct SII*)xsii->entry;
1675 (size_t) le32_to_cpu(psii->datasize)
1676 - sizeof(SECURITY_DESCRIPTOR_HEADER);
1677 /* work around bad alignment problem */
1678 realign.parts.dataoffsh = psii->dataoffsh;
1679 realign.parts.dataoffsl = psii->dataoffsl;
1680 offs = le64_to_cpu(realign.all)
1681 + sizeof(SECURITY_DESCRIPTOR_HEADER);
1683 securattr = (char*)ntfs_malloc(size);
1685 rdsize = ntfs_attr_data_read(
1687 securattr, size, offs);
1688 if ((rdsize != size)
1689 || !ntfs_valid_descr(securattr,
1691 /* error to be logged by caller */
1693 securattr = (char*)NULL;
1697 if (errno != ENOENT)
1698 ntfs_log_perror("Inconsistency in index $SII");
1701 ntfs_log_error("Failed to retrieve a security descriptor\n");
1708 * Get the security descriptor associated to a file
1711 * - read the security descriptor attribute (v1.x format)
1712 * - or find the descriptor in $Secure:$SDS (v3.x format)
1714 * in both case, sanity checks are done on the attribute and
1715 * the descriptor can be assumed safe
1717 * The returned descriptor is dynamically allocated and has to be freed
1720 static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni)
1722 SII_INDEX_KEY securid;
1727 * Warning : in some situations, after fixing by chkdsk,
1728 * v3_Extensions are marked present (long standard informations)
1729 * with a default security descriptor inserted in an
1732 if (test_nino_flag(ni, v3_Extensions)
1733 && vol->secure_ni && ni->security_id) {
1734 /* get v3.x descriptor in $Secure */
1735 securid.security_id = ni->security_id;
1736 securattr = retrievesecurityattr(vol,securid);
1738 ntfs_log_error("Bad security descriptor for 0x%lx\n",
1739 (long)le32_to_cpu(ni->security_id));
1741 /* get v1.x security attribute */
1743 securattr = ntfs_attr_readall(ni, AT_SECURITY_DESCRIPTOR,
1744 AT_UNNAMED, 0, &readallsz);
1745 if (securattr && !ntfs_valid_descr(securattr, readallsz)) {
1746 ntfs_log_error("Bad security descriptor for inode %lld\n",
1747 (long long)ni->mft_no);
1749 securattr = (char*)NULL;
1754 * in some situations, there is no security
1755 * descriptor, and chkdsk does not detect or fix
1756 * anything. This could be a normal situation.
1757 * When this happens, simulate a descriptor with
1758 * minimum rights, so that a real descriptor can
1759 * be created by chown or chmod
1761 ntfs_log_error("No security descriptor found for inode %lld\n",
1762 (long long)ni->mft_no);
1763 securattr = ntfs_build_descr(0, 0, adminsid, adminsid);
1771 * Determine which access types to a file are allowed
1772 * according to the relation of current process to the file
1774 * Do not call if default_permissions is set
1777 static int access_check_posix(struct SECURITY_CONTEXT *scx,
1778 struct POSIX_SECURITY *pxdesc, mode_t request,
1779 uid_t uid, gid_t gid)
1781 struct POSIX_ACE *pxace;
1790 perms = pxdesc->mode;
1791 /* owner and root access */
1792 if (!scx->uid || (uid == scx->uid)) {
1794 /* root access if owner or other execution */
1798 /* root access if some group execution */
1801 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1802 pxace = &pxdesc->acl.ace[i];
1803 switch (pxace->tag) {
1804 case POSIX_ACL_USER_OBJ :
1805 case POSIX_ACL_GROUP_OBJ :
1806 case POSIX_ACL_GROUP :
1807 groupperms |= pxace->perms;
1809 case POSIX_ACL_MASK :
1810 mask = pxace->perms & 7;
1816 perms = (groupperms & mask & 1) | 6;
1822 * analyze designated users, get mask
1823 * and identify whether we need to check
1824 * the group memberships. The groups are
1825 * not needed when all groups have the
1826 * same permissions as other for the
1833 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1834 pxace = &pxdesc->acl.ace[i];
1835 switch (pxace->tag) {
1836 case POSIX_ACL_USER :
1837 if ((uid_t)pxace->id == scx->uid)
1838 userperms = pxace->perms;
1840 case POSIX_ACL_MASK :
1841 mask = pxace->perms & 7;
1843 case POSIX_ACL_GROUP_OBJ :
1844 case POSIX_ACL_GROUP :
1845 if (((pxace->perms & mask) ^ perms)
1846 & (request >> 6) & 7)
1853 /* designated users */
1855 perms = (perms & 07000) + (userperms & mask);
1856 else if (!needgroups)
1860 if (!(~(perms >> 3) & request & mask)
1861 && ((gid == scx->gid)
1862 || groupmember(scx, scx->uid, gid)))
1868 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1869 pxace = &pxdesc->acl.ace[i];
1870 if ((pxace->tag == POSIX_ACL_GROUP)
1871 && groupmember(scx, uid, pxace->id)) {
1872 if (!(~pxace->perms & request & mask))
1873 groupperms = pxace->perms;
1877 if (groupperms >= 0)
1878 perms = (perms & 07000) + (groupperms & mask);
1891 * Get permissions to access a file
1892 * Takes into account the relation of user to file (owner, group, ...)
1893 * Do no use as mode of the file
1894 * Do no call if default_permissions is set
1896 * returns -1 if there is a problem
1899 static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
1900 ntfs_inode * ni, mode_t request)
1902 const SECURITY_DESCRIPTOR_RELATIVE *phead;
1903 const struct CACHED_PERMISSIONS *cached;
1905 const SID *usid; /* owner of file/directory */
1906 const SID *gsid; /* group of file/directory */
1911 struct POSIX_SECURITY *pxdesc;
1913 if (!scx->mapping[MAPUSERS])
1916 /* check whether available in cache */
1917 cached = fetch_cache(scx,ni);
1921 perm = access_check_posix(scx,cached->pxdesc,request,uid,gid);
1923 perm = 0; /* default to no permission */
1924 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
1925 != const_cpu_to_le16(0);
1926 securattr = getsecurityattr(scx->vol, ni);
1928 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
1930 gsid = (const SID*)&
1931 securattr[le32_to_cpu(phead->group)];
1932 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
1934 usid = ntfs_acl_owner(securattr);
1935 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
1938 perm = pxdesc->mode & 07777;
1941 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
1943 usid = (const SID*)&
1944 securattr[le32_to_cpu(phead->owner)];
1945 pxdesc = ntfs_build_permissions_posix(scx,securattr,
1948 perm = pxdesc->mode & 07777;
1951 if (!perm && ntfs_same_sid(usid, adminsid)) {
1952 uid = find_tenant(scx, securattr);
1956 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
1959 * Create a security id if there were none
1960 * and upgrade option is selected
1962 if (!test_nino_flag(ni, v3_Extensions)
1964 && (scx->vol->secure_flags
1965 & (1 << SECURITY_ADDSECURIDS))) {
1966 upgrade_secur_desc(scx->vol,
1969 * fetch owner and group for cacheing
1970 * if there is a securid
1973 if (test_nino_flag(ni, v3_Extensions)
1975 enter_cache(scx, ni, uid,
1979 perm = access_check_posix(scx,pxdesc,request,uid,gid);
1995 * returns size or -errno if there is a problem
1996 * if size was too small, no copy is done and errno is not set,
1997 * the caller is expected to issue a new call
2000 int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2001 const char *name, char *value, size_t size)
2003 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2004 struct POSIX_SECURITY *pxdesc;
2005 const struct CACHED_PERMISSIONS *cached;
2007 const SID *usid; /* owner of file/directory */
2008 const SID *gsid; /* group of file/directory */
2014 outsize = 0; /* default to error */
2015 if (!scx->mapping[MAPUSERS])
2018 /* check whether available in cache */
2019 cached = fetch_cache(scx,ni);
2021 pxdesc = cached->pxdesc;
2023 securattr = getsecurityattr(scx->vol, ni);
2024 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2025 != const_cpu_to_le16(0);
2028 (const SECURITY_DESCRIPTOR_RELATIVE*)
2030 gsid = (const SID*)&
2031 securattr[le32_to_cpu(phead->group)];
2033 usid = ntfs_acl_owner(securattr);
2035 usid = (const SID*)&
2036 securattr[le32_to_cpu(phead->owner)];
2038 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2042 * fetch owner and group for cacheing
2046 * Create a security id if there were none
2047 * and upgrade option is selected
2049 if (!test_nino_flag(ni, v3_Extensions)
2050 && (scx->vol->secure_flags
2051 & (1 << SECURITY_ADDSECURIDS))) {
2052 upgrade_secur_desc(scx->vol,
2056 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2058 if (!(pxdesc->mode & 07777)
2059 && ntfs_same_sid(usid, adminsid)) {
2060 uid = find_tenant(scx,
2063 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2065 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2066 if (pxdesc->tagsset & POSIX_ACL_EXTENSIONS)
2067 enter_cache(scx, ni, uid,
2072 pxdesc = (struct POSIX_SECURITY*)NULL;
2076 if (ntfs_valid_posix(pxdesc)) {
2077 if (!strcmp(name,"system.posix_acl_default")) {
2079 & MFT_RECORD_IS_DIRECTORY)
2080 outsize = sizeof(struct POSIX_ACL)
2081 + pxdesc->defcnt*sizeof(struct POSIX_ACE);
2084 * getting default ACL from plain file :
2085 * return EACCES if size > 0 as
2086 * indicated in the man, but return ok
2087 * if size == 0, so that ls does not
2094 outsize = sizeof(struct POSIX_ACL);
2096 if (outsize && (outsize <= size)) {
2097 memcpy(value,&pxdesc->acl,sizeof(struct POSIX_ACL));
2098 memcpy(&value[sizeof(struct POSIX_ACL)],
2099 &pxdesc->acl.ace[pxdesc->firstdef],
2100 outsize-sizeof(struct POSIX_ACL));
2103 outsize = sizeof(struct POSIX_ACL)
2104 + pxdesc->acccnt*sizeof(struct POSIX_ACE);
2105 if (outsize <= size)
2106 memcpy(value,&pxdesc->acl,outsize);
2111 ntfs_log_error("Invalid Posix ACL built\n");
2118 return (outsize ? (int)outsize : -errno);
2121 #else /* POSIXACLS */
2125 * Get permissions to access a file
2126 * Takes into account the relation of user to file (owner, group, ...)
2127 * Do no use as mode of the file
2129 * returns -1 if there is a problem
2132 static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
2133 ntfs_inode *ni, mode_t request)
2135 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2136 const struct CACHED_PERMISSIONS *cached;
2138 const SID *usid; /* owner of file/directory */
2139 const SID *gsid; /* group of file/directory */
2145 if (!scx->mapping[MAPUSERS] || (!scx->uid && !(request & S_IEXEC)))
2148 /* check whether available in cache */
2149 cached = fetch_cache(scx,ni);
2151 perm = cached->mode;
2155 perm = 0; /* default to no permission */
2156 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2157 != const_cpu_to_le16(0);
2158 securattr = getsecurityattr(scx->vol, ni);
2160 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2162 gsid = (const SID*)&
2163 securattr[le32_to_cpu(phead->group)];
2164 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2166 usid = ntfs_acl_owner(securattr);
2167 perm = ntfs_build_permissions(securattr,
2169 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2171 usid = (const SID*)&
2172 securattr[le32_to_cpu(phead->owner)];
2173 perm = ntfs_build_permissions(securattr,
2175 if (!perm && ntfs_same_sid(usid, adminsid)) {
2176 uid = find_tenant(scx, securattr);
2180 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2183 * Create a security id if there were none
2184 * and upgrade option is selected
2186 if (!test_nino_flag(ni, v3_Extensions)
2188 && (scx->vol->secure_flags
2189 & (1 << SECURITY_ADDSECURIDS))) {
2190 upgrade_secur_desc(scx->vol,
2193 * fetch owner and group for cacheing
2194 * if there is a securid
2197 if (test_nino_flag(ni, v3_Extensions)
2199 enter_cache(scx, ni, uid,
2210 /* root access and execution */
2216 if (uid == scx->uid)
2220 * avoid checking group membership
2221 * when the requested perms for group
2222 * are the same as perms for other
2224 if ((gid == scx->gid)
2225 || ((((perm >> 3) ^ perm)
2226 & (request >> 6) & 7)
2227 && groupmember(scx, scx->uid, gid)))
2236 #endif /* POSIXACLS */
2241 * Returns size or -errno if there is a problem
2242 * if size was too small, no copy is done and errno is not set,
2243 * the caller is expected to issue a new call
2246 int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2247 char *value, size_t size)
2252 outsize = 0; /* default to no data and no error */
2253 securattr = getsecurityattr(scx->vol, ni);
2255 outsize = ntfs_attr_size(securattr);
2256 if (outsize <= size) {
2257 memcpy(value,securattr,outsize);
2261 return (outsize ? (int)outsize : -errno);
2265 * Get owner, group and permissions in an stat structure
2266 * returns permissions, or -1 if there is a problem
2269 int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
2270 ntfs_inode * ni, struct stat *stbuf)
2272 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2274 const SID *usid; /* owner of file/directory */
2275 const SID *gsid; /* group of file/directory */
2276 const struct CACHED_PERMISSIONS *cached;
2280 struct POSIX_SECURITY *pxdesc;
2283 if (!scx->mapping[MAPUSERS])
2286 /* check whether available in cache */
2287 cached = fetch_cache(scx,ni);
2289 perm = cached->mode;
2290 stbuf->st_uid = cached->uid;
2291 stbuf->st_gid = cached->gid;
2292 stbuf->st_mode = (stbuf->st_mode & ~07777) + perm;
2294 perm = -1; /* default to error */
2295 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2296 != const_cpu_to_le16(0);
2297 securattr = getsecurityattr(scx->vol, ni);
2300 (const SECURITY_DESCRIPTOR_RELATIVE*)
2302 gsid = (const SID*)&
2303 securattr[le32_to_cpu(phead->group)];
2305 usid = ntfs_acl_owner(securattr);
2307 usid = (const SID*)&
2308 securattr[le32_to_cpu(phead->owner)];
2311 pxdesc = ntfs_build_permissions_posix(scx->mapping, securattr,
2314 perm = pxdesc->mode & 07777;
2318 perm = ntfs_build_permissions(securattr,
2322 * fetch owner and group for cacheing
2326 * Create a security id if there were none
2327 * and upgrade option is selected
2329 if (!test_nino_flag(ni, v3_Extensions)
2330 && (scx->vol->secure_flags
2331 & (1 << SECURITY_ADDSECURIDS))) {
2332 upgrade_secur_desc(scx->vol,
2336 stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2338 if (!perm && ntfs_same_sid(usid, adminsid)) {
2345 stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2347 stbuf->st_gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2349 (stbuf->st_mode & ~07777) + perm;
2351 enter_cache(scx, ni, stbuf->st_uid,
2352 stbuf->st_gid, pxdesc);
2355 enter_cache(scx, ni, stbuf->st_uid,
2356 stbuf->st_gid, perm);
2369 * Get the base for a Posix inheritance and
2370 * build an inherited Posix descriptor
2373 static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx,
2374 ntfs_inode *dir_ni, mode_t mode, BOOL isdir)
2376 const struct CACHED_PERMISSIONS *cached;
2377 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2378 struct POSIX_SECURITY *pxdesc;
2379 struct POSIX_SECURITY *pydesc;
2386 pydesc = (struct POSIX_SECURITY*)NULL;
2387 /* check whether parent directory is available in cache */
2388 cached = fetch_cache(scx,dir_ni);
2392 pxdesc = cached->pxdesc;
2394 pydesc = ntfs_build_inherited_posix(pxdesc,mode,
2398 securattr = getsecurityattr(scx->vol, dir_ni);
2400 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2402 gsid = (const SID*)&
2403 securattr[le32_to_cpu(phead->group)];
2404 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2406 usid = ntfs_acl_owner(securattr);
2407 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2409 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2411 usid = (const SID*)&
2412 securattr[le32_to_cpu(phead->owner)];
2413 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2415 if (pxdesc && ntfs_same_sid(usid, adminsid)) {
2416 uid = find_tenant(scx, securattr);
2418 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2422 * Create a security id if there were none
2423 * and upgrade option is selected
2425 if (!test_nino_flag(dir_ni, v3_Extensions)
2426 && (scx->vol->secure_flags
2427 & (1 << SECURITY_ADDSECURIDS))) {
2428 upgrade_secur_desc(scx->vol,
2431 * fetch owner and group for cacheing
2432 * if there is a securid
2435 if (test_nino_flag(dir_ni, v3_Extensions)) {
2436 enter_cache(scx, dir_ni, uid,
2439 pydesc = ntfs_build_inherited_posix(pxdesc,
2440 mode, scx->umask, isdir);
2450 * Allocate a security_id for a file being created
2452 * Returns zero if not possible (NTFS v3.x required)
2455 le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
2456 uid_t uid, gid_t gid, ntfs_inode *dir_ni,
2457 mode_t mode, BOOL isdir)
2459 #if !FORCE_FORMAT_v1x
2460 const struct CACHED_SECURID *cached;
2461 struct CACHED_SECURID wanted;
2462 struct POSIX_SECURITY *pxdesc;
2472 securid = const_cpu_to_le32(0);
2474 #if !FORCE_FORMAT_v1x
2476 pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
2478 /* check whether target securid is known in cache */
2482 wanted.dmode = pxdesc->mode & mode & 07777;
2483 if (isdir) wanted.dmode |= 0x10000;
2484 wanted.variable = (void*)pxdesc;
2485 wanted.varsize = sizeof(struct POSIX_SECURITY)
2486 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2487 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2488 scx->vol->securid_cache, GENERIC(&wanted),
2489 (cache_compare)compare);
2490 /* quite simple, if we are lucky */
2492 securid = cached->securid;
2494 /* not in cache : make sure we can create ids */
2496 if (!cached && (scx->vol->major_ver >= 3)) {
2497 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2498 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2499 if (!usid || !gsid) {
2500 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2501 (int)uid, (int)gid);
2502 usid = gsid = adminsid;
2504 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2507 newattrsz = ntfs_attr_size(newattr);
2508 securid = setsecurityattr(scx->vol,
2509 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
2512 /* update cache, for subsequent use */
2513 wanted.securid = securid;
2514 ntfs_enter_cache(scx->vol->securid_cache,
2516 (cache_compare)compare);
2521 * could not build new security attribute
2522 * errno set by ntfs_build_descr()
2533 * Apply Posix inheritance to a newly created file
2534 * (for NTFS 1.x only : no securid)
2537 int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
2538 ntfs_inode *ni, uid_t uid, gid_t gid,
2539 ntfs_inode *dir_ni, mode_t mode)
2541 struct POSIX_SECURITY *pxdesc;
2551 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2552 pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
2554 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2555 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2556 if (!usid || !gsid) {
2557 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2558 (int)uid, (int)gid);
2559 usid = gsid = adminsid;
2561 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2564 /* Adjust Windows read-only flag */
2565 res = update_secur_descr(scx->vol, newattr, ni);
2566 if (!res && !isdir) {
2568 ni->flags &= ~FILE_ATTR_READONLY;
2570 ni->flags |= FILE_ATTR_READONLY;
2572 #if CACHE_LEGACY_SIZE
2573 /* also invalidate legacy cache */
2574 if (isdir && !ni->security_id) {
2575 struct CACHED_PERMISSIONS_LEGACY legacy;
2577 legacy.mft_no = ni->mft_no;
2578 legacy.variable = pxdesc;
2579 legacy.varsize = sizeof(struct POSIX_SECURITY)
2580 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2581 ntfs_invalidate_cache(scx->vol->legacy_cache,
2583 (cache_compare)leg_compare,0);
2590 * could not build new security attribute
2591 * errno set by ntfs_build_descr()
2600 le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
2601 uid_t uid, gid_t gid, mode_t mode, BOOL isdir)
2603 #if !FORCE_FORMAT_v1x
2604 const struct CACHED_SECURID *cached;
2605 struct CACHED_SECURID wanted;
2615 securid = const_cpu_to_le32(0);
2617 #if !FORCE_FORMAT_v1x
2618 /* check whether target securid is known in cache */
2622 wanted.dmode = mode & 07777;
2623 if (isdir) wanted.dmode |= 0x10000;
2624 wanted.variable = (void*)NULL;
2626 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2627 scx->vol->securid_cache, GENERIC(&wanted),
2628 (cache_compare)compare);
2629 /* quite simple, if we are lucky */
2631 securid = cached->securid;
2633 /* not in cache : make sure we can create ids */
2635 if (!cached && (scx->vol->major_ver >= 3)) {
2636 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2637 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2638 if (!usid || !gsid) {
2639 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2640 (int)uid, (int)gid);
2641 usid = gsid = adminsid;
2643 newattr = ntfs_build_descr(mode, isdir, usid, gsid);
2645 newattrsz = ntfs_attr_size(newattr);
2646 securid = setsecurityattr(scx->vol,
2647 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
2650 /* update cache, for subsequent use */
2651 wanted.securid = securid;
2652 ntfs_enter_cache(scx->vol->securid_cache,
2654 (cache_compare)compare);
2659 * could not build new security attribute
2660 * errno set by ntfs_build_descr()
2671 * Update ownership and mode of a file, reusing an existing
2672 * security descriptor when possible
2674 * Returns zero if successful
2678 int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2679 uid_t uid, gid_t gid, mode_t mode,
2680 struct POSIX_SECURITY *pxdesc)
2682 int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2683 uid_t uid, gid_t gid, mode_t mode)
2687 const struct CACHED_SECURID *cached;
2688 struct CACHED_SECURID wanted;
2698 /* check whether target securid is known in cache */
2700 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2703 wanted.dmode = mode & 07777;
2704 if (isdir) wanted.dmode |= 0x10000;
2706 wanted.variable = (void*)pxdesc;
2708 wanted.varsize = sizeof(struct POSIX_SECURITY)
2709 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2713 wanted.variable = (void*)NULL;
2716 if (test_nino_flag(ni, v3_Extensions)) {
2717 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2718 scx->vol->securid_cache, GENERIC(&wanted),
2719 (cache_compare)compare);
2720 /* quite simple, if we are lucky */
2722 ni->security_id = cached->securid;
2725 } else cached = (struct CACHED_SECURID*)NULL;
2729 * Do not use usid and gsid from former attributes,
2730 * but recompute them to get repeatable results
2731 * which can be kept in cache.
2733 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2734 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2735 if (!usid || !gsid) {
2736 ntfs_log_error("File made owned by an unmapped user/group %d/%d\n",
2738 usid = gsid = adminsid;
2742 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2745 newattr = ntfs_build_descr(mode,
2748 newattr = ntfs_build_descr(mode,
2752 res = update_secur_descr(scx->vol, newattr, ni);
2754 /* adjust Windows read-only flag */
2757 ni->flags &= ~FILE_ATTR_READONLY;
2759 ni->flags |= FILE_ATTR_READONLY;
2760 NInoFileNameSetDirty(ni);
2762 /* update cache, for subsequent use */
2763 if (test_nino_flag(ni, v3_Extensions)) {
2764 wanted.securid = ni->security_id;
2765 ntfs_enter_cache(scx->vol->securid_cache,
2767 (cache_compare)compare);
2769 #if CACHE_LEGACY_SIZE
2770 /* also invalidate legacy cache */
2771 if (isdir && !ni->security_id) {
2772 struct CACHED_PERMISSIONS_LEGACY legacy;
2774 legacy.mft_no = ni->mft_no;
2776 legacy.variable = wanted.variable;
2777 legacy.varsize = wanted.varsize;
2779 legacy.variable = (void*)NULL;
2782 ntfs_invalidate_cache(scx->vol->legacy_cache,
2784 (cache_compare)leg_compare,0);
2791 * could not build new security attribute
2792 * errno set by ntfs_build_descr()
2801 * Check whether user has ownership rights on a file
2803 * Returns TRUE if allowed
2804 * if not, errno tells why
2807 BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni)
2809 const struct CACHED_PERMISSIONS *cached;
2817 processuid = scx->uid;
2818 /* TODO : use CAP_FOWNER process capability */
2820 * Always allow for root
2821 * Also always allow if no mapping has been defined
2823 if (!scx->mapping[MAPUSERS] || !processuid)
2826 gotowner = FALSE; /* default */
2827 /* get the owner, either from cache or from old attribute */
2828 cached = fetch_cache(scx, ni);
2833 oldattr = getsecurityattr(scx->vol, ni);
2836 usid = ntfs_acl_owner(oldattr);
2838 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2840 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2842 usid = (const SID*)&oldattr
2843 [le32_to_cpu(phead->owner)];
2845 uid = ntfs_find_user(scx->mapping[MAPUSERS],
2853 /* TODO : use CAP_FOWNER process capability */
2854 if (!processuid || (processuid == uid))
2863 #ifdef HAVE_SETXATTR /* extended attributes interface required */
2868 * Set a new access or default Posix ACL to a file
2869 * (or remove ACL if no input data)
2870 * Validity of input data is checked after merging
2872 * Returns 0, or -1 if there is a problem which errno describes
2875 int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2876 const char *name, const char *value, size_t size,
2879 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2880 const struct CACHED_PERMISSIONS *cached;
2892 struct POSIX_SECURITY *oldpxdesc;
2893 struct POSIX_SECURITY *newpxdesc;
2895 /* get the current pxsec, either from cache or from old attribute */
2897 deflt = !strcmp(name,"system.posix_acl_default");
2899 count = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE);
2902 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2903 newpxdesc = (struct POSIX_SECURITY*)NULL;
2905 || (((const struct POSIX_ACL*)value)->version == POSIX_VERSION))
2906 && (!deflt || isdir || (!size && !value))) {
2907 cached = fetch_cache(scx, ni);
2911 oldpxdesc = cached->pxdesc;
2913 newpxdesc = ntfs_replace_acl(oldpxdesc,
2914 (const struct POSIX_ACL*)value,count,deflt);
2917 oldattr = getsecurityattr(scx->vol, ni);
2919 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
2921 usid = ntfs_acl_owner(oldattr);
2923 usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
2925 gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
2926 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2927 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2928 oldpxdesc = ntfs_build_permissions_posix(scx->mapping,
2929 oldattr, usid, gsid, isdir);
2932 exist = oldpxdesc->defcnt > 0;
2934 exist = oldpxdesc->acccnt > 3;
2935 if ((exist && (flags & XATTR_CREATE))
2936 || (!exist && (flags & XATTR_REPLACE))) {
2937 errno = (exist ? EEXIST : ENODATA);
2939 newpxdesc = ntfs_replace_acl(oldpxdesc,
2940 (const struct POSIX_ACL*)value,count,deflt);
2951 processuid = scx->uid;
2952 /* TODO : use CAP_FOWNER process capability */
2953 if (!processuid || (uid == processuid)) {
2955 * clear setgid if file group does
2956 * not match process group
2958 if (processuid && (gid != scx->gid)
2959 && !groupmember(scx, scx->uid, gid)) {
2960 newpxdesc->mode &= ~S_ISGID;
2962 res = ntfs_set_owner_mode(scx, ni, uid, gid,
2963 newpxdesc->mode, newpxdesc);
2968 return (res ? -1 : 0);
2972 * Remove a default Posix ACL from a file
2974 * Returns 0, or -1 if there is a problem which errno describes
2977 int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2980 return (ntfs_set_posix_acl(scx, ni, name,
2981 (const char*)NULL, 0, 0));
2987 * Set a new NTFS ACL to a file
2989 * Returns 0, or -1 if there is a problem
2992 int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2993 const char *value, size_t size, int flags)
3000 && !(flags & XATTR_CREATE)
3001 && ntfs_valid_descr(value,size)
3002 && (ntfs_attr_size(value) == size)) {
3003 /* need copying in order to write */
3004 attr = (char*)ntfs_malloc(size);
3006 memcpy(attr,value,size);
3007 res = update_secur_descr(scx->vol, attr, ni);
3009 * No need to invalidate standard caches :
3010 * the relation between a securid and
3011 * the associated protection is unchanged,
3012 * only the relation between a file and
3013 * its securid and protection is changed.
3015 #if CACHE_LEGACY_SIZE
3017 * we must however invalidate the legacy
3018 * cache, which is based on inode numbers.
3019 * For safety, invalidate even if updating
3022 if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3023 && !ni->security_id) {
3024 struct CACHED_PERMISSIONS_LEGACY legacy;
3026 legacy.mft_no = ni->mft_no;
3027 legacy.variable = (char*)NULL;
3029 ntfs_invalidate_cache(scx->vol->legacy_cache,
3031 (cache_compare)leg_compare,0);
3039 return (res ? -1 : 0);
3042 #endif /* HAVE_SETXATTR */
3045 * Set new permissions to a file
3046 * Checks user mapping has been defined before request for setting
3048 * rejected if request is not originated by owner or root
3050 * returns 0 on success
3051 * -1 on failure, with errno = EIO
3054 int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode)
3056 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3057 const struct CACHED_PERMISSIONS *cached;
3068 const struct POSIX_SECURITY *oldpxdesc;
3069 struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
3072 /* get the current owner, either from cache or from old attribute */
3074 cached = fetch_cache(scx, ni);
3079 oldpxdesc = cached->pxdesc;
3081 /* must copy before merging */
3082 pxsize = sizeof(struct POSIX_SECURITY)
3083 + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
3084 newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
3086 memcpy(newpxdesc, oldpxdesc, pxsize);
3087 if (ntfs_merge_mode_posix(newpxdesc, mode))
3092 newpxdesc = (struct POSIX_SECURITY*)NULL;
3095 oldattr = getsecurityattr(scx->vol, ni);
3097 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
3099 usid = ntfs_acl_owner(oldattr);
3101 usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
3103 gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
3104 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3105 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3107 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
3108 newpxdesc = ntfs_build_permissions_posix(scx->mapping,
3109 oldattr, usid, gsid, isdir);
3110 if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
3119 processuid = scx->uid;
3120 /* TODO : use CAP_FOWNER process capability */
3121 if (!processuid || (uid == processuid)) {
3123 * clear setgid if file group does
3124 * not match process group
3126 if (processuid && (gid != scx->gid)
3127 && !groupmember(scx, scx->uid, gid))
3131 newpxdesc->mode = mode;
3132 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3135 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3138 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3142 res = -1; /* neither owner nor root */
3146 * Should not happen : a default descriptor is generated
3147 * by getsecurityattr() when there are none
3149 ntfs_log_error("File has no security descriptor\n");
3154 if (newpxdesc) free(newpxdesc);
3156 return (res ? -1 : 0);
3160 * Create a default security descriptor for files whose descriptor
3161 * cannot be inherited
3164 int ntfs_sd_add_everyone(ntfs_inode *ni)
3166 /* JPA SECURITY_DESCRIPTOR_ATTR *sd; */
3167 SECURITY_DESCRIPTOR_RELATIVE *sd;
3169 ACCESS_ALLOWED_ACE *ace;
3173 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
3175 * Calculate security descriptor length. We have 2 sub-authorities in
3176 * owner and group SIDs, but structure SID contain only one, so add
3177 * 4 bytes to every SID.
3179 sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
3180 sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
3181 sd = (SECURITY_DESCRIPTOR_RELATIVE*)ntfs_calloc(sd_len);
3185 sd->revision = SECURITY_DESCRIPTOR_REVISION;
3186 sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
3188 sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
3189 sid->revision = SID_REVISION;
3190 sid->sub_authority_count = 2;
3191 sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
3192 sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
3193 sid->identifier_authority.value[5] = 5;
3194 sd->owner = cpu_to_le32((u8*)sid - (u8*)sd);
3196 sid = (SID*)((u8*)sid + sizeof(SID) + 4);
3197 sid->revision = SID_REVISION;
3198 sid->sub_authority_count = 2;
3199 sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
3200 sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
3201 sid->identifier_authority.value[5] = 5;
3202 sd->group = cpu_to_le32((u8*)sid - (u8*)sd);
3204 acl = (ACL*)((u8*)sid + sizeof(SID) + 4);
3205 acl->revision = ACL_REVISION;
3206 acl->size = const_cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
3207 acl->ace_count = const_cpu_to_le16(1);
3208 sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd);
3210 ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL));
3211 ace->type = ACCESS_ALLOWED_ACE_TYPE;
3212 ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
3213 ace->size = const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
3214 ace->mask = const_cpu_to_le32(0x1f01ff); /* FIXME */
3215 ace->sid.revision = SID_REVISION;
3216 ace->sid.sub_authority_count = 1;
3217 ace->sid.sub_authority[0] = const_cpu_to_le32(0);
3218 ace->sid.identifier_authority.value[5] = 1;
3220 ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8*)sd,
3223 ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR");
3230 * Check whether user can access a file in a specific way
3232 * Returns 1 if access is allowed, including user is root or no
3233 * user mapping defined
3234 * 2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX
3235 * 0 and sets errno if there is a problem or if access
3238 * This is used for Posix ACL and checking creation of DOS file names
3241 int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
3243 int accesstype) /* access type required (S_Ixxx values) */
3251 * Always allow for root unless execution is requested.
3252 * (was checked by fuse until kernel 2.6.29)
3253 * Also always allow if no mapping has been defined
3255 if (!scx->mapping[MAPUSERS]
3257 && (!(accesstype & S_IEXEC)
3258 || (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY))))
3261 perm = ntfs_get_perm(scx, ni, accesstype);
3264 switch (accesstype) {
3266 allow = (perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
3269 allow = (perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0;
3271 case S_IWRITE + S_IEXEC:
3272 allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3273 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3276 allow = (perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0;
3278 case S_IREAD + S_IEXEC:
3279 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3280 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3282 case S_IREAD + S_IWRITE:
3283 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3284 && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0);
3286 case S_IWRITE + S_IEXEC + S_ISVTX:
3287 if (perm & S_ISVTX) {
3288 if ((ntfs_get_owner_mode(scx,ni,&stbuf) >= 0)
3289 && (stbuf.st_uid == scx->uid))
3294 allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3295 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3297 case S_IREAD + S_IWRITE + S_IEXEC:
3298 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3299 && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3300 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3315 #if 0 /* not needed any more */
3318 * Check whether user can access the parent directory
3319 * of a file in a specific way
3321 * Returns true if access is allowed, including user is root and
3322 * no user mapping defined
3324 * Sets errno if there is a problem or if not allowed
3326 * This is used for Posix ACL and checking creation of DOS file names
3329 BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
3330 const char *path, int accesstype)
3340 dirpath = strdup(path);
3342 /* the root of file system is seen as a parent of itself */
3343 /* is that correct ? */
3344 name = strrchr(dirpath, '/');
3346 dir_ni = ntfs_pathname_to_inode(scx->vol, NULL, dirpath);
3348 allow = ntfs_allowed_access(scx,
3349 dir_ni, accesstype);
3350 ntfs_inode_close(dir_ni);
3352 * for an not-owned sticky directory, have to
3353 * check whether file itself is owned
3355 if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX))
3357 ni = ntfs_pathname_to_inode(scx->vol, NULL,
3361 allow = (ntfs_get_owner_mode(scx,ni,&stbuf) >= 0)
3362 && (stbuf.st_uid == scx->uid);
3363 ntfs_inode_close(ni);
3369 return (allow); /* errno is set if not allowed */
3375 * Define a new owner/group to a file
3377 * returns zero if successful
3380 int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
3381 uid_t uid, gid_t gid)
3383 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3384 const struct CACHED_PERMISSIONS *cached;
3395 struct POSIX_SECURITY *pxdesc;
3396 BOOL pxdescbuilt = FALSE;
3400 /* get the current owner and mode from cache or security attributes */
3401 oldattr = (char*)NULL;
3402 cached = fetch_cache(scx,ni);
3404 fileuid = cached->uid;
3405 filegid = cached->gid;
3406 mode = cached->mode;
3408 pxdesc = cached->pxdesc;
3416 oldattr = getsecurityattr(scx->vol, ni);
3418 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3419 != const_cpu_to_le16(0);
3420 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
3423 &oldattr[le32_to_cpu(phead->group)];
3425 usid = ntfs_acl_owner(oldattr);
3428 &oldattr[le32_to_cpu(phead->owner)];
3431 pxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
3435 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3436 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3437 mode = perm = pxdesc->mode;
3441 mode = perm = ntfs_build_permissions(oldattr,
3444 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3445 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3454 /* check requested by root */
3455 /* or chgrp requested by owner to an owned group */
3457 || ((((int)uid < 0) || (uid == fileuid))
3458 && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
3459 && (fileuid == scx->uid))) {
3460 /* replace by the new usid and gsid */
3461 /* or reuse old gid and sid for cacheing */
3466 /* clear setuid and setgid if owner has changed */
3467 /* unless request originated by root */
3468 if (uid && (fileuid != uid))
3471 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3474 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3477 res = -1; /* neither owner nor root */
3486 * Should not happen : a default descriptor is generated
3487 * by getsecurityattr() when there are none
3489 ntfs_log_error("File has no security descriptor\n");
3493 return (res ? -1 : 0);
3497 * Define new owner/group and mode to a file
3499 * returns zero if successful
3502 int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
3503 uid_t uid, gid_t gid, const mode_t mode)
3505 const struct CACHED_PERMISSIONS *cached;
3511 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3515 const struct POSIX_SECURITY *oldpxdesc;
3516 struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
3521 /* get the current owner and mode from cache or security attributes */
3522 oldattr = (char*)NULL;
3523 cached = fetch_cache(scx,ni);
3525 fileuid = cached->uid;
3526 filegid = cached->gid;
3528 oldpxdesc = cached->pxdesc;
3530 /* must copy before merging */
3531 pxsize = sizeof(struct POSIX_SECURITY)
3532 + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
3533 newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
3535 memcpy(newpxdesc, oldpxdesc, pxsize);
3536 if (ntfs_merge_mode_posix(newpxdesc, mode))
3545 oldattr = getsecurityattr(scx->vol, ni);
3548 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3549 != const_cpu_to_le16(0);
3550 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
3553 &oldattr[le32_to_cpu(phead->group)];
3555 usid = ntfs_acl_owner(oldattr);
3558 &oldattr[le32_to_cpu(phead->owner)];
3560 newpxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
3562 if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
3565 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3566 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3574 /* check requested by root */
3575 /* or chgrp requested by owner to an owned group */
3577 || ((((int)uid < 0) || (uid == fileuid))
3578 && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
3579 && (fileuid == scx->uid))) {
3580 /* replace by the new usid and gsid */
3581 /* or reuse old gid and sid for cacheing */
3587 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3590 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3593 res = -1; /* neither owner nor root */
3598 * Should not happen : a default descriptor is generated
3599 * by getsecurityattr() when there are none
3601 ntfs_log_error("File has no security descriptor\n");
3608 return (res ? -1 : 0);
3612 * Build a security id for a descriptor inherited from
3613 * parent directory the Windows way
3616 static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
3617 const char *parentattr, BOOL fordir)
3619 const SECURITY_DESCRIPTOR_RELATIVE *pphead;
3628 SECURITY_DESCRIPTOR_RELATIVE *pnhead;
3639 parentattrsz = ntfs_attr_size(parentattr);
3640 pphead = (const SECURITY_DESCRIPTOR_RELATIVE*)parentattr;
3641 if (scx->mapping[MAPUSERS]) {
3642 usid = ntfs_find_usid(scx->mapping[MAPUSERS], scx->uid, (SID*)&defusid);
3643 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS], scx->gid, (SID*)&defgsid);
3650 * If there is no user mapping, we have to copy owner
3651 * and group from parent directory.
3652 * Windows never has to do that, because it can always
3653 * rely on a user mapping
3655 offowner = le32_to_cpu(pphead->owner);
3656 usid = (const SID*)&parentattr[offowner];
3657 offgroup = le32_to_cpu(pphead->group);
3658 gsid = (const SID*)&parentattr[offgroup];
3661 * new attribute is smaller than parent's
3662 * except for differences in SIDs which appear in
3663 * owner, group and possible grants and denials in
3664 * generic creator-owner and creator-group ACEs.
3665 * For directories, an ACE may be duplicated for
3666 * access and inheritance, so we double the count.
3668 usidsz = ntfs_sid_size(usid);
3669 gsidsz = ntfs_sid_size(gsid);
3670 newattrsz = parentattrsz + 3*usidsz + 3*gsidsz;
3673 newattr = (char*)ntfs_malloc(newattrsz);
3675 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr;
3676 pnhead->revision = SECURITY_DESCRIPTOR_REVISION;
3677 pnhead->alignment = 0;
3678 pnhead->control = SE_SELF_RELATIVE;
3679 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
3681 * locate and inherit DACL
3682 * do not test SE_DACL_PRESENT (wrong for "DR Watson")
3684 pnhead->dacl = const_cpu_to_le32(0);
3686 offpacl = le32_to_cpu(pphead->dacl);
3687 ppacl = (const ACL*)&parentattr[offpacl];
3688 pnacl = (ACL*)&newattr[pos];
3689 aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
3691 pnhead->dacl = cpu_to_le32(pos);
3693 pnhead->control |= SE_DACL_PRESENT;
3697 * locate and inherit SACL
3699 pnhead->sacl = const_cpu_to_le32(0);
3701 offpacl = le32_to_cpu(pphead->sacl);
3702 ppacl = (const ACL*)&parentattr[offpacl];
3703 pnacl = (ACL*)&newattr[pos];
3704 aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
3706 pnhead->sacl = cpu_to_le32(pos);
3708 pnhead->control |= SE_SACL_PRESENT;
3712 * inherit or redefine owner
3714 memcpy(&newattr[pos],usid,usidsz);
3715 pnhead->owner = cpu_to_le32(pos);
3718 * inherit or redefine group
3720 memcpy(&newattr[pos],gsid,gsidsz);
3721 pnhead->group = cpu_to_le32(pos);
3723 securid = setsecurityattr(scx->vol,
3724 (SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos);
3727 securid = const_cpu_to_le32(0);
3732 * Get an inherited security id
3734 * For Windows compatibility, the normal initial permission setting
3735 * may be inherited from the parent directory instead of being
3736 * defined by the creation arguments.
3738 * The following creates an inherited id for that purpose.
3740 * Note : the owner and group of parent directory are also
3741 * inherited (which is not the case on Windows) if no user mapping
3744 * Returns the inherited id, or zero if not possible (eg on NTFS 1.x)
3747 le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
3748 ntfs_inode *dir_ni, BOOL fordir)
3750 struct CACHED_PERMISSIONS *cached;
3754 securid = const_cpu_to_le32(0);
3755 cached = (struct CACHED_PERMISSIONS*)NULL;
3757 * Try to get inherited id from cache
3759 if (test_nino_flag(dir_ni, v3_Extensions)
3760 && dir_ni->security_id) {
3761 cached = fetch_cache(scx, dir_ni);
3763 securid = (fordir ? cached->inh_dirid
3764 : cached->inh_fileid);
3767 * Not cached or not available in cache, compute it all
3768 * Note : if parent directory has no id, it is not cacheable
3771 parentattr = getsecurityattr(scx->vol, dir_ni);
3773 securid = build_inherited_id(scx,
3774 parentattr, fordir);
3777 * Store the result into cache for further use
3780 cached = fetch_cache(scx, dir_ni);
3783 cached->inh_dirid = securid;
3785 cached->inh_fileid = securid;
3794 * Link a group to a member of group
3796 * Returns 0 if OK, -1 (and errno set) if error
3799 static int link_single_group(struct MAPPING *usermapping, struct passwd *user,
3802 struct group *group;
3809 group = getgrgid(gid);
3810 if (group && group->gr_mem) {
3811 grcnt = usermapping->grcnt;
3812 groups = usermapping->groups;
3813 grmem = group->gr_mem;
3814 while (*grmem && strcmp(user->pw_name, *grmem))
3818 groups = (gid_t*)malloc(sizeof(gid_t));
3820 groups = (gid_t*)realloc(groups,
3821 (grcnt+1)*sizeof(gid_t));
3823 groups[grcnt++] = gid;
3829 usermapping->grcnt = grcnt;
3830 usermapping->groups = groups;
3837 * Statically link group to users
3838 * This is based on groups defined in /etc/group and does not take
3839 * the groups dynamically set by setgroups() nor any changes in
3840 * /etc/group into account
3842 * Only mapped groups and root group are linked to mapped users
3844 * Returns 0 if OK, -1 (and errno set) if error
3848 static int link_group_members(struct SECURITY_CONTEXT *scx)
3850 struct MAPPING *usermapping;
3851 struct MAPPING *groupmapping;
3852 struct passwd *user;
3856 for (usermapping=scx->mapping[MAPUSERS]; usermapping && !res;
3857 usermapping=usermapping->next) {
3858 usermapping->grcnt = 0;
3859 usermapping->groups = (gid_t*)NULL;
3860 user = getpwuid(usermapping->xid);
3861 if (user && user->pw_name) {
3862 for (groupmapping=scx->mapping[MAPGROUPS];
3863 groupmapping && !res;
3864 groupmapping=groupmapping->next) {
3865 if (link_single_group(usermapping, user,
3869 if (!res && link_single_group(usermapping,
3878 * Apply default single user mapping
3879 * returns zero if successful
3882 static int ntfs_do_default_mapping(struct SECURITY_CONTEXT *scx,
3883 uid_t uid, gid_t gid, const SID *usid)
3885 struct MAPPING *usermapping;
3886 struct MAPPING *groupmapping;
3892 sidsz = ntfs_sid_size(usid);
3893 sid = (SID*)ntfs_malloc(sidsz);
3895 memcpy(sid,usid,sidsz);
3896 usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
3898 groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
3900 usermapping->sid = sid;
3901 usermapping->xid = uid;
3902 usermapping->next = (struct MAPPING*)NULL;
3903 groupmapping->sid = sid;
3904 groupmapping->xid = gid;
3905 groupmapping->next = (struct MAPPING*)NULL;
3906 scx->mapping[MAPUSERS] = usermapping;
3907 scx->mapping[MAPGROUPS] = groupmapping;
3916 * Make sure there are no ambiguous mapping
3917 * Ambiguous mapping may lead to undesired configurations and
3918 * we had rather be safe until the consequences are understood
3921 #if 0 /* not activated for now */
3923 static BOOL check_mapping(const struct MAPPING *usermapping,
3924 const struct MAPPING *groupmapping)
3926 const struct MAPPING *mapping1;
3927 const struct MAPPING *mapping2;
3931 for (mapping1=usermapping; mapping1; mapping1=mapping1->next)
3932 for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
3933 if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
3934 if (mapping1->xid != mapping2->xid)
3937 if (mapping1->xid == mapping2->xid)
3940 for (mapping1=groupmapping; mapping1; mapping1=mapping1->next)
3941 for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
3942 if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
3943 if (mapping1->xid != mapping2->xid)
3946 if (mapping1->xid == mapping2->xid)
3954 #if 0 /* not used any more */
3957 * Try and apply default single user mapping
3958 * returns zero if successful
3961 static int ntfs_default_mapping(struct SECURITY_CONTEXT *scx)
3963 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3970 ni = ntfs_pathname_to_inode(scx->vol, NULL, "/.");
3972 securattr = getsecurityattr(scx->vol, ni);
3974 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr;
3975 usid = (SID*)&securattr[le32_to_cpu(phead->owner)];
3976 if (ntfs_is_user_sid(usid))
3977 res = ntfs_do_default_mapping(scx,
3978 scx->uid, scx->gid, usid);
3981 ntfs_inode_close(ni);
3989 * Basic read from a user mapping file on another volume
3992 static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused)))
3994 return (read(*(int*)fileid, buf, size));
3999 * Read from a user mapping file on current NTFS partition
4002 static int localread(void *fileid, char *buf, size_t size, off_t offs)
4004 return (ntfs_attr_data_read((ntfs_inode*)fileid,
4005 AT_UNNAMED, 0, buf, size, offs));
4009 * Build the user mapping
4010 * - according to a mapping file if defined (or default present),
4011 * - or try default single user mapping if possible
4013 * The mapping is specific to a mounted device
4014 * No locking done, mounting assumed non multithreaded
4016 * returns zero if mapping is successful
4017 * (failure should not be interpreted as an error)
4020 int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
4023 struct MAPLIST *item;
4024 struct MAPLIST *firstitem;
4025 struct MAPPING *usermapping;
4026 struct MAPPING *groupmapping;
4040 1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5),
4041 const_cpu_to_le32(21),
4042 const_cpu_to_le32(DEFSECAUTH1), const_cpu_to_le32(DEFSECAUTH2),
4043 const_cpu_to_le32(DEFSECAUTH3), const_cpu_to_le32(DEFSECBASE)
4046 /* be sure not to map anything until done */
4047 scx->mapping[MAPUSERS] = (struct MAPPING*)NULL;
4048 scx->mapping[MAPGROUPS] = (struct MAPPING*)NULL;
4050 if (!usermap_path) usermap_path = MAPPINGFILE;
4051 if (usermap_path[0] == '/') {
4052 fd = open(usermap_path,O_RDONLY);
4054 firstitem = ntfs_read_mapping(basicread, (void*)&fd);
4057 firstitem = (struct MAPLIST*)NULL;
4059 ni = ntfs_pathname_to_inode(scx->vol, NULL, usermap_path);
4061 firstitem = ntfs_read_mapping(localread, ni);
4062 ntfs_inode_close(ni);
4064 firstitem = (struct MAPLIST*)NULL;
4069 usermapping = ntfs_do_user_mapping(firstitem);
4070 groupmapping = ntfs_do_group_mapping(firstitem);
4071 if (usermapping && groupmapping) {
4072 scx->mapping[MAPUSERS] = usermapping;
4073 scx->mapping[MAPGROUPS] = groupmapping;
4075 ntfs_log_error("There were no valid user or no valid group\n");
4076 /* now we can free the memory copy of input text */
4077 /* and rely on internal representation */
4079 item = firstitem->next;
4084 /* no mapping file, try a default mapping */
4086 if (!ntfs_do_default_mapping(scx,
4087 0, 0, (const SID*)&defmap))
4088 ntfs_log_info("Using default user mapping\n");
4091 return (!scx->mapping[MAPUSERS] || link_group_members(scx));
4094 #ifdef HAVE_SETXATTR /* extended attributes interface required */
4097 * Get the ntfs attribute into an extended attribute
4098 * The attribute is returned according to cpu endianness
4101 int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size)
4106 outsize = 0; /* default to no data and no error */
4108 attrib = le32_to_cpu(ni->flags);
4109 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
4110 attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4112 attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4114 attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
4115 outsize = sizeof(FILE_ATTR_FLAGS);
4116 if (size >= outsize) {
4118 memcpy(value,&attrib,outsize);
4123 return (outsize ? (int)outsize : -errno);
4127 * Get the ntfs attributes from an inode
4128 * The attributes are returned according to cpu endianness
4130 * Returns the attributes if successful (cannot be zero)
4131 * 0 if failed (errno to tell why)
4134 u32 ntfs_get_inode_attributes(ntfs_inode *ni)
4139 attrib = le32_to_cpu(ni->flags);
4140 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
4141 attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4143 attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4145 attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
4152 * Set the ntfs attributes on an inode
4153 * The attribute is expected according to cpu endianness
4155 * Returns 0 if successful
4156 * -1 if failed (errno to tell why)
4159 int ntfs_set_inode_attributes(ntfs_inode *ni, u32 attrib)
4162 ATTR_FLAGS dirflags;
4167 settable = FILE_ATTR_SETTABLE;
4169 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4171 * Accept changing compression for a directory
4172 * and set index root accordingly
4174 settable |= FILE_ATTR_COMPRESSED;
4175 if ((ni->flags ^ cpu_to_le32(attrib))
4176 & FILE_ATTR_COMPRESSED) {
4177 if (ni->flags & FILE_ATTR_COMPRESSED)
4178 dirflags = const_cpu_to_le16(0);
4180 dirflags = ATTR_IS_COMPRESSED;
4181 res = ntfs_attr_set_flags(ni, AT_INDEX_ROOT,
4182 NTFS_INDEX_I30, 4, dirflags,
4183 ATTR_COMPRESSION_MASK);
4187 ni->flags = (ni->flags & ~settable)
4188 | (cpu_to_le32(attrib) & settable);
4189 NInoFileNameSetDirty(ni);
4198 * Return the ntfs attribute into an extended attribute
4199 * The attribute is expected according to cpu endianness
4201 * Returns 0, or -1 if there is a problem
4204 int ntfs_set_ntfs_attrib(ntfs_inode *ni,
4205 const char *value, size_t size, int flags)
4211 if (ni && value && (size >= sizeof(FILE_ATTR_FLAGS))) {
4212 if (!(flags & XATTR_CREATE)) {
4213 /* copy to avoid alignment problems */
4214 memcpy(&attrib,value,sizeof(FILE_ATTR_FLAGS));
4215 res = ntfs_set_inode_attributes(ni, attrib);
4220 return (res ? -1 : 0);
4223 #endif /* HAVE_SETXATTR */
4226 * Open $Secure once for all
4227 * returns zero if it succeeds
4228 * non-zero if it fails. This is not an error (on NTFS v1.x)
4232 int ntfs_open_secure(ntfs_volume *vol)
4238 vol->secure_ni = (ntfs_inode*)NULL;
4239 vol->secure_xsii = (ntfs_index_context*)NULL;
4240 vol->secure_xsdh = (ntfs_index_context*)NULL;
4241 if (vol->major_ver >= 3) {
4242 /* make sure this is a genuine $Secure inode 9 */
4243 ni = ntfs_pathname_to_inode(vol, NULL, "$Secure");
4244 if (ni && (ni->mft_no == 9)) {
4245 vol->secure_reentry = 0;
4246 vol->secure_xsii = ntfs_index_ctx_get(ni,
4248 vol->secure_xsdh = ntfs_index_ctx_get(ni,
4250 if (ni && vol->secure_xsii && vol->secure_xsdh) {
4251 vol->secure_ni = ni;
4261 * Allocated memory is freed to facilitate the detection of memory leaks
4264 void ntfs_close_secure(struct SECURITY_CONTEXT *scx)
4269 if (vol->secure_ni) {
4270 ntfs_index_ctx_put(vol->secure_xsii);
4271 ntfs_index_ctx_put(vol->secure_xsdh);
4272 ntfs_inode_close(vol->secure_ni);
4275 ntfs_free_mapping(scx->mapping);
4280 * API for direct access to security descriptors
4281 * based on Win32 API
4286 * Selective feeding of a security descriptor into user buffer
4288 * Returns TRUE if successful
4291 static BOOL feedsecurityattr(const char *attr, u32 selection,
4292 char *buf, u32 buflen, u32 *psize)
4294 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4295 SECURITY_DESCRIPTOR_RELATIVE *pnhead;
4300 unsigned int offdacl;
4301 unsigned int offsacl;
4302 unsigned int offowner;
4303 unsigned int offgroup;
4304 unsigned int daclsz;
4305 unsigned int saclsz;
4306 unsigned int usidsz;
4307 unsigned int gsidsz;
4308 unsigned int size; /* size of requested attributes */
4315 control = SE_SELF_RELATIVE;
4316 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4317 size = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4319 /* locate DACL if requested and available */
4320 if (phead->dacl && (selection & DACL_SECURITY_INFORMATION)) {
4321 offdacl = le32_to_cpu(phead->dacl);
4322 pdacl = (const ACL*)&attr[offdacl];
4323 daclsz = le16_to_cpu(pdacl->size);
4325 avail |= DACL_SECURITY_INFORMATION;
4327 offdacl = daclsz = 0;
4329 /* locate owner if requested and available */
4330 offowner = le32_to_cpu(phead->owner);
4331 if (offowner && (selection & OWNER_SECURITY_INFORMATION)) {
4332 /* find end of USID */
4333 pusid = (const SID*)&attr[offowner];
4334 usidsz = ntfs_sid_size(pusid);
4336 avail |= OWNER_SECURITY_INFORMATION;
4338 offowner = usidsz = 0;
4340 /* locate group if requested and available */
4341 offgroup = le32_to_cpu(phead->group);
4342 if (offgroup && (selection & GROUP_SECURITY_INFORMATION)) {
4343 /* find end of GSID */
4344 pgsid = (const SID*)&attr[offgroup];
4345 gsidsz = ntfs_sid_size(pgsid);
4347 avail |= GROUP_SECURITY_INFORMATION;
4349 offgroup = gsidsz = 0;
4351 /* locate SACL if requested and available */
4352 if (phead->sacl && (selection & SACL_SECURITY_INFORMATION)) {
4353 /* find end of SACL */
4354 offsacl = le32_to_cpu(phead->sacl);
4355 psacl = (const ACL*)&attr[offsacl];
4356 saclsz = le16_to_cpu(psacl->size);
4358 avail |= SACL_SECURITY_INFORMATION;
4360 offsacl = saclsz = 0;
4363 * Check having enough size in destination buffer
4364 * (required size is returned nevertheless so that
4365 * the request can be reissued with adequate size)
4367 if (size > buflen) {
4372 if (selection & OWNER_SECURITY_INFORMATION)
4373 control |= phead->control & SE_OWNER_DEFAULTED;
4374 if (selection & GROUP_SECURITY_INFORMATION)
4375 control |= phead->control & SE_GROUP_DEFAULTED;
4376 if (selection & DACL_SECURITY_INFORMATION)
4377 control |= phead->control
4380 | SE_DACL_AUTO_INHERITED
4381 | SE_DACL_PROTECTED);
4382 if (selection & SACL_SECURITY_INFORMATION)
4383 control |= phead->control
4386 | SE_SACL_AUTO_INHERITED
4387 | SE_SACL_PROTECTED);
4389 * copy header and feed new flags, even if no detailed data
4391 memcpy(buf,attr,sizeof(SECURITY_DESCRIPTOR_RELATIVE));
4392 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)buf;
4393 pnhead->control = control;
4394 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4396 /* copy DACL if requested and available */
4397 if (selection & avail & DACL_SECURITY_INFORMATION) {
4398 pnhead->dacl = cpu_to_le32(pos);
4399 memcpy(&buf[pos],&attr[offdacl],daclsz);
4402 pnhead->dacl = const_cpu_to_le32(0);
4404 /* copy SACL if requested and available */
4405 if (selection & avail & SACL_SECURITY_INFORMATION) {
4406 pnhead->sacl = cpu_to_le32(pos);
4407 memcpy(&buf[pos],&attr[offsacl],saclsz);
4410 pnhead->sacl = const_cpu_to_le32(0);
4412 /* copy owner if requested and available */
4413 if (selection & avail & OWNER_SECURITY_INFORMATION) {
4414 pnhead->owner = cpu_to_le32(pos);
4415 memcpy(&buf[pos],&attr[offowner],usidsz);
4418 pnhead->owner = const_cpu_to_le32(0);
4420 /* copy group if requested and available */
4421 if (selection & avail & GROUP_SECURITY_INFORMATION) {
4422 pnhead->group = cpu_to_le32(pos);
4423 memcpy(&buf[pos],&attr[offgroup],gsidsz);
4426 pnhead->group = const_cpu_to_le32(0);
4428 ntfs_log_error("Error in security descriptor size\n");
4437 * Merge a new security descriptor into the old one
4438 * and assign to designated file
4440 * Returns TRUE if successful
4443 static BOOL mergesecurityattr(ntfs_volume *vol, const char *oldattr,
4444 const char *newattr, u32 selection, ntfs_inode *ni)
4446 const SECURITY_DESCRIPTOR_RELATIVE *oldhead;
4447 const SECURITY_DESCRIPTOR_RELATIVE *newhead;
4448 SECURITY_DESCRIPTOR_RELATIVE *targhead;
4465 ok = FALSE; /* default return */
4466 oldhead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
4467 newhead = (const SECURITY_DESCRIPTOR_RELATIVE*)newattr;
4468 oldattrsz = ntfs_attr_size(oldattr);
4469 newattrsz = ntfs_attr_size(newattr);
4470 target = (char*)ntfs_malloc(oldattrsz + newattrsz);
4472 targhead = (SECURITY_DESCRIPTOR_RELATIVE*)target;
4473 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4474 control = SE_SELF_RELATIVE;
4476 * copy new DACL if selected
4477 * or keep old DACL if any
4479 if ((selection & DACL_SECURITY_INFORMATION) ?
4480 newhead->dacl : oldhead->dacl) {
4481 if (selection & DACL_SECURITY_INFORMATION) {
4482 offdacl = le32_to_cpu(newhead->dacl);
4483 pdacl = (const ACL*)&newattr[offdacl];
4485 offdacl = le32_to_cpu(oldhead->dacl);
4486 pdacl = (const ACL*)&oldattr[offdacl];
4488 size = le16_to_cpu(pdacl->size);
4489 memcpy(&target[pos], pdacl, size);
4490 targhead->dacl = cpu_to_le32(pos);
4493 targhead->dacl = const_cpu_to_le32(0);
4494 if (selection & DACL_SECURITY_INFORMATION) {
4495 control |= newhead->control
4498 | SE_DACL_PROTECTED);
4499 if (newhead->control & SE_DACL_AUTO_INHERIT_REQ)
4500 control |= SE_DACL_AUTO_INHERITED;
4502 control |= oldhead->control
4505 | SE_DACL_AUTO_INHERITED
4506 | SE_DACL_PROTECTED);
4508 * copy new SACL if selected
4509 * or keep old SACL if any
4511 if ((selection & SACL_SECURITY_INFORMATION) ?
4512 newhead->sacl : oldhead->sacl) {
4513 if (selection & SACL_SECURITY_INFORMATION) {
4514 offsacl = le32_to_cpu(newhead->sacl);
4515 psacl = (const ACL*)&newattr[offsacl];
4517 offsacl = le32_to_cpu(oldhead->sacl);
4518 psacl = (const ACL*)&oldattr[offsacl];
4520 size = le16_to_cpu(psacl->size);
4521 memcpy(&target[pos], psacl, size);
4522 targhead->sacl = cpu_to_le32(pos);
4525 targhead->sacl = const_cpu_to_le32(0);
4526 if (selection & SACL_SECURITY_INFORMATION) {
4527 control |= newhead->control
4530 | SE_SACL_PROTECTED);
4531 if (newhead->control & SE_SACL_AUTO_INHERIT_REQ)
4532 control |= SE_SACL_AUTO_INHERITED;
4534 control |= oldhead->control
4537 | SE_SACL_AUTO_INHERITED
4538 | SE_SACL_PROTECTED);
4540 * copy new OWNER if selected
4541 * or keep old OWNER if any
4543 if ((selection & OWNER_SECURITY_INFORMATION) ?
4544 newhead->owner : oldhead->owner) {
4545 if (selection & OWNER_SECURITY_INFORMATION) {
4546 offowner = le32_to_cpu(newhead->owner);
4547 powner = (const SID*)&newattr[offowner];
4549 offowner = le32_to_cpu(oldhead->owner);
4550 powner = (const SID*)&oldattr[offowner];
4552 size = ntfs_sid_size(powner);
4553 memcpy(&target[pos], powner, size);
4554 targhead->owner = cpu_to_le32(pos);
4557 targhead->owner = const_cpu_to_le32(0);
4558 if (selection & OWNER_SECURITY_INFORMATION)
4559 control |= newhead->control & SE_OWNER_DEFAULTED;
4561 control |= oldhead->control & SE_OWNER_DEFAULTED;
4563 * copy new GROUP if selected
4564 * or keep old GROUP if any
4566 if ((selection & GROUP_SECURITY_INFORMATION) ?
4567 newhead->group : oldhead->group) {
4568 if (selection & GROUP_SECURITY_INFORMATION) {
4569 offgroup = le32_to_cpu(newhead->group);
4570 pgroup = (const SID*)&newattr[offgroup];
4571 control |= newhead->control
4572 & SE_GROUP_DEFAULTED;
4574 offgroup = le32_to_cpu(oldhead->group);
4575 pgroup = (const SID*)&oldattr[offgroup];
4576 control |= oldhead->control
4577 & SE_GROUP_DEFAULTED;
4579 size = ntfs_sid_size(pgroup);
4580 memcpy(&target[pos], pgroup, size);
4581 targhead->group = cpu_to_le32(pos);
4584 targhead->group = const_cpu_to_le32(0);
4585 if (selection & GROUP_SECURITY_INFORMATION)
4586 control |= newhead->control & SE_GROUP_DEFAULTED;
4588 control |= oldhead->control & SE_GROUP_DEFAULTED;
4589 targhead->revision = SECURITY_DESCRIPTOR_REVISION;
4590 targhead->alignment = 0;
4591 targhead->control = control;
4592 ok = !update_secur_descr(vol, target, ni);
4598 int ntfs_get_inode_security(ntfs_inode *ni, u32 selection,
4599 char *buf, u32 buflen, u32 *psize)
4606 attr = getsecurityattr(ni->vol, ni);
4608 if (feedsecurityattr(attr, selection,
4609 buf, buflen, psize)) {
4610 if (test_nino_flag(ni, v3_Extensions)
4624 int ntfs_set_inode_security(ntfs_inode *ni, u32 selection, const char *attr)
4626 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4632 res = -1; /* default return */
4634 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4635 attrsz = ntfs_attr_size(attr);
4636 /* if selected, owner and group must be present or defaulted */
4637 missing = ((selection & OWNER_SECURITY_INFORMATION)
4639 && !(phead->control & SE_OWNER_DEFAULTED))
4640 || ((selection & GROUP_SECURITY_INFORMATION)
4642 && !(phead->control & SE_GROUP_DEFAULTED));
4644 && (phead->control & SE_SELF_RELATIVE)
4645 && ntfs_valid_descr(attr, attrsz)) {
4646 oldattr = getsecurityattr(ni->vol, ni);
4648 if (mergesecurityattr(ni->vol, oldattr, attr,
4662 * Return the security descriptor of a file
4663 * This is intended to be similar to GetFileSecurity() from Win32
4664 * in order to facilitate the development of portable tools
4666 * returns zero if unsuccessful (following Win32 conventions)
4668 * the securid if any
4670 * The Win32 API is :
4672 * BOOL WINAPI GetFileSecurity(
4673 * __in LPCTSTR lpFileName,
4674 * __in SECURITY_INFORMATION RequestedInformation,
4675 * __out_opt PSECURITY_DESCRIPTOR pSecurityDescriptor,
4676 * __in DWORD nLength,
4677 * __out LPDWORD lpnLengthNeeded
4682 int ntfs_get_file_security(struct SECURITY_API *scapi,
4683 const char *path, u32 selection,
4684 char *buf, u32 buflen, u32 *psize)
4690 res = 0; /* default return */
4691 if (scapi && (scapi->magic == MAGIC_API)) {
4692 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4694 attr = getsecurityattr(scapi->security.vol, ni);
4696 if (feedsecurityattr(attr,selection,
4697 buf,buflen,psize)) {
4698 if (test_nino_flag(ni, v3_Extensions)
4707 ntfs_inode_close(ni);
4710 if (!res) *psize = 0;
4712 errno = EINVAL; /* do not clear *psize */
4718 * Set the security descriptor of a file or directory
4719 * This is intended to be similar to SetFileSecurity() from Win32
4720 * in order to facilitate the development of portable tools
4722 * returns zero if unsuccessful (following Win32 conventions)
4724 * the securid if any
4726 * The Win32 API is :
4728 * BOOL WINAPI SetFileSecurity(
4729 * __in LPCTSTR lpFileName,
4730 * __in SECURITY_INFORMATION SecurityInformation,
4731 * __in PSECURITY_DESCRIPTOR pSecurityDescriptor
4735 int ntfs_set_file_security(struct SECURITY_API *scapi,
4736 const char *path, u32 selection, const char *attr)
4738 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4745 res = 0; /* default return */
4746 if (scapi && (scapi->magic == MAGIC_API) && attr) {
4747 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4748 attrsz = ntfs_attr_size(attr);
4749 /* if selected, owner and group must be present or defaulted */
4750 missing = ((selection & OWNER_SECURITY_INFORMATION)
4752 && !(phead->control & SE_OWNER_DEFAULTED))
4753 || ((selection & GROUP_SECURITY_INFORMATION)
4755 && !(phead->control & SE_GROUP_DEFAULTED));
4757 && (phead->control & SE_SELF_RELATIVE)
4758 && ntfs_valid_descr(attr, attrsz)) {
4759 ni = ntfs_pathname_to_inode(scapi->security.vol,
4762 oldattr = getsecurityattr(scapi->security.vol,
4765 if (mergesecurityattr(
4766 scapi->security.vol,
4769 if (test_nino_flag(ni,
4778 ntfs_inode_close(ni);
4789 * Return the attributes of a file
4790 * This is intended to be similar to GetFileAttributes() from Win32
4791 * in order to facilitate the development of portable tools
4793 * returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES)
4795 * The Win32 API is :
4797 * DWORD WINAPI GetFileAttributes(
4798 * __in LPCTSTR lpFileName
4802 int ntfs_get_file_attributes(struct SECURITY_API *scapi, const char *path)
4807 attrib = -1; /* default return */
4808 if (scapi && (scapi->magic == MAGIC_API) && path) {
4809 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4811 attrib = ntfs_get_inode_attributes(ni);
4812 ntfs_inode_close(ni);
4816 errno = EINVAL; /* do not clear *psize */
4822 * Set attributes to a file or directory
4823 * This is intended to be similar to SetFileAttributes() from Win32
4824 * in order to facilitate the development of portable tools
4826 * Only a few flags can be set (same list as Win32)
4828 * returns zero if unsuccessful (following Win32 conventions)
4829 * nonzero if successful
4831 * The Win32 API is :
4833 * BOOL WINAPI SetFileAttributes(
4834 * __in LPCTSTR lpFileName,
4835 * __in DWORD dwFileAttributes
4839 BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi,
4840 const char *path, s32 attrib)
4845 res = 0; /* default return */
4846 if (scapi && (scapi->magic == MAGIC_API) && path) {
4847 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4849 /* Win32 convention here : -1 means successful */
4850 if (!ntfs_set_inode_attributes(ni, attrib))
4852 if (ntfs_inode_close(ni))
4861 BOOL ntfs_read_directory(struct SECURITY_API *scapi,
4862 const char *path, ntfs_filldir_t callback, void *context)
4868 ok = FALSE; /* default return */
4869 if (scapi && (scapi->magic == MAGIC_API) && callback) {
4870 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4872 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4874 ntfs_readdir(ni,&pos,context,callback);
4875 ok = !ntfs_inode_close(ni);
4877 ntfs_inode_close(ni);
4883 errno = EINVAL; /* do not clear *psize */
4888 * read $SDS (for auditing security data)
4890 * Returns the number or read bytes, or -1 if there is an error
4893 int ntfs_read_sds(struct SECURITY_API *scapi,
4894 char *buf, u32 size, u32 offset)
4898 got = -1; /* default return */
4899 if (scapi && (scapi->magic == MAGIC_API)) {
4900 if (scapi->security.vol->secure_ni)
4901 got = ntfs_attr_data_read(scapi->security.vol->secure_ni,
4902 STREAM_SDS, 4, buf, size, offset);
4911 * read $SII (for auditing security data)
4913 * Returns next entry, or NULL if there is an error
4916 INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
4922 ntfs_index_context *xsii;
4924 ret = (INDEX_ENTRY*)NULL; /* default return */
4925 if (scapi && (scapi->magic == MAGIC_API)) {
4926 xsii = scapi->security.vol->secure_xsii;
4929 key.security_id = const_cpu_to_le32(0);
4930 found = !ntfs_index_lookup((char*)&key,
4931 sizeof(SII_INDEX_KEY), xsii);
4932 /* not supposed to find */
4933 if (!found && (errno == ENOENT))
4936 ret = ntfs_index_next(entry,xsii);
4947 * read $SDH (for auditing security data)
4949 * Returns next entry, or NULL if there is an error
4952 INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
4958 ntfs_index_context *xsdh;
4960 ret = (INDEX_ENTRY*)NULL; /* default return */
4961 if (scapi && (scapi->magic == MAGIC_API)) {
4962 xsdh = scapi->security.vol->secure_xsdh;
4965 key.hash = const_cpu_to_le32(0);
4966 key.security_id = const_cpu_to_le32(0);
4967 found = !ntfs_index_lookup((char*)&key,
4968 sizeof(SDH_INDEX_KEY), xsdh);
4969 /* not supposed to find */
4970 if (!found && (errno == ENOENT))
4973 ret = ntfs_index_next(entry,xsdh);
4976 } else errno = ENOTSUP;
4983 * Get the mapped user SID
4984 * A buffer of 40 bytes has to be supplied
4986 * returns the size of the SID, or zero and errno set if not found
4989 int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf)
4996 if (scapi && (scapi->magic == MAGIC_API)) {
4997 usid = ntfs_find_usid(scapi->security.mapping[MAPUSERS], uid, (SID*)&defusid);
4999 size = ntfs_sid_size(usid);
5000 memcpy(buf,usid,size);
5009 * Get the mapped group SID
5010 * A buffer of 40 bytes has to be supplied
5012 * returns the size of the SID, or zero and errno set if not found
5015 int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf)
5022 if (scapi && (scapi->magic == MAGIC_API)) {
5023 gsid = ntfs_find_gsid(scapi->security.mapping[MAPGROUPS], gid, (SID*)&defgsid);
5025 size = ntfs_sid_size(gsid);
5026 memcpy(buf,gsid,size);
5035 * Get the user mapped to a SID
5037 * returns the uid, or -1 if not found
5040 int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid)
5045 if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(usid)) {
5046 if (ntfs_same_sid(usid,adminsid))
5049 uid = ntfs_find_user(scapi->security.mapping[MAPUSERS], usid);
5061 * Get the group mapped to a SID
5063 * returns the uid, or -1 if not found
5066 int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid)
5071 if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(gsid)) {
5072 if (ntfs_same_sid(gsid,adminsid))
5075 gid = ntfs_find_group(scapi->security.mapping[MAPGROUPS], gsid);
5087 * Initializations before calling ntfs_get_file_security()
5088 * ntfs_set_file_security() and ntfs_read_directory()
5090 * Only allowed for root
5092 * Returns an (obscured) struct SECURITY_API* needed for further calls
5093 * NULL if not root (EPERM) or device is mounted (EBUSY)
5096 struct SECURITY_API *ntfs_initialize_file_security(const char *device,
5097 unsigned long flags)
5100 unsigned long mntflag;
5102 struct SECURITY_API *scapi;
5103 struct SECURITY_CONTEXT *scx;
5105 scapi = (struct SECURITY_API*)NULL;
5106 mnt = ntfs_check_if_mounted(device, &mntflag);
5107 if (!mnt && !(mntflag & NTFS_MF_MOUNTED) && !getuid()) {
5108 vol = ntfs_mount(device, flags);
5110 scapi = (struct SECURITY_API*)
5111 ntfs_malloc(sizeof(struct SECURITY_API));
5112 if (!ntfs_volume_get_free_space(vol)
5114 scapi->magic = MAGIC_API;
5115 scapi->seccache = (struct PERMISSIONS_CACHE*)NULL;
5116 scx = &scapi->security;
5118 scx->uid = getuid();
5119 scx->gid = getgid();
5120 scx->pseccache = &scapi->seccache;
5121 scx->vol->secure_flags = 0;
5122 /* accept no mapping and no $Secure */
5123 ntfs_build_mapping(scx,(const char*)NULL,TRUE);
5124 ntfs_open_secure(vol);
5130 mnt = ntfs_umount(vol,FALSE);
5131 scapi = (struct SECURITY_API*)NULL;
5143 * Leaving after ntfs_initialize_file_security()
5145 * Returns FALSE if FAILED
5148 BOOL ntfs_leave_file_security(struct SECURITY_API *scapi)
5154 if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) {
5155 vol = scapi->security.vol;
5156 ntfs_close_secure(&scapi->security);
5158 if (!ntfs_umount(vol, 0))