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
53 #include <ntfs-3g/param.h>
54 #include <ntfs-3g/types.h>
55 #include <ntfs-3g/layout.h>
56 #include <ntfs-3g/attrib.h>
57 #include <ntfs-3g/index.h>
58 #include <ntfs-3g/dir.h>
59 #include <ntfs-3g/bitmap.h>
60 #include <ntfs-3g/security.h>
61 #include <ntfs-3g/acls.h>
62 #include <ntfs-3g/cache.h>
63 #include <ntfs-3g/misc.h>
66 * JPA NTFS constants or structs
67 * should be moved to layout.h
70 #define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */
71 #define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */
72 #define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */
73 #define FIRST_SECURITY_ID 0x100 /* Lowest security id */
75 /* Mask for attributes which can be forced */
76 #define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY \
80 | FILE_ATTR_TEMPORARY \
82 | FILE_ATTR_NOT_CONTENT_INDEXED )
84 struct SII { /* this is an image of an $SII index entry */
94 /* did not find official description for the following */
97 le32 dataoffsl; /* documented as badly aligned */
102 struct SDH { /* this is an image of an $SDH index entry */
113 /* did not find official description for the following */
123 * A few useful constants
126 static ntfschar sii_stream[] = { const_cpu_to_le16('$'),
127 const_cpu_to_le16('S'),
128 const_cpu_to_le16('I'),
129 const_cpu_to_le16('I'),
130 const_cpu_to_le16(0) };
131 static ntfschar sdh_stream[] = { const_cpu_to_le16('$'),
132 const_cpu_to_le16('S'),
133 const_cpu_to_le16('D'),
134 const_cpu_to_le16('H'),
135 const_cpu_to_le16(0) };
141 extern const SID *nullsid;
147 static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
148 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
149 static const GUID *const zero_guid = &__zero_guid;
152 * ntfs_guid_is_zero - check if a GUID is zero
153 * @guid: [IN] guid to check
155 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
156 * and FALSE otherwise.
158 BOOL ntfs_guid_is_zero(const GUID *guid)
160 return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
164 * ntfs_guid_to_mbs - convert a GUID to a multi byte string
165 * @guid: [IN] guid to convert
166 * @guid_str: [OUT] string in which to return the GUID (optional)
168 * Convert the GUID pointed to by @guid to a multi byte string of the form
169 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
170 * needs to be able to store at least 37 bytes.
172 * If @guid_str is not NULL it will contain the converted GUID on return. If
173 * it is NULL a string will be allocated and this will be returned. The caller
174 * is responsible for free()ing the string in that case.
176 * On success return the converted string and on failure return NULL with errno
177 * set to the error code.
179 char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
188 _guid_str = guid_str;
190 _guid_str = (char*)ntfs_malloc(37);
194 res = snprintf(_guid_str, 37,
195 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
196 (unsigned int)le32_to_cpu(guid->data1),
197 le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
198 guid->data4[0], guid->data4[1],
199 guid->data4[2], guid->data4[3], guid->data4[4],
200 guid->data4[5], guid->data4[6], guid->data4[7]);
210 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
211 * @sid: [IN] SID for which to determine the maximum string size
213 * Determine the maximum multi byte string size in bytes which is needed to
214 * store the standard textual representation of the SID pointed to by @sid.
215 * See ntfs_sid_to_mbs(), below.
217 * On success return the maximum number of bytes needed to store the multi byte
218 * string and on failure return -1 with errno set to the error code.
220 int ntfs_sid_to_mbs_size(const SID *sid)
224 if (!ntfs_sid_is_valid(sid)) {
228 /* Start with "S-". */
231 * Add the SID_REVISION. Hopefully the compiler will optimize this
232 * away as SID_REVISION is a constant.
234 for (i = SID_REVISION; i > 0; i /= 10)
239 * Add the identifier authority. If it needs to be in decimal, the
240 * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
241 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
243 if (!sid->identifier_authority.high_part)
248 * Finally, add the sub authorities. For each we have a "-" followed
249 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
251 size += (1 + 10) * sid->sub_authority_count;
252 /* We need the zero byte at the end, too. */
254 return size * sizeof(char);
258 * ntfs_sid_to_mbs - convert a SID to a multi byte string
259 * @sid: [IN] SID to convert
260 * @sid_str: [OUT] string in which to return the SID (optional)
261 * @sid_str_size: [IN] size in bytes of @sid_str
263 * Convert the SID pointed to by @sid to its standard textual representation.
264 * @sid_str (if not NULL) needs to be able to store at least
265 * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
266 * @sid_str if @sid_str is not NULL.
268 * The standard textual representation of the SID is of the form:
271 * - The first "S" is the literal character 'S' identifying the following
273 * - R is the revision level of the SID expressed as a sequence of digits
275 * - I is the 48-bit identifier_authority, expressed as digits in decimal,
276 * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
277 * - S... is one or more sub_authority values, expressed as digits in
280 * If @sid_str is not NULL it will contain the converted SUID on return. If it
281 * is NULL a string will be allocated and this will be returned. The caller is
282 * responsible for free()ing the string in that case.
284 * On success return the converted string and on failure return NULL with errno
285 * set to the error code.
287 char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
295 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
296 * check @sid, too. 8 is the minimum SID string size.
298 if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
302 /* Allocate string if not provided. */
304 cnt = ntfs_sid_to_mbs_size(sid);
307 s = (char*)ntfs_malloc(cnt);
311 /* So we know we allocated it. */
317 /* Start with "S-R-". */
318 i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
319 if (i < 0 || i >= cnt)
323 /* Add the identifier authority. */
324 for (u = i = 0, j = 40; i < 6; i++, j -= 8)
325 u += (u64)sid->identifier_authority.value[i] << j;
326 if (!sid->identifier_authority.high_part)
327 i = snprintf(s, cnt, "%lu", (unsigned long)u);
329 i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
330 if (i < 0 || i >= cnt)
334 /* Finally, add the sub authorities. */
335 for (j = 0; j < sid->sub_authority_count; j++) {
336 leauth = sid->sub_authority[j];
337 i = snprintf(s, cnt, "-%u", (unsigned int)
338 le32_to_cpu(leauth));
339 if (i < 0 || i >= cnt)
357 * ntfs_generate_guid - generatates a random current guid.
358 * @guid: [OUT] pointer to a GUID struct to hold the generated guid.
360 * perhaps not a very good random number generator though...
362 void ntfs_generate_guid(GUID *guid)
367 for (i = 0; i < sizeof(GUID); i++) {
368 p[i] = (u8)(random() & 0xFF);
370 p[7] = (p[7] & 0x0F) | 0x40;
372 p[8] = (p[8] & 0x3F) | 0x80;
377 * ntfs_security_hash - calculate the hash of a security descriptor
378 * @sd: self-relative security descriptor whose hash to calculate
379 * @length: size in bytes of the security descritor @sd
381 * Calculate the hash of the self-relative security descriptor @sd of length
384 * This hash is used in the $Secure system file as the primary key for the $SDH
385 * index and is also stored in the header of each security descriptor in the
386 * $SDS data stream as well as in the index data of both the $SII and $SDH
387 * indexes. In all three cases it forms part of the SDS_ENTRY_HEADER
390 * Return the calculated security hash in little endian.
392 le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len)
394 const le32 *pos = (const le32*)sd;
395 const le32 *end = pos + (len >> 2);
399 hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3);
402 return cpu_to_le32(hash);
406 * Get the first entry of current index block
407 * cut and pasted form ntfs_ie_get_first() in index.c
410 static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih)
412 return (INDEX_ENTRY*)((u8*)ih + le32_to_cpu(ih->entries_offset));
416 * Stuff a 256KB block into $SDS before writing descriptors
419 * This prevents $SDS from being automatically declared as sparse
420 * when the second copy of the first security descriptor is written
421 * 256KB further ahead.
423 * Having $SDS declared as a sparse file is not wrong by itself
424 * and chkdsk leaves it as a sparse file. It does however complain
425 * and add a sparse flag (0x0200) into field file_attributes of
426 * STANDARD_INFORMATION of $Secure. This probably means that a
427 * sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse
428 * files (FILE_ATTR_SPARSE_FILE).
430 * Windows normally does not convert to sparse attribute or sparse
431 * file. Stuffing is just a way to get to the same result.
434 static int entersecurity_stuff(ntfs_volume *vol, off_t offs)
443 stuff = (char*)ntfs_malloc(STUFFSZ);
445 memset(stuff, 0, STUFFSZ);
447 written = ntfs_attr_data_write(vol->secure_ni,
448 STREAM_SDS, 4, stuff, STUFFSZ, offs);
449 if (written == STUFFSZ) {
456 } while (!res && (total < ALIGN_SDS_BLOCK));
466 * Enter a new security descriptor into $Secure (data only)
467 * it has to be written twice with an offset of 256KB
469 * Should only be called by entersecurityattr() to ensure consistency
471 * Returns zero if sucessful
474 static int entersecurity_data(ntfs_volume *vol,
475 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
476 le32 hash, le32 keyid, off_t offs, int gap)
483 SECURITY_DESCRIPTOR_HEADER *phsds;
486 fullsz = attrsz + gap + sizeof(SECURITY_DESCRIPTOR_HEADER);
487 fullattr = (char*)ntfs_malloc(fullsz);
490 * Clear the gap from previous descriptor
491 * this could be useful for appending the second
492 * copy to the end of file. When creating a new
493 * 256K block, the gap is cleared while writing
497 memset(fullattr,0,gap);
498 memcpy(&fullattr[gap + sizeof(SECURITY_DESCRIPTOR_HEADER)],
500 phsds = (SECURITY_DESCRIPTOR_HEADER*)&fullattr[gap];
502 phsds->security_id = keyid;
503 phsds->offset = cpu_to_le64(offs);
504 phsds->length = cpu_to_le32(fullsz - gap);
505 written1 = ntfs_attr_data_write(vol->secure_ni,
506 STREAM_SDS, 4, fullattr, fullsz,
508 written2 = ntfs_attr_data_write(vol->secure_ni,
509 STREAM_SDS, 4, fullattr, fullsz,
510 offs - gap + ALIGN_SDS_BLOCK);
511 if ((written1 == fullsz)
512 && (written2 == written1))
523 * Enter a new security descriptor in $Secure (indexes only)
525 * Should only be called by entersecurityattr() to ensure consistency
527 * Returns zero if sucessful
530 static int entersecurity_indexes(ntfs_volume *vol, s64 attrsz,
531 le32 hash, le32 keyid, off_t offs)
541 ntfs_index_context *xsii;
542 ntfs_index_context *xsdh;
547 /* enter a new $SII record */
549 xsii = vol->secure_xsii;
550 ntfs_index_ctx_reinit(xsii);
551 newsii.offs = const_cpu_to_le16(20);
552 newsii.size = const_cpu_to_le16(sizeof(struct SII) - 20);
553 newsii.fill1 = const_cpu_to_le32(0);
554 newsii.indexsz = const_cpu_to_le16(sizeof(struct SII));
555 newsii.indexksz = const_cpu_to_le16(sizeof(SII_INDEX_KEY));
556 newsii.flags = const_cpu_to_le16(0);
557 newsii.fill2 = const_cpu_to_le16(0);
558 newsii.keysecurid = keyid;
560 newsii.securid = keyid;
561 realign.all = cpu_to_le64(offs);
562 newsii.dataoffsh = realign.parts.dataoffsh;
563 newsii.dataoffsl = realign.parts.dataoffsl;
564 newsii.datasize = cpu_to_le32(attrsz
565 + sizeof(SECURITY_DESCRIPTOR_HEADER));
566 if (!ntfs_ie_add(xsii,(INDEX_ENTRY*)&newsii)) {
568 /* enter a new $SDH record */
570 xsdh = vol->secure_xsdh;
571 ntfs_index_ctx_reinit(xsdh);
572 newsdh.offs = const_cpu_to_le16(24);
573 newsdh.size = const_cpu_to_le16(
574 sizeof(SECURITY_DESCRIPTOR_HEADER));
575 newsdh.fill1 = const_cpu_to_le32(0);
576 newsdh.indexsz = const_cpu_to_le16(
578 newsdh.indexksz = const_cpu_to_le16(
579 sizeof(SDH_INDEX_KEY));
580 newsdh.flags = const_cpu_to_le16(0);
581 newsdh.fill2 = const_cpu_to_le16(0);
582 newsdh.keyhash = hash;
583 newsdh.keysecurid = keyid;
585 newsdh.securid = keyid;
586 newsdh.dataoffsh = realign.parts.dataoffsh;
587 newsdh.dataoffsl = realign.parts.dataoffsl;
588 newsdh.datasize = cpu_to_le32(attrsz
589 + sizeof(SECURITY_DESCRIPTOR_HEADER));
590 /* special filler value, Windows generally */
591 /* fills with 0x00490049, sometimes with zero */
592 newsdh.fill3 = const_cpu_to_le32(0x00490049);
593 if (!ntfs_ie_add(xsdh,(INDEX_ENTRY*)&newsdh))
600 * Enter a new security descriptor in $Secure (data and indexes)
601 * Returns id of entry, or zero if there is a problem.
602 * (should not be called for NTFS version < 3.0)
604 * important : calls have to be serialized, however no locking is
605 * needed while fuse is not multithreaded
608 static le32 entersecurityattr(ntfs_volume *vol,
609 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
629 ntfs_index_context *xsii;
634 /* find the first available securid beyond the last key */
635 /* in $Secure:$SII. This also determines the first */
636 /* available location in $Secure:$SDS, as this stream */
637 /* is always appended to and the id's are allocated */
640 securid = const_cpu_to_le32(0);
641 xsii = vol->secure_xsii;
642 ntfs_index_ctx_reinit(xsii);
644 keyid = const_cpu_to_le32(-1);
646 found = !ntfs_index_lookup((char*)&keyid,
647 sizeof(SII_INDEX_KEY), xsii);
648 if (!found && (errno != ENOENT)) {
649 ntfs_log_perror("Inconsistency in index $SII");
650 psii = (struct SII*)NULL;
652 /* restore errno to avoid misinterpretation */
655 psii = (struct SII*)xsii->entry;
659 * Get last entry in block, but must get first one
660 * one first, as we should already be beyond the
661 * last one. For some reason the search for the last
662 * entry sometimes does not return the last block...
663 * we assume this can only happen in root block
665 if (xsii->is_in_root)
666 entry = ntfs_ie_get_first
667 ((INDEX_HEADER*)&xsii->ir->index);
669 entry = ntfs_ie_get_first
670 ((INDEX_HEADER*)&xsii->ib->index);
672 * All index blocks should be at least half full
673 * so there always is a last entry but one,
674 * except when creating the first entry in index root.
675 * This was however found not to be true : chkdsk
676 * sometimes deletes all the (unused) keys in the last
677 * index block without rebalancing the tree.
678 * When this happens, a new search is restarted from
681 keyid = const_cpu_to_le32(0);
684 next = ntfs_index_next(entry,xsii);
686 psii = (struct SII*)next;
687 /* save last key and */
688 /* available position */
689 keyid = psii->keysecurid;
690 realign.parts.dataoffsh
692 realign.parts.dataoffsl
694 offs = le64_to_cpu(realign.all);
695 size = le32_to_cpu(psii->datasize);
698 if (!entry && !keyid && !retries) {
699 /* search failed, retry from smallest key */
700 ntfs_index_ctx_reinit(xsii);
701 found = !ntfs_index_lookup((char*)&keyid,
702 sizeof(SII_INDEX_KEY), xsii);
703 if (!found && (errno != ENOENT)) {
704 ntfs_log_perror("Index $SII is broken");
716 * could not find any entry, before creating the first
717 * entry, make a double check by making sure size of $SII
718 * is less than needed for one entry
720 securid = const_cpu_to_le32(0);
721 na = ntfs_attr_open(vol->secure_ni,AT_INDEX_ROOT,sii_stream,4);
723 if ((size_t)na->data_size < sizeof(struct SII)) {
724 ntfs_log_error("Creating the first security_id\n");
725 securid = const_cpu_to_le32(FIRST_SECURITY_ID);
730 ntfs_log_error("Error creating a security_id\n");
734 newkey = le32_to_cpu(keyid) + 1;
735 securid = cpu_to_le32(newkey);
738 * The security attr has to be written twice 256KB
739 * apart. This implies that offsets like
740 * 0x40000*odd_integer must be left available for
741 * the second copy. So align to next block when
742 * the last byte overflows on a wrong block.
746 gap = (-size) & (ALIGN_SDS_ENTRY - 1);
748 if ((offs + attrsz + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
750 offs = ((offs + attrsz
751 + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
752 | (ALIGN_SDS_BLOCK - 1)) + 1;
754 if (!(offs & (ALIGN_SDS_BLOCK - 1)))
755 entersecurity_stuff(vol, offs);
757 * now write the security attr to storage :
758 * first data, then SII, then SDH
759 * If failure occurs while writing SDS, data will never
760 * be accessed through indexes, and will be overwritten
761 * by the next allocated descriptor
762 * If failure occurs while writing SII, the id has not
763 * recorded and will be reallocated later
764 * If failure occurs while writing SDH, the space allocated
765 * in SDS or SII will not be reused, an inconsistency
766 * will persist with no significant consequence
768 if (entersecurity_data(vol, attr, attrsz, hash, securid, offs, gap)
769 || entersecurity_indexes(vol, attrsz, hash, securid, offs))
770 securid = const_cpu_to_le32(0);
772 /* inode now is dirty, synchronize it all */
773 ntfs_index_entry_mark_dirty(vol->secure_xsii);
774 ntfs_index_ctx_reinit(vol->secure_xsii);
775 ntfs_index_entry_mark_dirty(vol->secure_xsdh);
776 ntfs_index_ctx_reinit(vol->secure_xsdh);
777 NInoSetDirty(vol->secure_ni);
778 if (ntfs_inode_sync(vol->secure_ni))
779 ntfs_log_perror("Could not sync $Secure\n");
784 * Find a matching security descriptor in $Secure,
785 * if none, allocate a new id and write the descriptor to storage
786 * Returns id of entry, or zero if there is a problem.
788 * important : calls have to be serialized, however no locking is
789 * needed while fuse is not multithreaded
792 static le32 setsecurityattr(ntfs_volume *vol,
793 const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz)
795 struct SDH *psdh; /* this is an image of index (le) */
809 ntfs_index_context *xsdh;
817 hash = ntfs_security_hash(attr,attrsz);
818 oldattr = (char*)NULL;
819 securid = const_cpu_to_le32(0);
821 xsdh = vol->secure_xsdh;
822 if (vol->secure_ni && xsdh && !vol->secure_reentry++) {
823 ntfs_index_ctx_reinit(xsdh);
825 * find the nearest key as (hash,0)
826 * (do not search for partial key : in case of collision,
827 * it could return a key which is not the first one which
831 key.security_id = const_cpu_to_le32(0);
833 found = !ntfs_index_lookup((char*)&key,
834 sizeof(SDH_INDEX_KEY), xsdh);
835 if (!found && (errno != ENOENT))
836 ntfs_log_perror("Inconsistency in index $SDH");
838 /* restore errno to avoid misinterpretation */
843 * lookup() may return a node with no data,
846 if (entry->ie_flags & INDEX_ENTRY_END)
847 entry = ntfs_index_next(entry,xsdh);
850 psdh = (struct SDH*)entry;
852 size = (size_t) le32_to_cpu(psdh->datasize)
853 - sizeof(SECURITY_DESCRIPTOR_HEADER);
855 /* if hash is not the same, the key is not present */
856 if (psdh && (size > 0)
857 && (psdh->keyhash == hash)) {
858 /* if hash is the same */
859 /* check the whole record */
860 realign.parts.dataoffsh = psdh->dataoffsh;
861 realign.parts.dataoffsl = psdh->dataoffsl;
862 offs = le64_to_cpu(realign.all)
863 + sizeof(SECURITY_DESCRIPTOR_HEADER);
864 oldattr = (char*)ntfs_malloc(size);
866 rdsize = ntfs_attr_data_read(
869 oldattr, size, offs);
870 found = (rdsize == size)
871 && !memcmp(oldattr,attr,size);
873 /* if the records do not compare */
874 /* (hash collision), try next one */
876 entry = ntfs_index_next(
883 } while (collision && entry);
885 securid = psdh->keysecurid;
889 securid = const_cpu_to_le32(0);
893 * have to build a new one
895 securid = entersecurityattr(vol,
901 if (--vol->secure_reentry)
902 ntfs_log_perror("Reentry error, check no multithreading\n");
908 * Update the security descriptor of a file
909 * Either as an attribute (complying with pre v3.x NTFS version)
910 * or, when possible, as an entry in $Secure (for NTFS v3.x)
912 * returns 0 if success
915 static int update_secur_descr(ntfs_volume *vol,
916 char *newattr, ntfs_inode *ni)
923 newattrsz = ntfs_attr_size(newattr);
925 #if !FORCE_FORMAT_v1x
926 if ((vol->major_ver < 3) || !vol->secure_ni) {
929 /* update for NTFS format v1.x */
931 /* update the old security attribute */
932 na = ntfs_attr_open(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0);
934 /* resize attribute */
935 res = ntfs_attr_truncate(na, (s64) newattrsz);
936 /* overwrite value */
938 written = (int)ntfs_attr_pwrite(na, (s64) 0,
939 (s64) newattrsz, newattr);
940 if (written != newattrsz) {
941 ntfs_log_error("Failed to update "
942 "a v1.x security descriptor\n");
949 /* if old security attribute was found, also */
950 /* truncate standard information attribute to v1.x */
951 /* this is needed when security data is wanted */
952 /* as v1.x though volume is formatted for v3.x */
953 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
956 clear_nino_flag(ni, v3_Extensions);
958 * Truncating the record does not sweep extensions
959 * from copy in memory. Clear security_id to be safe
961 ni->security_id = const_cpu_to_le32(0);
962 res = ntfs_attr_truncate(na, (s64)48);
964 clear_nino_flag(ni, v3_Extensions);
968 * insert the new security attribute if there
971 res = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR,
972 AT_UNNAMED, 0, (u8*)newattr,
975 #if !FORCE_FORMAT_v1x
978 /* update for NTFS format v3.x */
982 securid = setsecurityattr(vol,
983 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
986 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
990 if (!test_nino_flag(ni, v3_Extensions)) {
991 /* expand standard information attribute to v3.x */
992 res = ntfs_attr_truncate(na,
993 (s64)sizeof(STANDARD_INFORMATION));
994 ni->owner_id = const_cpu_to_le32(0);
995 ni->quota_charged = const_cpu_to_le64(0);
996 ni->usn = const_cpu_to_le64(0);
998 AT_SECURITY_DESCRIPTOR,
1001 set_nino_flag(ni, v3_Extensions);
1002 ni->security_id = securid;
1003 ntfs_attr_close(na);
1005 ntfs_log_error("Failed to update "
1006 "standard informations\n");
1015 /* mark node as dirty */
1021 * Upgrade the security descriptor of a file
1022 * This is intended to allow graceful upgrades for files which
1023 * were created in previous versions, with a security attributes
1024 * and no security id.
1026 * It will allocate a security id and replace the individual
1027 * security attribute by a reference to the global one
1029 * Special files are not upgraded (currently / and files in
1032 * Though most code is similar to update_secur_desc() it has
1033 * been kept apart to facilitate the further processing of
1034 * special cases or even to remove it if found dangerous.
1036 * returns 0 if success,
1037 * 1 if not upgradable. This is not an error.
1038 * -1 if there is a problem
1041 static int upgrade_secur_desc(ntfs_volume *vol,
1042 const char *attr, ntfs_inode *ni)
1050 * upgrade requires NTFS format v3.x
1051 * also refuse upgrading for special files
1052 * whose number is less than FILE_first_user
1055 if ((vol->major_ver >= 3)
1056 && (ni->mft_no >= FILE_first_user)) {
1057 attrsz = ntfs_attr_size(attr);
1058 securid = setsecurityattr(vol,
1059 (const SECURITY_DESCRIPTOR_RELATIVE*)attr,
1062 na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
1065 /* expand standard information attribute to v3.x */
1066 res = ntfs_attr_truncate(na,
1067 (s64)sizeof(STANDARD_INFORMATION));
1068 ni->owner_id = const_cpu_to_le32(0);
1069 ni->quota_charged = const_cpu_to_le64(0);
1070 ni->usn = const_cpu_to_le64(0);
1071 ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR,
1073 set_nino_flag(ni, v3_Extensions);
1074 ni->security_id = securid;
1075 ntfs_attr_close(na);
1077 ntfs_log_error("Failed to upgrade "
1078 "standard informations\n");
1084 /* mark node as dirty */
1093 * Optional simplified checking of group membership
1095 * This only takes into account the groups defined in
1096 * /etc/group at initialization time.
1097 * It does not take into account the groups dynamically set by
1098 * setgroups() nor the changes in /etc/group since initialization
1100 * This optional method could be useful if standard checking
1101 * leads to a performance concern.
1103 * Should not be called for user root, however the group may be root
1107 static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1112 struct MAPPING *user;
1116 user = scx->mapping[MAPUSERS];
1117 while (user && ((uid_t)user->xid != uid))
1120 groups = user->groups;
1121 grcnt = user->grcnt;
1122 while ((--grcnt >= 0) && (groups[grcnt] != gid)) { }
1123 ingroup = (grcnt >= 0);
1131 * Check whether current thread owner is member of file group
1133 * Should not be called for user root, however the group may be root
1135 * As indicated by Miklos Szeredi :
1137 * The group list is available in
1139 * /proc/$PID/task/$TID/status
1141 * and fuse supplies TID in get_fuse_context()->pid. The only problem is
1142 * finding out PID, for which I have no good solution, except to iterate
1143 * through all processes. This is rather slow, but may be speeded up
1144 * with caching and heuristics (for single threaded programs PID = TID).
1146 * The following implementation gets the group list from
1147 * /proc/$TID/task/$TID/status which apparently exists and
1148 * contains the same data.
1151 static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1153 static char key[] = "\nGroups:";
1156 enum { INKEY, INSEP, INNUM, INEND } state;
1166 if (scx->vol->secure_flags & (1 << SECURITY_STATICGRPS))
1167 ismember = staticgroupmember(scx, uid, gid);
1169 ismember = FALSE; /* default return */
1171 sprintf(filename,"/proc/%u/task/%u/status",tid,tid);
1172 fd = open(filename,O_RDONLY);
1174 got = read(fd, buf, BUFSZ);
1181 * A simple automaton to process lines like
1182 * Groups: 14 500 513
1188 got = read(fd, buf, BUFSZ);
1191 c = *p++; /* 0 at end of file */
1195 if (key[matched] == c) {
1196 if (!key[++matched])
1205 if ((c >= '0') && (c <= '9')) {
1209 if ((c != ' ') && (c != '\t'))
1213 if ((c >= '0') && (c <= '9'))
1214 grp = grp*10 + c - '0';
1216 ismember = (grp == gid);
1217 if ((c != ' ') && (c != '\t'))
1225 } while (!ismember && c && (state != INEND));
1228 ntfs_log_error("No group record found in %s\n",filename);
1230 ntfs_log_error("Could not open %s\n",filename);
1236 * Cacheing is done two-way :
1237 * - from uid, gid and perm to securid (CACHED_SECURID)
1238 * - from a securid to uid, gid and perm (CACHED_PERMISSIONS)
1240 * CACHED_SECURID data is kept in a most-recent-first list
1241 * which should not be too long to be efficient. Its optimal
1242 * size is depends on usage and is hard to determine.
1244 * CACHED_PERMISSIONS data is kept in a two-level indexed array. It
1245 * is optimal at the expense of storage. Use of a most-recent-first
1246 * list would save memory and provide similar performances for
1247 * standard usage, but not for file servers with too many file
1250 * CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS
1251 * for legacy directories which were not allocated a security_id
1252 * it is organized in a most-recent-first list.
1254 * In main caches, data is never invalidated, as the meaning of
1255 * a security_id only changes when user mapping is changed, which
1256 * current implies remounting. However returned entries may be
1257 * overwritten at next update, so data has to be copied elsewhere
1258 * before another cache update is made.
1259 * In legacy cache, data has to be invalidated when protection is
1262 * Though the same data may be found in both list, they
1263 * must be kept separately : the interpretation of ACL
1264 * in both direction are approximations which could be non
1265 * reciprocal for some configuration of the user mapping data
1267 * During the process of recompiling ntfs-3g from a tgz archive,
1268 * security processing added 7.6% to the cpu time used by ntfs-3g
1269 * and 30% if the cache is disabled.
1272 static struct PERMISSIONS_CACHE *create_caches(struct SECURITY_CONTEXT *scx,
1275 struct PERMISSIONS_CACHE *cache;
1276 unsigned int index1;
1279 cache = (struct PERMISSIONS_CACHE*)NULL;
1280 /* create the first permissions blocks */
1281 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1282 cache = (struct PERMISSIONS_CACHE*)
1283 ntfs_malloc(sizeof(struct PERMISSIONS_CACHE)
1284 + index1*sizeof(struct CACHED_PERMISSIONS*));
1286 cache->head.last = index1;
1287 cache->head.p_reads = 0;
1288 cache->head.p_hits = 0;
1289 cache->head.p_writes = 0;
1290 *scx->pseccache = cache;
1291 for (i=0; i<=index1; i++)
1292 cache->cachetable[i]
1293 = (struct CACHED_PERMISSIONS*)NULL;
1299 * Free memory used by caches
1300 * The only purpose is to facilitate the detection of memory leaks
1303 static void free_caches(struct SECURITY_CONTEXT *scx)
1305 unsigned int index1;
1306 struct PERMISSIONS_CACHE *pseccache;
1308 pseccache = *scx->pseccache;
1310 for (index1=0; index1<=pseccache->head.last; index1++)
1311 if (pseccache->cachetable[index1]) {
1313 struct CACHED_PERMISSIONS *cacheentry;
1314 unsigned int index2;
1316 for (index2=0; index2<(1<< CACHE_PERMISSIONS_BITS); index2++) {
1317 cacheentry = &pseccache->cachetable[index1][index2];
1318 if (cacheentry->valid
1319 && cacheentry->pxdesc)
1320 free(cacheentry->pxdesc);
1323 free(pseccache->cachetable[index1]);
1329 static int compare(const struct CACHED_SECURID *cached,
1330 const struct CACHED_SECURID *item)
1336 /* only compare data and sizes */
1337 csize = (cached->variable ?
1338 sizeof(struct POSIX_ACL)
1339 + (((struct POSIX_SECURITY*)cached->variable)->acccnt
1340 + ((struct POSIX_SECURITY*)cached->variable)->defcnt)
1341 *sizeof(struct POSIX_ACE) :
1343 isize = (item->variable ?
1344 sizeof(struct POSIX_ACL)
1345 + (((struct POSIX_SECURITY*)item->variable)->acccnt
1346 + ((struct POSIX_SECURITY*)item->variable)->defcnt)
1347 *sizeof(struct POSIX_ACE) :
1349 return ((cached->uid != item->uid)
1350 || (cached->gid != item->gid)
1351 || (cached->dmode != item->dmode)
1355 && memcmp(&((struct POSIX_SECURITY*)cached->variable)->acl,
1356 &((struct POSIX_SECURITY*)item->variable)->acl, csize)));
1358 return ((cached->uid != item->uid)
1359 || (cached->gid != item->gid)
1360 || (cached->dmode != item->dmode));
1364 static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached,
1365 const struct CACHED_PERMISSIONS_LEGACY *item)
1367 return (cached->mft_no != item->mft_no);
1371 * Resize permission cache table
1372 * do not call unless resizing is needed
1374 * If allocation fails, the cache size is not updated
1375 * Lack of memory is not considered as an error, the cache is left
1376 * consistent and errno is not set.
1379 static void resize_cache(struct SECURITY_CONTEXT *scx,
1382 struct PERMISSIONS_CACHE *oldcache;
1383 struct PERMISSIONS_CACHE *newcache;
1386 unsigned int index1;
1389 oldcache = *scx->pseccache;
1390 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1391 newcnt = index1 + 1;
1392 if (newcnt <= ((CACHE_PERMISSIONS_SIZE
1393 + (1 << CACHE_PERMISSIONS_BITS)
1394 - 1) >> CACHE_PERMISSIONS_BITS)) {
1395 /* expand cache beyond current end, do not use realloc() */
1396 /* to avoid losing data when there is no more memory */
1397 oldcnt = oldcache->head.last + 1;
1398 newcache = (struct PERMISSIONS_CACHE*)
1400 sizeof(struct PERMISSIONS_CACHE)
1401 + (newcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
1403 memcpy(newcache,oldcache,
1404 sizeof(struct PERMISSIONS_CACHE)
1405 + (oldcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
1407 /* mark new entries as not valid */
1408 for (i=newcache->head.last+1; i<=index1; i++)
1409 newcache->cachetable[i]
1410 = (struct CACHED_PERMISSIONS*)NULL;
1411 newcache->head.last = index1;
1412 *scx->pseccache = newcache;
1418 * Enter uid, gid and mode into cache, if possible
1420 * returns the updated or created cache entry,
1421 * or NULL if not possible (typically if there is no
1422 * security id associated)
1426 static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
1427 ntfs_inode *ni, uid_t uid, gid_t gid,
1428 struct POSIX_SECURITY *pxdesc)
1430 static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
1431 ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode)
1434 struct CACHED_PERMISSIONS *cacheentry;
1435 struct CACHED_PERMISSIONS *cacheblock;
1436 struct PERMISSIONS_CACHE *pcache;
1440 struct POSIX_SECURITY *pxcached;
1442 unsigned int index1;
1443 unsigned int index2;
1446 /* cacheing is only possible if a security_id has been defined */
1447 if (test_nino_flag(ni, v3_Extensions)
1448 && ni->security_id) {
1450 * Immediately test the most frequent situation
1451 * where the entry exists
1453 securindex = le32_to_cpu(ni->security_id);
1454 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1455 index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
1456 pcache = *scx->pseccache;
1458 && (pcache->head.last >= index1)
1459 && pcache->cachetable[index1]) {
1460 cacheentry = &pcache->cachetable[index1][index2];
1461 cacheentry->uid = uid;
1462 cacheentry->gid = gid;
1464 if (cacheentry->valid && cacheentry->pxdesc)
1465 free(cacheentry->pxdesc);
1467 pxsize = sizeof(struct POSIX_SECURITY)
1468 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1469 pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
1471 memcpy(pxcached, pxdesc, pxsize);
1472 cacheentry->pxdesc = pxcached;
1474 cacheentry->valid = 0;
1475 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1477 cacheentry->mode = pxdesc->mode & 07777;
1479 cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
1481 cacheentry->mode = mode & 07777;
1483 cacheentry->inh_fileid = const_cpu_to_le32(0);
1484 cacheentry->inh_dirid = const_cpu_to_le32(0);
1485 cacheentry->valid = 1;
1486 pcache->head.p_writes++;
1489 /* create the first cache block */
1490 pcache = create_caches(scx, securindex);
1492 if (index1 > pcache->head.last) {
1493 resize_cache(scx, securindex);
1494 pcache = *scx->pseccache;
1497 /* allocate block, if cache table was allocated */
1498 if (pcache && (index1 <= pcache->head.last)) {
1499 cacheblock = (struct CACHED_PERMISSIONS*)
1500 malloc(sizeof(struct CACHED_PERMISSIONS)
1501 << CACHE_PERMISSIONS_BITS);
1502 pcache->cachetable[index1] = cacheblock;
1503 for (i=0; i<(1 << CACHE_PERMISSIONS_BITS); i++)
1504 cacheblock[i].valid = 0;
1505 cacheentry = &cacheblock[index2];
1507 cacheentry->uid = uid;
1508 cacheentry->gid = gid;
1511 pxsize = sizeof(struct POSIX_SECURITY)
1512 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1513 pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
1515 memcpy(pxcached, pxdesc, pxsize);
1516 cacheentry->pxdesc = pxcached;
1518 cacheentry->valid = 0;
1519 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1521 cacheentry->mode = pxdesc->mode & 07777;
1523 cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
1525 cacheentry->mode = mode & 07777;
1527 cacheentry->inh_fileid = const_cpu_to_le32(0);
1528 cacheentry->inh_dirid = const_cpu_to_le32(0);
1529 cacheentry->valid = 1;
1530 pcache->head.p_writes++;
1533 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1536 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1537 #if CACHE_LEGACY_SIZE
1538 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1539 struct CACHED_PERMISSIONS_LEGACY wanted;
1540 struct CACHED_PERMISSIONS_LEGACY *legacy;
1542 wanted.perm.uid = uid;
1543 wanted.perm.gid = gid;
1545 wanted.perm.mode = pxdesc->mode & 07777;
1546 wanted.perm.inh_fileid = const_cpu_to_le32(0);
1547 wanted.perm.inh_dirid = const_cpu_to_le32(0);
1548 wanted.mft_no = ni->mft_no;
1549 wanted.variable = (void*)pxdesc;
1550 wanted.varsize = sizeof(struct POSIX_SECURITY)
1551 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1553 wanted.perm.mode = mode & 07777;
1554 wanted.perm.inh_fileid = const_cpu_to_le32(0);
1555 wanted.perm.inh_dirid = const_cpu_to_le32(0);
1556 wanted.mft_no = ni->mft_no;
1557 wanted.variable = (void*)NULL;
1560 legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_enter_cache(
1561 scx->vol->legacy_cache, GENERIC(&wanted),
1562 (cache_compare)leg_compare);
1564 cacheentry = &legacy->perm;
1567 * give direct access to the cached pxdesc
1568 * in the permissions structure
1570 cacheentry->pxdesc = legacy->variable;
1576 return (cacheentry);
1580 * Fetch owner, group and permission of a file, if cached
1582 * Beware : do not use the returned entry after a cache update :
1583 * the cache may be relocated making the returned entry meaningless
1585 * returns the cache entry, or NULL if not available
1588 static struct CACHED_PERMISSIONS *fetch_cache(struct SECURITY_CONTEXT *scx,
1591 struct CACHED_PERMISSIONS *cacheentry;
1592 struct PERMISSIONS_CACHE *pcache;
1594 unsigned int index1;
1595 unsigned int index2;
1597 /* cacheing is only possible if a security_id has been defined */
1598 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1599 if (test_nino_flag(ni, v3_Extensions)
1600 && (ni->security_id)) {
1601 securindex = le32_to_cpu(ni->security_id);
1602 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1603 index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
1604 pcache = *scx->pseccache;
1606 && (pcache->head.last >= index1)
1607 && pcache->cachetable[index1]) {
1608 cacheentry = &pcache->cachetable[index1][index2];
1609 /* reject if entry is not valid */
1610 if (!cacheentry->valid)
1611 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1613 pcache->head.p_hits++;
1615 pcache->head.p_reads++;
1618 #if CACHE_LEGACY_SIZE
1620 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1621 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1622 struct CACHED_PERMISSIONS_LEGACY wanted;
1623 struct CACHED_PERMISSIONS_LEGACY *legacy;
1625 wanted.mft_no = ni->mft_no;
1626 wanted.variable = (void*)NULL;
1628 legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_fetch_cache(
1629 scx->vol->legacy_cache, GENERIC(&wanted),
1630 (cache_compare)leg_compare);
1631 if (legacy) cacheentry = &legacy->perm;
1636 if (cacheentry && !cacheentry->pxdesc) {
1637 ntfs_log_error("No Posix descriptor in cache\n");
1638 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1641 return (cacheentry);
1645 * Retrieve a security attribute from $Secure
1648 static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id)
1663 ntfs_index_context *xsii;
1666 securattr = (char*)NULL;
1667 ni = vol->secure_ni;
1668 xsii = vol->secure_xsii;
1670 ntfs_index_ctx_reinit(xsii);
1672 !ntfs_index_lookup((char*)&id,
1673 sizeof(SII_INDEX_KEY), xsii);
1675 psii = (struct SII*)xsii->entry;
1677 (size_t) le32_to_cpu(psii->datasize)
1678 - sizeof(SECURITY_DESCRIPTOR_HEADER);
1679 /* work around bad alignment problem */
1680 realign.parts.dataoffsh = psii->dataoffsh;
1681 realign.parts.dataoffsl = psii->dataoffsl;
1682 offs = le64_to_cpu(realign.all)
1683 + sizeof(SECURITY_DESCRIPTOR_HEADER);
1685 securattr = (char*)ntfs_malloc(size);
1687 rdsize = ntfs_attr_data_read(
1689 securattr, size, offs);
1690 if ((rdsize != size)
1691 || !ntfs_valid_descr(securattr,
1693 /* error to be logged by caller */
1695 securattr = (char*)NULL;
1699 if (errno != ENOENT)
1700 ntfs_log_perror("Inconsistency in index $SII");
1703 ntfs_log_error("Failed to retrieve a security descriptor\n");
1710 * Get the security descriptor associated to a file
1713 * - read the security descriptor attribute (v1.x format)
1714 * - or find the descriptor in $Secure:$SDS (v3.x format)
1716 * in both case, sanity checks are done on the attribute and
1717 * the descriptor can be assumed safe
1719 * The returned descriptor is dynamically allocated and has to be freed
1722 static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni)
1724 SII_INDEX_KEY securid;
1729 * Warning : in some situations, after fixing by chkdsk,
1730 * v3_Extensions are marked present (long standard informations)
1731 * with a default security descriptor inserted in an
1734 if (test_nino_flag(ni, v3_Extensions)
1735 && vol->secure_ni && ni->security_id) {
1736 /* get v3.x descriptor in $Secure */
1737 securid.security_id = ni->security_id;
1738 securattr = retrievesecurityattr(vol,securid);
1740 ntfs_log_error("Bad security descriptor for 0x%lx\n",
1741 (long)le32_to_cpu(ni->security_id));
1743 /* get v1.x security attribute */
1745 securattr = ntfs_attr_readall(ni, AT_SECURITY_DESCRIPTOR,
1746 AT_UNNAMED, 0, &readallsz);
1747 if (securattr && !ntfs_valid_descr(securattr, readallsz)) {
1748 ntfs_log_error("Bad security descriptor for inode %lld\n",
1749 (long long)ni->mft_no);
1751 securattr = (char*)NULL;
1756 * in some situations, there is no security
1757 * descriptor, and chkdsk does not detect or fix
1758 * anything. This could be a normal situation.
1759 * When this happens, simulate a descriptor with
1760 * minimum rights, so that a real descriptor can
1761 * be created by chown or chmod
1763 ntfs_log_error("No security descriptor found for inode %lld\n",
1764 (long long)ni->mft_no);
1765 securattr = ntfs_build_descr(0, 0, adminsid, adminsid);
1773 * Determine which access types to a file are allowed
1774 * according to the relation of current process to the file
1776 * Do not call if default_permissions is set
1779 static int access_check_posix(struct SECURITY_CONTEXT *scx,
1780 struct POSIX_SECURITY *pxdesc, mode_t request,
1781 uid_t uid, gid_t gid)
1783 struct POSIX_ACE *pxace;
1792 perms = pxdesc->mode;
1793 /* owner and root access */
1794 if (!scx->uid || (uid == scx->uid)) {
1796 /* root access if owner or other execution */
1800 /* root access if some group execution */
1803 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1804 pxace = &pxdesc->acl.ace[i];
1805 switch (pxace->tag) {
1806 case POSIX_ACL_USER_OBJ :
1807 case POSIX_ACL_GROUP_OBJ :
1808 case POSIX_ACL_GROUP :
1809 groupperms |= pxace->perms;
1811 case POSIX_ACL_MASK :
1812 mask = pxace->perms & 7;
1818 perms = (groupperms & mask & 1) | 6;
1824 * analyze designated users, get mask
1825 * and identify whether we need to check
1826 * the group memberships. The groups are
1827 * not needed when all groups have the
1828 * same permissions as other for the
1835 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1836 pxace = &pxdesc->acl.ace[i];
1837 switch (pxace->tag) {
1838 case POSIX_ACL_USER :
1839 if ((uid_t)pxace->id == scx->uid)
1840 userperms = pxace->perms;
1842 case POSIX_ACL_MASK :
1843 mask = pxace->perms & 7;
1845 case POSIX_ACL_GROUP_OBJ :
1846 case POSIX_ACL_GROUP :
1847 if (((pxace->perms & mask) ^ perms)
1848 & (request >> 6) & 7)
1855 /* designated users */
1857 perms = (perms & 07000) + (userperms & mask);
1858 else if (!needgroups)
1862 if (!(~(perms >> 3) & request & mask)
1863 && ((gid == scx->gid)
1864 || groupmember(scx, scx->uid, gid)))
1870 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1871 pxace = &pxdesc->acl.ace[i];
1872 if ((pxace->tag == POSIX_ACL_GROUP)
1873 && groupmember(scx, uid, pxace->id)) {
1874 if (!(~pxace->perms & request & mask))
1875 groupperms = pxace->perms;
1879 if (groupperms >= 0)
1880 perms = (perms & 07000) + (groupperms & mask);
1893 * Get permissions to access a file
1894 * Takes into account the relation of user to file (owner, group, ...)
1895 * Do no use as mode of the file
1896 * Do no call if default_permissions is set
1898 * returns -1 if there is a problem
1901 static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
1902 ntfs_inode * ni, mode_t request)
1904 const SECURITY_DESCRIPTOR_RELATIVE *phead;
1905 const struct CACHED_PERMISSIONS *cached;
1907 const SID *usid; /* owner of file/directory */
1908 const SID *gsid; /* group of file/directory */
1913 struct POSIX_SECURITY *pxdesc;
1915 if (!scx->mapping[MAPUSERS])
1918 /* check whether available in cache */
1919 cached = fetch_cache(scx,ni);
1923 perm = access_check_posix(scx,cached->pxdesc,request,uid,gid);
1925 perm = 0; /* default to no permission */
1926 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
1927 != const_cpu_to_le16(0);
1928 securattr = getsecurityattr(scx->vol, ni);
1930 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
1932 gsid = (const SID*)&
1933 securattr[le32_to_cpu(phead->group)];
1934 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
1936 usid = ntfs_acl_owner(securattr);
1937 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
1940 perm = pxdesc->mode & 07777;
1943 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
1945 usid = (const SID*)&
1946 securattr[le32_to_cpu(phead->owner)];
1947 pxdesc = ntfs_build_permissions_posix(scx,securattr,
1950 perm = pxdesc->mode & 07777;
1953 if (!perm && ntfs_same_sid(usid, adminsid)) {
1954 uid = find_tenant(scx, securattr);
1958 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
1961 * Create a security id if there were none
1962 * and upgrade option is selected
1964 if (!test_nino_flag(ni, v3_Extensions)
1966 && (scx->vol->secure_flags
1967 & (1 << SECURITY_ADDSECURIDS))) {
1968 upgrade_secur_desc(scx->vol,
1971 * fetch owner and group for cacheing
1972 * if there is a securid
1975 if (test_nino_flag(ni, v3_Extensions)
1977 enter_cache(scx, ni, uid,
1981 perm = access_check_posix(scx,pxdesc,request,uid,gid);
1997 * returns size or -errno if there is a problem
1998 * if size was too small, no copy is done and errno is not set,
1999 * the caller is expected to issue a new call
2002 int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2003 const char *name, char *value, size_t size)
2005 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2006 struct POSIX_SECURITY *pxdesc;
2007 const struct CACHED_PERMISSIONS *cached;
2009 const SID *usid; /* owner of file/directory */
2010 const SID *gsid; /* group of file/directory */
2016 outsize = 0; /* default to error */
2017 if (!scx->mapping[MAPUSERS])
2020 /* check whether available in cache */
2021 cached = fetch_cache(scx,ni);
2023 pxdesc = cached->pxdesc;
2025 securattr = getsecurityattr(scx->vol, ni);
2026 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2027 != const_cpu_to_le16(0);
2030 (const SECURITY_DESCRIPTOR_RELATIVE*)
2032 gsid = (const SID*)&
2033 securattr[le32_to_cpu(phead->group)];
2035 usid = ntfs_acl_owner(securattr);
2037 usid = (const SID*)&
2038 securattr[le32_to_cpu(phead->owner)];
2040 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2044 * fetch owner and group for cacheing
2048 * Create a security id if there were none
2049 * and upgrade option is selected
2051 if (!test_nino_flag(ni, v3_Extensions)
2052 && (scx->vol->secure_flags
2053 & (1 << SECURITY_ADDSECURIDS))) {
2054 upgrade_secur_desc(scx->vol,
2058 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2060 if (!(pxdesc->mode & 07777)
2061 && ntfs_same_sid(usid, adminsid)) {
2062 uid = find_tenant(scx,
2065 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2067 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2068 if (pxdesc->tagsset & POSIX_ACL_EXTENSIONS)
2069 enter_cache(scx, ni, uid,
2074 pxdesc = (struct POSIX_SECURITY*)NULL;
2078 if (ntfs_valid_posix(pxdesc)) {
2079 if (!strcmp(name,"system.posix_acl_default")) {
2081 & MFT_RECORD_IS_DIRECTORY)
2082 outsize = sizeof(struct POSIX_ACL)
2083 + pxdesc->defcnt*sizeof(struct POSIX_ACE);
2086 * getting default ACL from plain file :
2087 * return EACCES if size > 0 as
2088 * indicated in the man, but return ok
2089 * if size == 0, so that ls does not
2096 outsize = sizeof(struct POSIX_ACL);
2098 if (outsize && (outsize <= size)) {
2099 memcpy(value,&pxdesc->acl,sizeof(struct POSIX_ACL));
2100 memcpy(&value[sizeof(struct POSIX_ACL)],
2101 &pxdesc->acl.ace[pxdesc->firstdef],
2102 outsize-sizeof(struct POSIX_ACL));
2105 outsize = sizeof(struct POSIX_ACL)
2106 + pxdesc->acccnt*sizeof(struct POSIX_ACE);
2107 if (outsize <= size)
2108 memcpy(value,&pxdesc->acl,outsize);
2113 ntfs_log_error("Invalid Posix ACL built\n");
2120 return (outsize ? (int)outsize : -errno);
2123 #else /* POSIXACLS */
2127 * Get permissions to access a file
2128 * Takes into account the relation of user to file (owner, group, ...)
2129 * Do no use as mode of the file
2131 * returns -1 if there is a problem
2134 static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
2135 ntfs_inode *ni, mode_t request)
2137 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2138 const struct CACHED_PERMISSIONS *cached;
2140 const SID *usid; /* owner of file/directory */
2141 const SID *gsid; /* group of file/directory */
2147 if (!scx->mapping[MAPUSERS] || (!scx->uid && !(request & S_IEXEC)))
2150 /* check whether available in cache */
2151 cached = fetch_cache(scx,ni);
2153 perm = cached->mode;
2157 perm = 0; /* default to no permission */
2158 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2159 != const_cpu_to_le16(0);
2160 securattr = getsecurityattr(scx->vol, ni);
2162 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2164 gsid = (const SID*)&
2165 securattr[le32_to_cpu(phead->group)];
2166 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2168 usid = ntfs_acl_owner(securattr);
2169 perm = ntfs_build_permissions(securattr,
2171 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2173 usid = (const SID*)&
2174 securattr[le32_to_cpu(phead->owner)];
2175 perm = ntfs_build_permissions(securattr,
2177 if (!perm && ntfs_same_sid(usid, adminsid)) {
2178 uid = find_tenant(scx, securattr);
2182 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2185 * Create a security id if there were none
2186 * and upgrade option is selected
2188 if (!test_nino_flag(ni, v3_Extensions)
2190 && (scx->vol->secure_flags
2191 & (1 << SECURITY_ADDSECURIDS))) {
2192 upgrade_secur_desc(scx->vol,
2195 * fetch owner and group for cacheing
2196 * if there is a securid
2199 if (test_nino_flag(ni, v3_Extensions)
2201 enter_cache(scx, ni, uid,
2212 /* root access and execution */
2218 if (uid == scx->uid)
2222 * avoid checking group membership
2223 * when the requested perms for group
2224 * are the same as perms for other
2226 if ((gid == scx->gid)
2227 || ((((perm >> 3) ^ perm)
2228 & (request >> 6) & 7)
2229 && groupmember(scx, scx->uid, gid)))
2238 #endif /* POSIXACLS */
2243 * Returns size or -errno if there is a problem
2244 * if size was too small, no copy is done and errno is not set,
2245 * the caller is expected to issue a new call
2248 int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2249 char *value, size_t size)
2254 outsize = 0; /* default to no data and no error */
2255 securattr = getsecurityattr(scx->vol, ni);
2257 outsize = ntfs_attr_size(securattr);
2258 if (outsize <= size) {
2259 memcpy(value,securattr,outsize);
2263 return (outsize ? (int)outsize : -errno);
2267 * Get owner, group and permissions in an stat structure
2268 * returns permissions, or -1 if there is a problem
2271 int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
2272 ntfs_inode * ni, struct stat *stbuf)
2274 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2276 const SID *usid; /* owner of file/directory */
2277 const SID *gsid; /* group of file/directory */
2278 const struct CACHED_PERMISSIONS *cached;
2282 struct POSIX_SECURITY *pxdesc;
2285 if (!scx->mapping[MAPUSERS])
2288 /* check whether available in cache */
2289 cached = fetch_cache(scx,ni);
2291 perm = cached->mode;
2292 stbuf->st_uid = cached->uid;
2293 stbuf->st_gid = cached->gid;
2294 stbuf->st_mode = (stbuf->st_mode & ~07777) + perm;
2296 perm = -1; /* default to error */
2297 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2298 != const_cpu_to_le16(0);
2299 securattr = getsecurityattr(scx->vol, ni);
2302 (const SECURITY_DESCRIPTOR_RELATIVE*)
2304 gsid = (const SID*)&
2305 securattr[le32_to_cpu(phead->group)];
2307 usid = ntfs_acl_owner(securattr);
2309 usid = (const SID*)&
2310 securattr[le32_to_cpu(phead->owner)];
2313 pxdesc = ntfs_build_permissions_posix(scx->mapping, securattr,
2316 perm = pxdesc->mode & 07777;
2320 perm = ntfs_build_permissions(securattr,
2324 * fetch owner and group for cacheing
2328 * Create a security id if there were none
2329 * and upgrade option is selected
2331 if (!test_nino_flag(ni, v3_Extensions)
2332 && (scx->vol->secure_flags
2333 & (1 << SECURITY_ADDSECURIDS))) {
2334 upgrade_secur_desc(scx->vol,
2338 stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2340 if (!perm && ntfs_same_sid(usid, adminsid)) {
2347 stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2349 stbuf->st_gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2351 (stbuf->st_mode & ~07777) + perm;
2353 enter_cache(scx, ni, stbuf->st_uid,
2354 stbuf->st_gid, pxdesc);
2357 enter_cache(scx, ni, stbuf->st_uid,
2358 stbuf->st_gid, perm);
2371 * Get the base for a Posix inheritance and
2372 * build an inherited Posix descriptor
2375 static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx,
2376 ntfs_inode *dir_ni, mode_t mode, BOOL isdir)
2378 const struct CACHED_PERMISSIONS *cached;
2379 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2380 struct POSIX_SECURITY *pxdesc;
2381 struct POSIX_SECURITY *pydesc;
2388 pydesc = (struct POSIX_SECURITY*)NULL;
2389 /* check whether parent directory is available in cache */
2390 cached = fetch_cache(scx,dir_ni);
2394 pxdesc = cached->pxdesc;
2396 pydesc = ntfs_build_inherited_posix(pxdesc,mode,
2400 securattr = getsecurityattr(scx->vol, dir_ni);
2402 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2404 gsid = (const SID*)&
2405 securattr[le32_to_cpu(phead->group)];
2406 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2408 usid = ntfs_acl_owner(securattr);
2409 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2411 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2413 usid = (const SID*)&
2414 securattr[le32_to_cpu(phead->owner)];
2415 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2417 if (pxdesc && ntfs_same_sid(usid, adminsid)) {
2418 uid = find_tenant(scx, securattr);
2420 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2424 * Create a security id if there were none
2425 * and upgrade option is selected
2427 if (!test_nino_flag(dir_ni, v3_Extensions)
2428 && (scx->vol->secure_flags
2429 & (1 << SECURITY_ADDSECURIDS))) {
2430 upgrade_secur_desc(scx->vol,
2433 * fetch owner and group for cacheing
2434 * if there is a securid
2437 if (test_nino_flag(dir_ni, v3_Extensions)) {
2438 enter_cache(scx, dir_ni, uid,
2441 pydesc = ntfs_build_inherited_posix(pxdesc,
2442 mode, scx->umask, isdir);
2452 * Allocate a security_id for a file being created
2454 * Returns zero if not possible (NTFS v3.x required)
2457 le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
2458 uid_t uid, gid_t gid, ntfs_inode *dir_ni,
2459 mode_t mode, BOOL isdir)
2461 #if !FORCE_FORMAT_v1x
2462 const struct CACHED_SECURID *cached;
2463 struct CACHED_SECURID wanted;
2464 struct POSIX_SECURITY *pxdesc;
2474 securid = const_cpu_to_le32(0);
2476 #if !FORCE_FORMAT_v1x
2478 pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
2480 /* check whether target securid is known in cache */
2484 wanted.dmode = pxdesc->mode & mode & 07777;
2485 if (isdir) wanted.dmode |= 0x10000;
2486 wanted.variable = (void*)pxdesc;
2487 wanted.varsize = sizeof(struct POSIX_SECURITY)
2488 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2489 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2490 scx->vol->securid_cache, GENERIC(&wanted),
2491 (cache_compare)compare);
2492 /* quite simple, if we are lucky */
2494 securid = cached->securid;
2496 /* not in cache : make sure we can create ids */
2498 if (!cached && (scx->vol->major_ver >= 3)) {
2499 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2500 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2501 if (!usid || !gsid) {
2502 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2503 (int)uid, (int)gid);
2504 usid = gsid = adminsid;
2506 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2509 newattrsz = ntfs_attr_size(newattr);
2510 securid = setsecurityattr(scx->vol,
2511 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
2514 /* update cache, for subsequent use */
2515 wanted.securid = securid;
2516 ntfs_enter_cache(scx->vol->securid_cache,
2518 (cache_compare)compare);
2523 * could not build new security attribute
2524 * errno set by ntfs_build_descr()
2535 * Apply Posix inheritance to a newly created file
2536 * (for NTFS 1.x only : no securid)
2539 int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
2540 ntfs_inode *ni, uid_t uid, gid_t gid,
2541 ntfs_inode *dir_ni, mode_t mode)
2543 struct POSIX_SECURITY *pxdesc;
2553 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2554 pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
2556 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2557 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2558 if (!usid || !gsid) {
2559 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2560 (int)uid, (int)gid);
2561 usid = gsid = adminsid;
2563 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2566 /* Adjust Windows read-only flag */
2567 res = update_secur_descr(scx->vol, newattr, ni);
2568 if (!res && !isdir) {
2570 ni->flags &= ~FILE_ATTR_READONLY;
2572 ni->flags |= FILE_ATTR_READONLY;
2574 #if CACHE_LEGACY_SIZE
2575 /* also invalidate legacy cache */
2576 if (isdir && !ni->security_id) {
2577 struct CACHED_PERMISSIONS_LEGACY legacy;
2579 legacy.mft_no = ni->mft_no;
2580 legacy.variable = pxdesc;
2581 legacy.varsize = sizeof(struct POSIX_SECURITY)
2582 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2583 ntfs_invalidate_cache(scx->vol->legacy_cache,
2585 (cache_compare)leg_compare,0);
2592 * could not build new security attribute
2593 * errno set by ntfs_build_descr()
2602 le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
2603 uid_t uid, gid_t gid, mode_t mode, BOOL isdir)
2605 #if !FORCE_FORMAT_v1x
2606 const struct CACHED_SECURID *cached;
2607 struct CACHED_SECURID wanted;
2617 securid = const_cpu_to_le32(0);
2619 #if !FORCE_FORMAT_v1x
2620 /* check whether target securid is known in cache */
2624 wanted.dmode = mode & 07777;
2625 if (isdir) wanted.dmode |= 0x10000;
2626 wanted.variable = (void*)NULL;
2628 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2629 scx->vol->securid_cache, GENERIC(&wanted),
2630 (cache_compare)compare);
2631 /* quite simple, if we are lucky */
2633 securid = cached->securid;
2635 /* not in cache : make sure we can create ids */
2637 if (!cached && (scx->vol->major_ver >= 3)) {
2638 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2639 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2640 if (!usid || !gsid) {
2641 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2642 (int)uid, (int)gid);
2643 usid = gsid = adminsid;
2645 newattr = ntfs_build_descr(mode, isdir, usid, gsid);
2647 newattrsz = ntfs_attr_size(newattr);
2648 securid = setsecurityattr(scx->vol,
2649 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
2652 /* update cache, for subsequent use */
2653 wanted.securid = securid;
2654 ntfs_enter_cache(scx->vol->securid_cache,
2656 (cache_compare)compare);
2661 * could not build new security attribute
2662 * errno set by ntfs_build_descr()
2673 * Update ownership and mode of a file, reusing an existing
2674 * security descriptor when possible
2676 * Returns zero if successful
2680 int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2681 uid_t uid, gid_t gid, mode_t mode,
2682 struct POSIX_SECURITY *pxdesc)
2684 int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2685 uid_t uid, gid_t gid, mode_t mode)
2689 const struct CACHED_SECURID *cached;
2690 struct CACHED_SECURID wanted;
2700 /* check whether target securid is known in cache */
2702 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2705 wanted.dmode = mode & 07777;
2706 if (isdir) wanted.dmode |= 0x10000;
2708 wanted.variable = (void*)pxdesc;
2710 wanted.varsize = sizeof(struct POSIX_SECURITY)
2711 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2715 wanted.variable = (void*)NULL;
2718 if (test_nino_flag(ni, v3_Extensions)) {
2719 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2720 scx->vol->securid_cache, GENERIC(&wanted),
2721 (cache_compare)compare);
2722 /* quite simple, if we are lucky */
2724 ni->security_id = cached->securid;
2727 } else cached = (struct CACHED_SECURID*)NULL;
2731 * Do not use usid and gsid from former attributes,
2732 * but recompute them to get repeatable results
2733 * which can be kept in cache.
2735 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2736 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2737 if (!usid || !gsid) {
2738 ntfs_log_error("File made owned by an unmapped user/group %d/%d\n",
2740 usid = gsid = adminsid;
2744 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2747 newattr = ntfs_build_descr(mode,
2750 newattr = ntfs_build_descr(mode,
2754 res = update_secur_descr(scx->vol, newattr, ni);
2756 /* adjust Windows read-only flag */
2759 ni->flags &= ~FILE_ATTR_READONLY;
2761 ni->flags |= FILE_ATTR_READONLY;
2762 NInoFileNameSetDirty(ni);
2764 /* update cache, for subsequent use */
2765 if (test_nino_flag(ni, v3_Extensions)) {
2766 wanted.securid = ni->security_id;
2767 ntfs_enter_cache(scx->vol->securid_cache,
2769 (cache_compare)compare);
2771 #if CACHE_LEGACY_SIZE
2772 /* also invalidate legacy cache */
2773 if (isdir && !ni->security_id) {
2774 struct CACHED_PERMISSIONS_LEGACY legacy;
2776 legacy.mft_no = ni->mft_no;
2778 legacy.variable = wanted.variable;
2779 legacy.varsize = wanted.varsize;
2781 legacy.variable = (void*)NULL;
2784 ntfs_invalidate_cache(scx->vol->legacy_cache,
2786 (cache_compare)leg_compare,0);
2793 * could not build new security attribute
2794 * errno set by ntfs_build_descr()
2803 * Check whether user has ownership rights on a file
2805 * Returns TRUE if allowed
2806 * if not, errno tells why
2809 BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni)
2811 const struct CACHED_PERMISSIONS *cached;
2819 processuid = scx->uid;
2820 /* TODO : use CAP_FOWNER process capability */
2822 * Always allow for root
2823 * Also always allow if no mapping has been defined
2825 if (!scx->mapping[MAPUSERS] || !processuid)
2828 gotowner = FALSE; /* default */
2829 /* get the owner, either from cache or from old attribute */
2830 cached = fetch_cache(scx, ni);
2835 oldattr = getsecurityattr(scx->vol, ni);
2838 usid = ntfs_acl_owner(oldattr);
2840 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2842 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2844 usid = (const SID*)&oldattr
2845 [le32_to_cpu(phead->owner)];
2847 uid = ntfs_find_user(scx->mapping[MAPUSERS],
2855 /* TODO : use CAP_FOWNER process capability */
2856 if (!processuid || (processuid == uid))
2865 #ifdef HAVE_SETXATTR /* extended attributes interface required */
2870 * Set a new access or default Posix ACL to a file
2871 * (or remove ACL if no input data)
2872 * Validity of input data is checked after merging
2874 * Returns 0, or -1 if there is a problem which errno describes
2877 int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2878 const char *name, const char *value, size_t size,
2881 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2882 const struct CACHED_PERMISSIONS *cached;
2894 struct POSIX_SECURITY *oldpxdesc;
2895 struct POSIX_SECURITY *newpxdesc;
2897 /* get the current pxsec, either from cache or from old attribute */
2899 deflt = !strcmp(name,"system.posix_acl_default");
2901 count = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE);
2904 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2905 newpxdesc = (struct POSIX_SECURITY*)NULL;
2907 || (((const struct POSIX_ACL*)value)->version == POSIX_VERSION))
2908 && (!deflt || isdir || (!size && !value))) {
2909 cached = fetch_cache(scx, ni);
2913 oldpxdesc = cached->pxdesc;
2915 newpxdesc = ntfs_replace_acl(oldpxdesc,
2916 (const struct POSIX_ACL*)value,count,deflt);
2919 oldattr = getsecurityattr(scx->vol, ni);
2921 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
2923 usid = ntfs_acl_owner(oldattr);
2925 usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
2927 gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
2928 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2929 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2930 oldpxdesc = ntfs_build_permissions_posix(scx->mapping,
2931 oldattr, usid, gsid, isdir);
2934 exist = oldpxdesc->defcnt > 0;
2936 exist = oldpxdesc->acccnt > 3;
2937 if ((exist && (flags & XATTR_CREATE))
2938 || (!exist && (flags & XATTR_REPLACE))) {
2939 errno = (exist ? EEXIST : ENODATA);
2941 newpxdesc = ntfs_replace_acl(oldpxdesc,
2942 (const struct POSIX_ACL*)value,count,deflt);
2953 processuid = scx->uid;
2954 /* TODO : use CAP_FOWNER process capability */
2955 if (!processuid || (uid == processuid)) {
2957 * clear setgid if file group does
2958 * not match process group
2960 if (processuid && (gid != scx->gid)
2961 && !groupmember(scx, scx->uid, gid)) {
2962 newpxdesc->mode &= ~S_ISGID;
2964 res = ntfs_set_owner_mode(scx, ni, uid, gid,
2965 newpxdesc->mode, newpxdesc);
2970 return (res ? -1 : 0);
2974 * Remove a default Posix ACL from a file
2976 * Returns 0, or -1 if there is a problem which errno describes
2979 int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2982 return (ntfs_set_posix_acl(scx, ni, name,
2983 (const char*)NULL, 0, 0));
2989 * Set a new NTFS ACL to a file
2991 * Returns 0, or -1 if there is a problem
2994 int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2995 const char *value, size_t size, int flags)
3002 && !(flags & XATTR_CREATE)
3003 && ntfs_valid_descr(value,size)
3004 && (ntfs_attr_size(value) == size)) {
3005 /* need copying in order to write */
3006 attr = (char*)ntfs_malloc(size);
3008 memcpy(attr,value,size);
3009 res = update_secur_descr(scx->vol, attr, ni);
3011 * No need to invalidate standard caches :
3012 * the relation between a securid and
3013 * the associated protection is unchanged,
3014 * only the relation between a file and
3015 * its securid and protection is changed.
3017 #if CACHE_LEGACY_SIZE
3019 * we must however invalidate the legacy
3020 * cache, which is based on inode numbers.
3021 * For safety, invalidate even if updating
3024 if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3025 && !ni->security_id) {
3026 struct CACHED_PERMISSIONS_LEGACY legacy;
3028 legacy.mft_no = ni->mft_no;
3029 legacy.variable = (char*)NULL;
3031 ntfs_invalidate_cache(scx->vol->legacy_cache,
3033 (cache_compare)leg_compare,0);
3041 return (res ? -1 : 0);
3044 #endif /* HAVE_SETXATTR */
3047 * Set new permissions to a file
3048 * Checks user mapping has been defined before request for setting
3050 * rejected if request is not originated by owner or root
3052 * returns 0 on success
3053 * -1 on failure, with errno = EIO
3056 int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode)
3058 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3059 const struct CACHED_PERMISSIONS *cached;
3070 const struct POSIX_SECURITY *oldpxdesc;
3071 struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
3074 /* get the current owner, either from cache or from old attribute */
3076 cached = fetch_cache(scx, ni);
3081 oldpxdesc = cached->pxdesc;
3083 /* must copy before merging */
3084 pxsize = sizeof(struct POSIX_SECURITY)
3085 + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
3086 newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
3088 memcpy(newpxdesc, oldpxdesc, pxsize);
3089 if (ntfs_merge_mode_posix(newpxdesc, mode))
3094 newpxdesc = (struct POSIX_SECURITY*)NULL;
3097 oldattr = getsecurityattr(scx->vol, ni);
3099 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
3101 usid = ntfs_acl_owner(oldattr);
3103 usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
3105 gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
3106 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3107 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3109 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
3110 newpxdesc = ntfs_build_permissions_posix(scx->mapping,
3111 oldattr, usid, gsid, isdir);
3112 if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
3121 processuid = scx->uid;
3122 /* TODO : use CAP_FOWNER process capability */
3123 if (!processuid || (uid == processuid)) {
3125 * clear setgid if file group does
3126 * not match process group
3128 if (processuid && (gid != scx->gid)
3129 && !groupmember(scx, scx->uid, gid))
3133 newpxdesc->mode = mode;
3134 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3137 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3140 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3144 res = -1; /* neither owner nor root */
3148 * Should not happen : a default descriptor is generated
3149 * by getsecurityattr() when there are none
3151 ntfs_log_error("File has no security descriptor\n");
3156 if (newpxdesc) free(newpxdesc);
3158 return (res ? -1 : 0);
3162 * Create a default security descriptor for files whose descriptor
3163 * cannot be inherited
3166 int ntfs_sd_add_everyone(ntfs_inode *ni)
3168 /* JPA SECURITY_DESCRIPTOR_ATTR *sd; */
3169 SECURITY_DESCRIPTOR_RELATIVE *sd;
3171 ACCESS_ALLOWED_ACE *ace;
3175 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
3177 * Calculate security descriptor length. We have 2 sub-authorities in
3178 * owner and group SIDs, but structure SID contain only one, so add
3179 * 4 bytes to every SID.
3181 sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
3182 sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
3183 sd = (SECURITY_DESCRIPTOR_RELATIVE*)ntfs_calloc(sd_len);
3187 sd->revision = SECURITY_DESCRIPTOR_REVISION;
3188 sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
3190 sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
3191 sid->revision = SID_REVISION;
3192 sid->sub_authority_count = 2;
3193 sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
3194 sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
3195 sid->identifier_authority.value[5] = 5;
3196 sd->owner = cpu_to_le32((u8*)sid - (u8*)sd);
3198 sid = (SID*)((u8*)sid + sizeof(SID) + 4);
3199 sid->revision = SID_REVISION;
3200 sid->sub_authority_count = 2;
3201 sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
3202 sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
3203 sid->identifier_authority.value[5] = 5;
3204 sd->group = cpu_to_le32((u8*)sid - (u8*)sd);
3206 acl = (ACL*)((u8*)sid + sizeof(SID) + 4);
3207 acl->revision = ACL_REVISION;
3208 acl->size = const_cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
3209 acl->ace_count = const_cpu_to_le16(1);
3210 sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd);
3212 ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL));
3213 ace->type = ACCESS_ALLOWED_ACE_TYPE;
3214 ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
3215 ace->size = const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
3216 ace->mask = const_cpu_to_le32(0x1f01ff); /* FIXME */
3217 ace->sid.revision = SID_REVISION;
3218 ace->sid.sub_authority_count = 1;
3219 ace->sid.sub_authority[0] = const_cpu_to_le32(0);
3220 ace->sid.identifier_authority.value[5] = 1;
3222 ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8*)sd,
3225 ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR");
3232 * Check whether user can access a file in a specific way
3234 * Returns 1 if access is allowed, including user is root or no
3235 * user mapping defined
3236 * 2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX
3237 * 0 and sets errno if there is a problem or if access
3240 * This is used for Posix ACL and checking creation of DOS file names
3243 int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
3245 int accesstype) /* access type required (S_Ixxx values) */
3253 * Always allow for root unless execution is requested.
3254 * (was checked by fuse until kernel 2.6.29)
3255 * Also always allow if no mapping has been defined
3257 if (!scx->mapping[MAPUSERS]
3259 && (!(accesstype & S_IEXEC)
3260 || (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY))))
3263 perm = ntfs_get_perm(scx, ni, accesstype);
3266 switch (accesstype) {
3268 allow = (perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
3271 allow = (perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0;
3273 case S_IWRITE + S_IEXEC:
3274 allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3275 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3278 allow = (perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0;
3280 case S_IREAD + S_IEXEC:
3281 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3282 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3284 case S_IREAD + S_IWRITE:
3285 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3286 && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0);
3288 case S_IWRITE + S_IEXEC + S_ISVTX:
3289 if (perm & S_ISVTX) {
3290 if ((ntfs_get_owner_mode(scx,ni,&stbuf) >= 0)
3291 && (stbuf.st_uid == scx->uid))
3296 allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3297 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3299 case S_IREAD + S_IWRITE + S_IEXEC:
3300 allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3301 && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3302 && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3317 #if 0 /* not needed any more */
3320 * Check whether user can access the parent directory
3321 * of a file in a specific way
3323 * Returns true if access is allowed, including user is root and
3324 * no user mapping defined
3326 * Sets errno if there is a problem or if not allowed
3328 * This is used for Posix ACL and checking creation of DOS file names
3331 BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
3332 const char *path, int accesstype)
3342 dirpath = strdup(path);
3344 /* the root of file system is seen as a parent of itself */
3345 /* is that correct ? */
3346 name = strrchr(dirpath, '/');
3348 dir_ni = ntfs_pathname_to_inode(scx->vol, NULL, dirpath);
3350 allow = ntfs_allowed_access(scx,
3351 dir_ni, accesstype);
3352 ntfs_inode_close(dir_ni);
3354 * for an not-owned sticky directory, have to
3355 * check whether file itself is owned
3357 if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX))
3359 ni = ntfs_pathname_to_inode(scx->vol, NULL,
3363 allow = (ntfs_get_owner_mode(scx,ni,&stbuf) >= 0)
3364 && (stbuf.st_uid == scx->uid);
3365 ntfs_inode_close(ni);
3371 return (allow); /* errno is set if not allowed */
3377 * Define a new owner/group to a file
3379 * returns zero if successful
3382 int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
3383 uid_t uid, gid_t gid)
3385 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3386 const struct CACHED_PERMISSIONS *cached;
3397 struct POSIX_SECURITY *pxdesc;
3398 BOOL pxdescbuilt = FALSE;
3402 /* get the current owner and mode from cache or security attributes */
3403 oldattr = (char*)NULL;
3404 cached = fetch_cache(scx,ni);
3406 fileuid = cached->uid;
3407 filegid = cached->gid;
3408 mode = cached->mode;
3410 pxdesc = cached->pxdesc;
3418 oldattr = getsecurityattr(scx->vol, ni);
3420 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3421 != const_cpu_to_le16(0);
3422 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
3425 &oldattr[le32_to_cpu(phead->group)];
3427 usid = ntfs_acl_owner(oldattr);
3430 &oldattr[le32_to_cpu(phead->owner)];
3433 pxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
3437 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3438 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3439 mode = perm = pxdesc->mode;
3443 mode = perm = ntfs_build_permissions(oldattr,
3446 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3447 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3456 /* check requested by root */
3457 /* or chgrp requested by owner to an owned group */
3459 || ((((int)uid < 0) || (uid == fileuid))
3460 && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
3461 && (fileuid == scx->uid))) {
3462 /* replace by the new usid and gsid */
3463 /* or reuse old gid and sid for cacheing */
3468 /* clear setuid and setgid if owner has changed */
3469 /* unless request originated by root */
3470 if (uid && (fileuid != uid))
3473 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3476 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3479 res = -1; /* neither owner nor root */
3488 * Should not happen : a default descriptor is generated
3489 * by getsecurityattr() when there are none
3491 ntfs_log_error("File has no security descriptor\n");
3495 return (res ? -1 : 0);
3499 * Define new owner/group and mode to a file
3501 * returns zero if successful
3504 int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
3505 uid_t uid, gid_t gid, const mode_t mode)
3507 const struct CACHED_PERMISSIONS *cached;
3513 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3517 const struct POSIX_SECURITY *oldpxdesc;
3518 struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
3523 /* get the current owner and mode from cache or security attributes */
3524 oldattr = (char*)NULL;
3525 cached = fetch_cache(scx,ni);
3527 fileuid = cached->uid;
3528 filegid = cached->gid;
3530 oldpxdesc = cached->pxdesc;
3532 /* must copy before merging */
3533 pxsize = sizeof(struct POSIX_SECURITY)
3534 + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
3535 newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
3537 memcpy(newpxdesc, oldpxdesc, pxsize);
3538 if (ntfs_merge_mode_posix(newpxdesc, mode))
3547 oldattr = getsecurityattr(scx->vol, ni);
3550 isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3551 != const_cpu_to_le16(0);
3552 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
3555 &oldattr[le32_to_cpu(phead->group)];
3557 usid = ntfs_acl_owner(oldattr);
3560 &oldattr[le32_to_cpu(phead->owner)];
3562 newpxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
3564 if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
3567 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3568 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3576 /* check requested by root */
3577 /* or chgrp requested by owner to an owned group */
3579 || ((((int)uid < 0) || (uid == fileuid))
3580 && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
3581 && (fileuid == scx->uid))) {
3582 /* replace by the new usid and gsid */
3583 /* or reuse old gid and sid for cacheing */
3589 res = ntfs_set_owner_mode(scx, ni, uid, gid,
3592 res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3595 res = -1; /* neither owner nor root */
3600 * Should not happen : a default descriptor is generated
3601 * by getsecurityattr() when there are none
3603 ntfs_log_error("File has no security descriptor\n");
3610 return (res ? -1 : 0);
3614 * Build a security id for a descriptor inherited from
3615 * parent directory the Windows way
3618 static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
3619 const char *parentattr, BOOL fordir)
3621 const SECURITY_DESCRIPTOR_RELATIVE *pphead;
3630 SECURITY_DESCRIPTOR_RELATIVE *pnhead;
3641 parentattrsz = ntfs_attr_size(parentattr);
3642 pphead = (const SECURITY_DESCRIPTOR_RELATIVE*)parentattr;
3643 if (scx->mapping[MAPUSERS]) {
3644 usid = ntfs_find_usid(scx->mapping[MAPUSERS], scx->uid, (SID*)&defusid);
3645 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS], scx->gid, (SID*)&defgsid);
3652 * If there is no user mapping, we have to copy owner
3653 * and group from parent directory.
3654 * Windows never has to do that, because it can always
3655 * rely on a user mapping
3657 offowner = le32_to_cpu(pphead->owner);
3658 usid = (const SID*)&parentattr[offowner];
3659 offgroup = le32_to_cpu(pphead->group);
3660 gsid = (const SID*)&parentattr[offgroup];
3663 * new attribute is smaller than parent's
3664 * except for differences in SIDs which appear in
3665 * owner, group and possible grants and denials in
3666 * generic creator-owner and creator-group ACEs.
3667 * For directories, an ACE may be duplicated for
3668 * access and inheritance, so we double the count.
3670 usidsz = ntfs_sid_size(usid);
3671 gsidsz = ntfs_sid_size(gsid);
3672 newattrsz = parentattrsz + 3*usidsz + 3*gsidsz;
3675 newattr = (char*)ntfs_malloc(newattrsz);
3677 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr;
3678 pnhead->revision = SECURITY_DESCRIPTOR_REVISION;
3679 pnhead->alignment = 0;
3680 pnhead->control = SE_SELF_RELATIVE;
3681 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
3683 * locate and inherit DACL
3684 * do not test SE_DACL_PRESENT (wrong for "DR Watson")
3686 pnhead->dacl = const_cpu_to_le32(0);
3688 offpacl = le32_to_cpu(pphead->dacl);
3689 ppacl = (const ACL*)&parentattr[offpacl];
3690 pnacl = (ACL*)&newattr[pos];
3691 aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
3693 pnhead->dacl = cpu_to_le32(pos);
3695 pnhead->control |= SE_DACL_PRESENT;
3699 * locate and inherit SACL
3701 pnhead->sacl = const_cpu_to_le32(0);
3703 offpacl = le32_to_cpu(pphead->sacl);
3704 ppacl = (const ACL*)&parentattr[offpacl];
3705 pnacl = (ACL*)&newattr[pos];
3706 aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
3708 pnhead->sacl = cpu_to_le32(pos);
3710 pnhead->control |= SE_SACL_PRESENT;
3714 * inherit or redefine owner
3716 memcpy(&newattr[pos],usid,usidsz);
3717 pnhead->owner = cpu_to_le32(pos);
3720 * inherit or redefine group
3722 memcpy(&newattr[pos],gsid,gsidsz);
3723 pnhead->group = cpu_to_le32(pos);
3725 securid = setsecurityattr(scx->vol,
3726 (SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos);
3729 securid = const_cpu_to_le32(0);
3734 * Get an inherited security id
3736 * For Windows compatibility, the normal initial permission setting
3737 * may be inherited from the parent directory instead of being
3738 * defined by the creation arguments.
3740 * The following creates an inherited id for that purpose.
3742 * Note : the owner and group of parent directory are also
3743 * inherited (which is not the case on Windows) if no user mapping
3746 * Returns the inherited id, or zero if not possible (eg on NTFS 1.x)
3749 le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
3750 ntfs_inode *dir_ni, BOOL fordir)
3752 struct CACHED_PERMISSIONS *cached;
3756 securid = const_cpu_to_le32(0);
3757 cached = (struct CACHED_PERMISSIONS*)NULL;
3759 * Try to get inherited id from cache
3761 if (test_nino_flag(dir_ni, v3_Extensions)
3762 && dir_ni->security_id) {
3763 cached = fetch_cache(scx, dir_ni);
3765 securid = (fordir ? cached->inh_dirid
3766 : cached->inh_fileid);
3769 * Not cached or not available in cache, compute it all
3770 * Note : if parent directory has no id, it is not cacheable
3773 parentattr = getsecurityattr(scx->vol, dir_ni);
3775 securid = build_inherited_id(scx,
3776 parentattr, fordir);
3779 * Store the result into cache for further use
3782 cached = fetch_cache(scx, dir_ni);
3785 cached->inh_dirid = securid;
3787 cached->inh_fileid = securid;
3796 * Link a group to a member of group
3798 * Returns 0 if OK, -1 (and errno set) if error
3801 static int link_single_group(struct MAPPING *usermapping, struct passwd *user,
3804 struct group *group;
3811 group = getgrgid(gid);
3812 if (group && group->gr_mem) {
3813 grcnt = usermapping->grcnt;
3814 groups = usermapping->groups;
3815 grmem = group->gr_mem;
3816 while (*grmem && strcmp(user->pw_name, *grmem))
3820 groups = (gid_t*)malloc(sizeof(gid_t));
3822 groups = (gid_t*)realloc(groups,
3823 (grcnt+1)*sizeof(gid_t));
3825 groups[grcnt++] = gid;
3831 usermapping->grcnt = grcnt;
3832 usermapping->groups = groups;
3839 * Statically link group to users
3840 * This is based on groups defined in /etc/group and does not take
3841 * the groups dynamically set by setgroups() nor any changes in
3842 * /etc/group into account
3844 * Only mapped groups and root group are linked to mapped users
3846 * Returns 0 if OK, -1 (and errno set) if error
3850 static int link_group_members(struct SECURITY_CONTEXT *scx)
3852 struct MAPPING *usermapping;
3853 struct MAPPING *groupmapping;
3854 struct passwd *user;
3858 for (usermapping=scx->mapping[MAPUSERS]; usermapping && !res;
3859 usermapping=usermapping->next) {
3860 usermapping->grcnt = 0;
3861 usermapping->groups = (gid_t*)NULL;
3862 user = getpwuid(usermapping->xid);
3863 if (user && user->pw_name) {
3864 for (groupmapping=scx->mapping[MAPGROUPS];
3865 groupmapping && !res;
3866 groupmapping=groupmapping->next) {
3867 if (link_single_group(usermapping, user,
3871 if (!res && link_single_group(usermapping,
3880 * Apply default single user mapping
3881 * returns zero if successful
3884 static int ntfs_do_default_mapping(struct SECURITY_CONTEXT *scx,
3885 uid_t uid, gid_t gid, const SID *usid)
3887 struct MAPPING *usermapping;
3888 struct MAPPING *groupmapping;
3894 sidsz = ntfs_sid_size(usid);
3895 sid = (SID*)ntfs_malloc(sidsz);
3897 memcpy(sid,usid,sidsz);
3898 usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
3900 groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
3902 usermapping->sid = sid;
3903 usermapping->xid = uid;
3904 usermapping->next = (struct MAPPING*)NULL;
3905 groupmapping->sid = sid;
3906 groupmapping->xid = gid;
3907 groupmapping->next = (struct MAPPING*)NULL;
3908 scx->mapping[MAPUSERS] = usermapping;
3909 scx->mapping[MAPGROUPS] = groupmapping;
3918 * Make sure there are no ambiguous mapping
3919 * Ambiguous mapping may lead to undesired configurations and
3920 * we had rather be safe until the consequences are understood
3923 #if 0 /* not activated for now */
3925 static BOOL check_mapping(const struct MAPPING *usermapping,
3926 const struct MAPPING *groupmapping)
3928 const struct MAPPING *mapping1;
3929 const struct MAPPING *mapping2;
3933 for (mapping1=usermapping; mapping1; mapping1=mapping1->next)
3934 for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
3935 if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
3936 if (mapping1->xid != mapping2->xid)
3939 if (mapping1->xid == mapping2->xid)
3942 for (mapping1=groupmapping; mapping1; mapping1=mapping1->next)
3943 for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
3944 if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
3945 if (mapping1->xid != mapping2->xid)
3948 if (mapping1->xid == mapping2->xid)
3956 #if 0 /* not used any more */
3959 * Try and apply default single user mapping
3960 * returns zero if successful
3963 static int ntfs_default_mapping(struct SECURITY_CONTEXT *scx)
3965 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3972 ni = ntfs_pathname_to_inode(scx->vol, NULL, "/.");
3974 securattr = getsecurityattr(scx->vol, ni);
3976 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr;
3977 usid = (SID*)&securattr[le32_to_cpu(phead->owner)];
3978 if (ntfs_is_user_sid(usid))
3979 res = ntfs_do_default_mapping(scx,
3980 scx->uid, scx->gid, usid);
3983 ntfs_inode_close(ni);
3991 * Basic read from a user mapping file on another volume
3994 static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused)))
3996 return (read(*(int*)fileid, buf, size));
4001 * Read from a user mapping file on current NTFS partition
4004 static int localread(void *fileid, char *buf, size_t size, off_t offs)
4006 return (ntfs_attr_data_read((ntfs_inode*)fileid,
4007 AT_UNNAMED, 0, buf, size, offs));
4011 * Build the user mapping
4012 * - according to a mapping file if defined (or default present),
4013 * - or try default single user mapping if possible
4015 * The mapping is specific to a mounted device
4016 * No locking done, mounting assumed non multithreaded
4018 * returns zero if mapping is successful
4019 * (failure should not be interpreted as an error)
4022 int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
4025 struct MAPLIST *item;
4026 struct MAPLIST *firstitem;
4027 struct MAPPING *usermapping;
4028 struct MAPPING *groupmapping;
4042 1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5),
4043 const_cpu_to_le32(21),
4044 const_cpu_to_le32(DEFSECAUTH1), const_cpu_to_le32(DEFSECAUTH2),
4045 const_cpu_to_le32(DEFSECAUTH3), const_cpu_to_le32(DEFSECBASE)
4048 /* be sure not to map anything until done */
4049 scx->mapping[MAPUSERS] = (struct MAPPING*)NULL;
4050 scx->mapping[MAPGROUPS] = (struct MAPPING*)NULL;
4052 if (!usermap_path) usermap_path = MAPPINGFILE;
4053 if (usermap_path[0] == '/') {
4054 fd = open(usermap_path,O_RDONLY);
4056 firstitem = ntfs_read_mapping(basicread, (void*)&fd);
4059 firstitem = (struct MAPLIST*)NULL;
4061 ni = ntfs_pathname_to_inode(scx->vol, NULL, usermap_path);
4063 firstitem = ntfs_read_mapping(localread, ni);
4064 ntfs_inode_close(ni);
4066 firstitem = (struct MAPLIST*)NULL;
4071 usermapping = ntfs_do_user_mapping(firstitem);
4072 groupmapping = ntfs_do_group_mapping(firstitem);
4073 if (usermapping && groupmapping) {
4074 scx->mapping[MAPUSERS] = usermapping;
4075 scx->mapping[MAPGROUPS] = groupmapping;
4077 ntfs_log_error("There were no valid user or no valid group\n");
4078 /* now we can free the memory copy of input text */
4079 /* and rely on internal representation */
4081 item = firstitem->next;
4086 /* no mapping file, try a default mapping */
4088 if (!ntfs_do_default_mapping(scx,
4089 0, 0, (const SID*)&defmap))
4090 ntfs_log_info("Using default user mapping\n");
4093 return (!scx->mapping[MAPUSERS] || link_group_members(scx));
4096 #ifdef HAVE_SETXATTR /* extended attributes interface required */
4099 * Get the ntfs attribute into an extended attribute
4100 * The attribute is returned according to cpu endianness
4103 int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size)
4108 outsize = 0; /* default to no data and no error */
4110 attrib = le32_to_cpu(ni->flags);
4111 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
4112 attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4114 attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4116 attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
4117 outsize = sizeof(FILE_ATTR_FLAGS);
4118 if (size >= outsize) {
4120 memcpy(value,&attrib,outsize);
4125 return (outsize ? (int)outsize : -errno);
4129 * Return the ntfs attribute into an extended attribute
4130 * The attribute is expected according to cpu endianness
4132 * Returns 0, or -1 if there is a problem
4135 int ntfs_set_ntfs_attrib(ntfs_inode *ni,
4136 const char *value, size_t size, int flags)
4140 ATTR_FLAGS dirflags;
4144 if (ni && value && (size >= sizeof(FILE_ATTR_FLAGS))) {
4145 if (!(flags & XATTR_CREATE)) {
4146 /* copy to avoid alignment problems */
4147 memcpy(&attrib,value,sizeof(FILE_ATTR_FLAGS));
4148 settable = FILE_ATTR_SETTABLE;
4150 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4152 * Accept changing compression for a directory
4153 * and set index root accordingly
4155 settable |= FILE_ATTR_COMPRESSED;
4156 if ((ni->flags ^ cpu_to_le32(attrib))
4157 & FILE_ATTR_COMPRESSED) {
4158 if (ni->flags & FILE_ATTR_COMPRESSED)
4159 dirflags = const_cpu_to_le16(0);
4161 dirflags = ATTR_IS_COMPRESSED;
4162 res = ntfs_attr_set_flags(ni,
4166 ATTR_COMPRESSION_MASK);
4170 ni->flags = (ni->flags & ~settable)
4171 | (cpu_to_le32(attrib) & settable);
4172 NInoFileNameSetDirty(ni);
4179 return (res ? -1 : 0);
4182 #endif /* HAVE_SETXATTR */
4185 * Open $Secure once for all
4186 * returns zero if it succeeds
4187 * non-zero if it fails. This is not an error (on NTFS v1.x)
4191 int ntfs_open_secure(ntfs_volume *vol)
4197 vol->secure_ni = (ntfs_inode*)NULL;
4198 vol->secure_xsii = (ntfs_index_context*)NULL;
4199 vol->secure_xsdh = (ntfs_index_context*)NULL;
4200 if (vol->major_ver >= 3) {
4201 /* make sure this is a genuine $Secure inode 9 */
4202 ni = ntfs_pathname_to_inode(vol, NULL, "$Secure");
4203 if (ni && (ni->mft_no == 9)) {
4204 vol->secure_reentry = 0;
4205 vol->secure_xsii = ntfs_index_ctx_get(ni,
4207 vol->secure_xsdh = ntfs_index_ctx_get(ni,
4209 if (ni && vol->secure_xsii && vol->secure_xsdh) {
4210 vol->secure_ni = ni;
4220 * Allocated memory is freed to facilitate the detection of memory leaks
4223 void ntfs_close_secure(struct SECURITY_CONTEXT *scx)
4228 if (vol->secure_ni) {
4229 ntfs_index_ctx_put(vol->secure_xsii);
4230 ntfs_index_ctx_put(vol->secure_xsdh);
4231 ntfs_inode_close(vol->secure_ni);
4234 ntfs_free_mapping(scx->mapping);
4239 * API for direct access to security descriptors
4240 * based on Win32 API
4245 * Selective feeding of a security descriptor into user buffer
4247 * Returns TRUE if successful
4250 static BOOL feedsecurityattr(const char *attr, u32 selection,
4251 char *buf, u32 buflen, u32 *psize)
4253 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4254 SECURITY_DESCRIPTOR_RELATIVE *pnhead;
4259 unsigned int offdacl;
4260 unsigned int offsacl;
4261 unsigned int offowner;
4262 unsigned int offgroup;
4263 unsigned int daclsz;
4264 unsigned int saclsz;
4265 unsigned int usidsz;
4266 unsigned int gsidsz;
4267 unsigned int size; /* size of requested attributes */
4274 control = SE_SELF_RELATIVE;
4275 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4276 size = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4278 /* locate DACL if requested and available */
4279 if (phead->dacl && (selection & DACL_SECURITY_INFORMATION)) {
4280 offdacl = le32_to_cpu(phead->dacl);
4281 pdacl = (const ACL*)&attr[offdacl];
4282 daclsz = le16_to_cpu(pdacl->size);
4284 avail |= DACL_SECURITY_INFORMATION;
4286 offdacl = daclsz = 0;
4288 /* locate owner if requested and available */
4289 offowner = le32_to_cpu(phead->owner);
4290 if (offowner && (selection & OWNER_SECURITY_INFORMATION)) {
4291 /* find end of USID */
4292 pusid = (const SID*)&attr[offowner];
4293 usidsz = ntfs_sid_size(pusid);
4295 avail |= OWNER_SECURITY_INFORMATION;
4297 offowner = usidsz = 0;
4299 /* locate group if requested and available */
4300 offgroup = le32_to_cpu(phead->group);
4301 if (offgroup && (selection & GROUP_SECURITY_INFORMATION)) {
4302 /* find end of GSID */
4303 pgsid = (const SID*)&attr[offgroup];
4304 gsidsz = ntfs_sid_size(pgsid);
4306 avail |= GROUP_SECURITY_INFORMATION;
4308 offgroup = gsidsz = 0;
4310 /* locate SACL if requested and available */
4311 if (phead->sacl && (selection & SACL_SECURITY_INFORMATION)) {
4312 /* find end of SACL */
4313 offsacl = le32_to_cpu(phead->sacl);
4314 psacl = (const ACL*)&attr[offsacl];
4315 saclsz = le16_to_cpu(psacl->size);
4317 avail |= SACL_SECURITY_INFORMATION;
4319 offsacl = saclsz = 0;
4322 * Check having enough size in destination buffer
4323 * (required size is returned nevertheless so that
4324 * the request can be reissued with adequate size)
4326 if (size > buflen) {
4331 if (selection & OWNER_SECURITY_INFORMATION)
4332 control |= phead->control & SE_OWNER_DEFAULTED;
4333 if (selection & GROUP_SECURITY_INFORMATION)
4334 control |= phead->control & SE_GROUP_DEFAULTED;
4335 if (selection & DACL_SECURITY_INFORMATION)
4336 control |= phead->control
4339 | SE_DACL_AUTO_INHERITED
4340 | SE_DACL_PROTECTED);
4341 if (selection & SACL_SECURITY_INFORMATION)
4342 control |= phead->control
4345 | SE_SACL_AUTO_INHERITED
4346 | SE_SACL_PROTECTED);
4348 * copy header and feed new flags, even if no detailed data
4350 memcpy(buf,attr,sizeof(SECURITY_DESCRIPTOR_RELATIVE));
4351 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)buf;
4352 pnhead->control = control;
4353 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4355 /* copy DACL if requested and available */
4356 if (selection & avail & DACL_SECURITY_INFORMATION) {
4357 pnhead->dacl = cpu_to_le32(pos);
4358 memcpy(&buf[pos],&attr[offdacl],daclsz);
4361 pnhead->dacl = const_cpu_to_le32(0);
4363 /* copy SACL if requested and available */
4364 if (selection & avail & SACL_SECURITY_INFORMATION) {
4365 pnhead->sacl = cpu_to_le32(pos);
4366 memcpy(&buf[pos],&attr[offsacl],saclsz);
4369 pnhead->sacl = const_cpu_to_le32(0);
4371 /* copy owner if requested and available */
4372 if (selection & avail & OWNER_SECURITY_INFORMATION) {
4373 pnhead->owner = cpu_to_le32(pos);
4374 memcpy(&buf[pos],&attr[offowner],usidsz);
4377 pnhead->owner = const_cpu_to_le32(0);
4379 /* copy group if requested and available */
4380 if (selection & avail & GROUP_SECURITY_INFORMATION) {
4381 pnhead->group = cpu_to_le32(pos);
4382 memcpy(&buf[pos],&attr[offgroup],gsidsz);
4385 pnhead->group = const_cpu_to_le32(0);
4387 ntfs_log_error("Error in security descriptor size\n");
4396 * Merge a new security descriptor into the old one
4397 * and assign to designated file
4399 * Returns TRUE if successful
4402 static BOOL mergesecurityattr(ntfs_volume *vol, const char *oldattr,
4403 const char *newattr, u32 selection, ntfs_inode *ni)
4405 const SECURITY_DESCRIPTOR_RELATIVE *oldhead;
4406 const SECURITY_DESCRIPTOR_RELATIVE *newhead;
4407 SECURITY_DESCRIPTOR_RELATIVE *targhead;
4424 ok = FALSE; /* default return */
4425 oldhead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
4426 newhead = (const SECURITY_DESCRIPTOR_RELATIVE*)newattr;
4427 oldattrsz = ntfs_attr_size(oldattr);
4428 newattrsz = ntfs_attr_size(newattr);
4429 target = (char*)ntfs_malloc(oldattrsz + newattrsz);
4431 targhead = (SECURITY_DESCRIPTOR_RELATIVE*)target;
4432 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4433 control = SE_SELF_RELATIVE;
4435 * copy new DACL if selected
4436 * or keep old DACL if any
4438 if ((selection & DACL_SECURITY_INFORMATION) ?
4439 newhead->dacl : oldhead->dacl) {
4440 if (selection & DACL_SECURITY_INFORMATION) {
4441 offdacl = le32_to_cpu(newhead->dacl);
4442 pdacl = (const ACL*)&newattr[offdacl];
4444 offdacl = le32_to_cpu(oldhead->dacl);
4445 pdacl = (const ACL*)&oldattr[offdacl];
4447 size = le16_to_cpu(pdacl->size);
4448 memcpy(&target[pos], pdacl, size);
4449 targhead->dacl = cpu_to_le32(pos);
4452 targhead->dacl = const_cpu_to_le32(0);
4453 if (selection & DACL_SECURITY_INFORMATION) {
4454 control |= newhead->control
4457 | SE_DACL_PROTECTED);
4458 if (newhead->control & SE_DACL_AUTO_INHERIT_REQ)
4459 control |= SE_DACL_AUTO_INHERITED;
4461 control |= oldhead->control
4464 | SE_DACL_AUTO_INHERITED
4465 | SE_DACL_PROTECTED);
4467 * copy new SACL if selected
4468 * or keep old SACL if any
4470 if ((selection & SACL_SECURITY_INFORMATION) ?
4471 newhead->sacl : oldhead->sacl) {
4472 if (selection & SACL_SECURITY_INFORMATION) {
4473 offsacl = le32_to_cpu(newhead->sacl);
4474 psacl = (const ACL*)&newattr[offsacl];
4476 offsacl = le32_to_cpu(oldhead->sacl);
4477 psacl = (const ACL*)&oldattr[offsacl];
4479 size = le16_to_cpu(psacl->size);
4480 memcpy(&target[pos], psacl, size);
4481 targhead->sacl = cpu_to_le32(pos);
4484 targhead->sacl = const_cpu_to_le32(0);
4485 if (selection & SACL_SECURITY_INFORMATION) {
4486 control |= newhead->control
4489 | SE_SACL_PROTECTED);
4490 if (newhead->control & SE_SACL_AUTO_INHERIT_REQ)
4491 control |= SE_SACL_AUTO_INHERITED;
4493 control |= oldhead->control
4496 | SE_SACL_AUTO_INHERITED
4497 | SE_SACL_PROTECTED);
4499 * copy new OWNER if selected
4500 * or keep old OWNER if any
4502 if ((selection & OWNER_SECURITY_INFORMATION) ?
4503 newhead->owner : oldhead->owner) {
4504 if (selection & OWNER_SECURITY_INFORMATION) {
4505 offowner = le32_to_cpu(newhead->owner);
4506 powner = (const SID*)&newattr[offowner];
4508 offowner = le32_to_cpu(oldhead->owner);
4509 powner = (const SID*)&oldattr[offowner];
4511 size = ntfs_sid_size(powner);
4512 memcpy(&target[pos], powner, size);
4513 targhead->owner = cpu_to_le32(pos);
4516 targhead->owner = const_cpu_to_le32(0);
4517 if (selection & OWNER_SECURITY_INFORMATION)
4518 control |= newhead->control & SE_OWNER_DEFAULTED;
4520 control |= oldhead->control & SE_OWNER_DEFAULTED;
4522 * copy new GROUP if selected
4523 * or keep old GROUP if any
4525 if ((selection & GROUP_SECURITY_INFORMATION) ?
4526 newhead->group : oldhead->group) {
4527 if (selection & GROUP_SECURITY_INFORMATION) {
4528 offgroup = le32_to_cpu(newhead->group);
4529 pgroup = (const SID*)&newattr[offgroup];
4530 control |= newhead->control
4531 & SE_GROUP_DEFAULTED;
4533 offgroup = le32_to_cpu(oldhead->group);
4534 pgroup = (const SID*)&oldattr[offgroup];
4535 control |= oldhead->control
4536 & SE_GROUP_DEFAULTED;
4538 size = ntfs_sid_size(pgroup);
4539 memcpy(&target[pos], pgroup, size);
4540 targhead->group = cpu_to_le32(pos);
4543 targhead->group = const_cpu_to_le32(0);
4544 if (selection & GROUP_SECURITY_INFORMATION)
4545 control |= newhead->control & SE_GROUP_DEFAULTED;
4547 control |= oldhead->control & SE_GROUP_DEFAULTED;
4548 targhead->revision = SECURITY_DESCRIPTOR_REVISION;
4549 targhead->alignment = 0;
4550 targhead->control = control;
4551 ok = !update_secur_descr(vol, target, ni);
4559 * Return the security descriptor of a file
4560 * This is intended to be similar to GetFileSecurity() from Win32
4561 * in order to facilitate the development of portable tools
4563 * returns zero if unsuccessful (following Win32 conventions)
4565 * the securid if any
4567 * The Win32 API is :
4569 * BOOL WINAPI GetFileSecurity(
4570 * __in LPCTSTR lpFileName,
4571 * __in SECURITY_INFORMATION RequestedInformation,
4572 * __out_opt PSECURITY_DESCRIPTOR pSecurityDescriptor,
4573 * __in DWORD nLength,
4574 * __out LPDWORD lpnLengthNeeded
4579 int ntfs_get_file_security(struct SECURITY_API *scapi,
4580 const char *path, u32 selection,
4581 char *buf, u32 buflen, u32 *psize)
4587 res = 0; /* default return */
4588 if (scapi && (scapi->magic == MAGIC_API)) {
4589 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4591 attr = getsecurityattr(scapi->security.vol, ni);
4593 if (feedsecurityattr(attr,selection,
4594 buf,buflen,psize)) {
4595 if (test_nino_flag(ni, v3_Extensions)
4604 ntfs_inode_close(ni);
4607 if (!res) *psize = 0;
4609 errno = EINVAL; /* do not clear *psize */
4615 * Set the security descriptor of a file or directory
4616 * This is intended to be similar to SetFileSecurity() from Win32
4617 * in order to facilitate the development of portable tools
4619 * returns zero if unsuccessful (following Win32 conventions)
4621 * the securid if any
4623 * The Win32 API is :
4625 * BOOL WINAPI SetFileSecurity(
4626 * __in LPCTSTR lpFileName,
4627 * __in SECURITY_INFORMATION SecurityInformation,
4628 * __in PSECURITY_DESCRIPTOR pSecurityDescriptor
4632 int ntfs_set_file_security(struct SECURITY_API *scapi,
4633 const char *path, u32 selection, const char *attr)
4635 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4642 res = 0; /* default return */
4643 if (scapi && (scapi->magic == MAGIC_API) && attr) {
4644 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4645 attrsz = ntfs_attr_size(attr);
4646 /* if selected, owner and group must be present or defaulted */
4647 missing = ((selection & OWNER_SECURITY_INFORMATION)
4649 && !(phead->control & SE_OWNER_DEFAULTED))
4650 || ((selection & GROUP_SECURITY_INFORMATION)
4652 && !(phead->control & SE_GROUP_DEFAULTED));
4654 && (phead->control & SE_SELF_RELATIVE)
4655 && ntfs_valid_descr(attr, attrsz)) {
4656 ni = ntfs_pathname_to_inode(scapi->security.vol,
4659 oldattr = getsecurityattr(scapi->security.vol,
4662 if (mergesecurityattr(
4663 scapi->security.vol,
4666 if (test_nino_flag(ni,
4675 ntfs_inode_close(ni);
4686 * Set security data on a NTFS file given an inode
4688 * Returns nonzero on success
4690 int _ntfs_set_file_security(ntfs_volume *vol, ntfs_inode *ni,
4691 u32 selection, const char *attr)
4693 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4699 res = 0; /* default return */
4700 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4701 attrsz = ntfs_attr_size(attr);
4702 /* if selected, owner and group must be present or defaulted */
4703 missing = ((selection & OWNER_SECURITY_INFORMATION)
4705 && !(phead->control & SE_OWNER_DEFAULTED))
4706 || ((selection & GROUP_SECURITY_INFORMATION)
4708 && !(phead->control & SE_GROUP_DEFAULTED));
4710 && (phead->control & SE_SELF_RELATIVE)
4711 && ntfs_valid_descr(attr, attrsz)) {
4712 oldattr = getsecurityattr(vol, ni);
4714 if (mergesecurityattr(
4718 if (test_nino_flag(ni,
4735 * Return the attributes of a file
4736 * This is intended to be similar to GetFileAttributes() from Win32
4737 * in order to facilitate the development of portable tools
4739 * returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES)
4741 * The Win32 API is :
4743 * DWORD WINAPI GetFileAttributes(
4744 * __in LPCTSTR lpFileName
4748 int ntfs_get_file_attributes(struct SECURITY_API *scapi, const char *path)
4753 attrib = -1; /* default return */
4754 if (scapi && (scapi->magic == MAGIC_API) && path) {
4755 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4757 attrib = le32_to_cpu(ni->flags);
4758 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
4759 attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4761 attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4763 attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
4765 ntfs_inode_close(ni);
4769 errno = EINVAL; /* do not clear *psize */
4775 * Set attributes to a file or directory
4776 * This is intended to be similar to SetFileAttributes() from Win32
4777 * in order to facilitate the development of portable tools
4779 * Only a few flags can be set (same list as Win32)
4781 * returns zero if unsuccessful (following Win32 conventions)
4782 * nonzero if successful
4784 * The Win32 API is :
4786 * BOOL WINAPI SetFileAttributes(
4787 * __in LPCTSTR lpFileName,
4788 * __in DWORD dwFileAttributes
4792 BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi,
4793 const char *path, s32 attrib)
4797 ATTR_FLAGS dirflags;
4800 res = 0; /* default return */
4801 if (scapi && (scapi->magic == MAGIC_API) && path) {
4802 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4804 settable = FILE_ATTR_SETTABLE;
4805 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4807 * Accept changing compression for a directory
4808 * and set index root accordingly
4810 settable |= FILE_ATTR_COMPRESSED;
4811 if ((ni->flags ^ cpu_to_le32(attrib))
4812 & FILE_ATTR_COMPRESSED) {
4813 if (ni->flags & FILE_ATTR_COMPRESSED)
4814 dirflags = const_cpu_to_le16(0);
4816 dirflags = ATTR_IS_COMPRESSED;
4817 res = ntfs_attr_set_flags(ni,
4821 ATTR_COMPRESSION_MASK);
4825 ni->flags = (ni->flags & ~settable)
4826 | (cpu_to_le32(attrib) & settable);
4828 NInoFileNameSetDirty(ni);
4830 if (!ntfs_inode_close(ni))
4840 * Set attributes of a NTFS file given an inode
4842 * Returns nonzero on success
4844 int _ntfs_set_file_attributes(ntfs_inode *ni, s32 attrib)
4846 le32 settable = FILE_ATTR_SETTABLE;
4847 ATTR_FLAGS dirflags;
4850 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4852 * Accept changing compression for a directory
4853 * and set index root accordingly
4855 settable |= FILE_ATTR_COMPRESSED;
4856 if ((ni->flags ^ cpu_to_le32(attrib))
4857 & FILE_ATTR_COMPRESSED) {
4858 if (ni->flags & FILE_ATTR_COMPRESSED)
4859 dirflags = const_cpu_to_le16(0);
4861 dirflags = ATTR_IS_COMPRESSED;
4862 ret = ntfs_attr_set_flags(ni,
4866 ATTR_COMPRESSION_MASK);
4870 ni->flags = (ni->flags & ~settable)
4871 | (cpu_to_le32(attrib) & settable);
4873 NInoFileNameSetDirty(ni);
4881 BOOL ntfs_read_directory(struct SECURITY_API *scapi,
4882 const char *path, ntfs_filldir_t callback, void *context)
4888 ok = FALSE; /* default return */
4889 if (scapi && (scapi->magic == MAGIC_API) && callback) {
4890 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4892 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4894 ntfs_readdir(ni,&pos,context,callback);
4895 ok = !ntfs_inode_close(ni);
4897 ntfs_inode_close(ni);
4903 errno = EINVAL; /* do not clear *psize */
4908 * read $SDS (for auditing security data)
4910 * Returns the number or read bytes, or -1 if there is an error
4913 int ntfs_read_sds(struct SECURITY_API *scapi,
4914 char *buf, u32 size, u32 offset)
4918 got = -1; /* default return */
4919 if (scapi && (scapi->magic == MAGIC_API)) {
4920 if (scapi->security.vol->secure_ni)
4921 got = ntfs_attr_data_read(scapi->security.vol->secure_ni,
4922 STREAM_SDS, 4, buf, size, offset);
4931 * read $SII (for auditing security data)
4933 * Returns next entry, or NULL if there is an error
4936 INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
4942 ntfs_index_context *xsii;
4944 ret = (INDEX_ENTRY*)NULL; /* default return */
4945 if (scapi && (scapi->magic == MAGIC_API)) {
4946 xsii = scapi->security.vol->secure_xsii;
4949 key.security_id = const_cpu_to_le32(0);
4950 found = !ntfs_index_lookup((char*)&key,
4951 sizeof(SII_INDEX_KEY), xsii);
4952 /* not supposed to find */
4953 if (!found && (errno == ENOENT))
4956 ret = ntfs_index_next(entry,xsii);
4967 * read $SDH (for auditing security data)
4969 * Returns next entry, or NULL if there is an error
4972 INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
4978 ntfs_index_context *xsdh;
4980 ret = (INDEX_ENTRY*)NULL; /* default return */
4981 if (scapi && (scapi->magic == MAGIC_API)) {
4982 xsdh = scapi->security.vol->secure_xsdh;
4985 key.hash = const_cpu_to_le32(0);
4986 key.security_id = const_cpu_to_le32(0);
4987 found = !ntfs_index_lookup((char*)&key,
4988 sizeof(SDH_INDEX_KEY), xsdh);
4989 /* not supposed to find */
4990 if (!found && (errno == ENOENT))
4993 ret = ntfs_index_next(entry,xsdh);
4996 } else errno = ENOTSUP;
5003 * Get the mapped user SID
5004 * A buffer of 40 bytes has to be supplied
5006 * returns the size of the SID, or zero and errno set if not found
5009 int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf)
5016 if (scapi && (scapi->magic == MAGIC_API)) {
5017 usid = ntfs_find_usid(scapi->security.mapping[MAPUSERS], uid, (SID*)&defusid);
5019 size = ntfs_sid_size(usid);
5020 memcpy(buf,usid,size);
5029 * Get the mapped group SID
5030 * A buffer of 40 bytes has to be supplied
5032 * returns the size of the SID, or zero and errno set if not found
5035 int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf)
5042 if (scapi && (scapi->magic == MAGIC_API)) {
5043 gsid = ntfs_find_gsid(scapi->security.mapping[MAPGROUPS], gid, (SID*)&defgsid);
5045 size = ntfs_sid_size(gsid);
5046 memcpy(buf,gsid,size);
5055 * Get the user mapped to a SID
5057 * returns the uid, or -1 if not found
5060 int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid)
5065 if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(usid)) {
5066 if (ntfs_same_sid(usid,adminsid))
5069 uid = ntfs_find_user(scapi->security.mapping[MAPUSERS], usid);
5081 * Get the group mapped to a SID
5083 * returns the uid, or -1 if not found
5086 int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid)
5091 if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(gsid)) {
5092 if (ntfs_same_sid(gsid,adminsid))
5095 gid = ntfs_find_group(scapi->security.mapping[MAPGROUPS], gsid);
5107 * Initializations before calling ntfs_get_file_security()
5108 * ntfs_set_file_security() and ntfs_read_directory()
5110 * Only allowed for root
5112 * Returns an (obscured) struct SECURITY_API* needed for further calls
5113 * NULL if not root (EPERM) or device is mounted (EBUSY)
5116 struct SECURITY_API *ntfs_initialize_file_security(const char *device,
5117 unsigned long flags)
5120 unsigned long mntflag;
5122 struct SECURITY_API *scapi;
5123 struct SECURITY_CONTEXT *scx;
5125 scapi = (struct SECURITY_API*)NULL;
5126 mnt = ntfs_check_if_mounted(device, &mntflag);
5127 if (!mnt && !(mntflag & NTFS_MF_MOUNTED) && !getuid()) {
5128 vol = ntfs_mount(device, flags);
5130 scapi = (struct SECURITY_API*)
5131 ntfs_malloc(sizeof(struct SECURITY_API));
5132 if (!ntfs_volume_get_free_space(vol)
5134 scapi->magic = MAGIC_API;
5135 scapi->seccache = (struct PERMISSIONS_CACHE*)NULL;
5136 scx = &scapi->security;
5138 scx->uid = getuid();
5139 scx->gid = getgid();
5140 scx->pseccache = &scapi->seccache;
5141 scx->vol->secure_flags = 0;
5142 /* accept no mapping and no $Secure */
5143 ntfs_build_mapping(scx,(const char*)NULL,TRUE);
5144 ntfs_open_secure(vol);
5150 mnt = ntfs_umount(vol,FALSE);
5151 scapi = (struct SECURITY_API*)NULL;
5163 * Leaving after ntfs_initialize_file_security()
5165 * Returns FALSE if FAILED
5168 BOOL ntfs_leave_file_security(struct SECURITY_API *scapi)
5174 if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) {
5175 vol = scapi->security.vol;
5176 ntfs_close_secure(&scapi->security);
5178 if (!ntfs_umount(vol, 0))