1/**
2 * security.c - Handling security/ACLs in NTFS.  Originated from the Linux-NTFS project.
3 *
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
8 *
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.
13 *
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.
18 *
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
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#ifdef HAVE_STDIO_H
30#include <stdio.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_STRING_H
36#include <string.h>
37#endif
38#ifdef HAVE_ERRNO_H
39#include <errno.h>
40#endif
41#ifdef HAVE_FCNTL_H
42#include <fcntl.h>
43#endif
44#ifdef HAVE_SETXATTR
45#include <sys/xattr.h>
46#endif
47#ifdef HAVE_SYS_STAT_H
48#include <sys/stat.h>
49#endif
50
51#include <unistd.h>
52#include <pwd.h>
53#include <grp.h>
54
55#include "param.h"
56#include "types.h"
57#include "layout.h"
58#include "attrib.h"
59#include "index.h"
60#include "dir.h"
61#include "bitmap.h"
62#include "security.h"
63#include "acls.h"
64#include "cache.h"
65#include "misc.h"
66
67#ifdef __HAIKU__
68#define getgrgid(a) NULL
69#define getpwuid(a) NULL
70#endif
71
72/*
73 *	JPA NTFS constants or structs
74 *	should be moved to layout.h
75 */
76
77#define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */
78#define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */
79#define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */
80#define FIRST_SECURITY_ID 0x100 /* Lowest security id */
81
82	/* Mask for attributes which can be forced */
83#define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY		\
84				| FILE_ATTR_HIDDEN	\
85				| FILE_ATTR_SYSTEM	\
86				| FILE_ATTR_ARCHIVE	\
87				| FILE_ATTR_TEMPORARY	\
88				| FILE_ATTR_OFFLINE	\
89				| FILE_ATTR_NOT_CONTENT_INDEXED )
90
91struct SII {		/* this is an image of an $SII index entry */
92	le16 offs;
93	le16 size;
94	le32 fill1;
95	le16 indexsz;
96	le16 indexksz;
97	le16 flags;
98	le16 fill2;
99	le32 keysecurid;
100
101	/* did not find official description for the following */
102	le32 hash;
103	le32 securid;
104	le32 dataoffsl;	/* documented as badly aligned */
105	le32 dataoffsh;
106	le32 datasize;
107} ;
108
109struct SDH {		/* this is an image of an $SDH index entry */
110	le16 offs;
111	le16 size;
112	le32 fill1;
113	le16 indexsz;
114	le16 indexksz;
115	le16 flags;
116	le16 fill2;
117	le32 keyhash;
118	le32 keysecurid;
119
120	/* did not find official description for the following */
121	le32 hash;
122	le32 securid;
123	le32 dataoffsl;
124	le32 dataoffsh;
125	le32 datasize;
126	le32 fill3;
127	} ;
128
129/*
130 *	A few useful constants
131 */
132
133static ntfschar sii_stream[] = { const_cpu_to_le16('$'),
134				 const_cpu_to_le16('S'),
135				 const_cpu_to_le16('I'),
136				 const_cpu_to_le16('I'),
137				 const_cpu_to_le16(0) };
138static ntfschar sdh_stream[] = { const_cpu_to_le16('$'),
139				 const_cpu_to_le16('S'),
140				 const_cpu_to_le16('D'),
141				 const_cpu_to_le16('H'),
142				 const_cpu_to_le16(0) };
143
144/*
145 *		null SID (S-1-0-0)
146 */
147
148extern const SID *nullsid;
149
150/*
151 * The zero GUID.
152 */
153
154static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
155		const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
156static const GUID *const zero_guid = &__zero_guid;
157
158/**
159 * ntfs_guid_is_zero - check if a GUID is zero
160 * @guid:	[IN] guid to check
161 *
162 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
163 * and FALSE otherwise.
164 */
165BOOL ntfs_guid_is_zero(const GUID *guid)
166{
167	return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
168}
169
170/**
171 * ntfs_guid_to_mbs - convert a GUID to a multi byte string
172 * @guid:	[IN]  guid to convert
173 * @guid_str:	[OUT] string in which to return the GUID (optional)
174 *
175 * Convert the GUID pointed to by @guid to a multi byte string of the form
176 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".  Therefore, @guid_str (if not NULL)
177 * needs to be able to store at least 37 bytes.
178 *
179 * If @guid_str is not NULL it will contain the converted GUID on return.  If
180 * it is NULL a string will be allocated and this will be returned.  The caller
181 * is responsible for free()ing the string in that case.
182 *
183 * On success return the converted string and on failure return NULL with errno
184 * set to the error code.
185 */
186char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
187{
188	char *_guid_str;
189	int res;
190
191	if (!guid) {
192		errno = EINVAL;
193		return NULL;
194	}
195	_guid_str = guid_str;
196	if (!_guid_str) {
197		_guid_str = (char*)ntfs_malloc(37);
198		if (!_guid_str)
199			return _guid_str;
200	}
201	res = snprintf(_guid_str, 37,
202			"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
203			(unsigned int)le32_to_cpu(guid->data1),
204			le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
205			guid->data4[0], guid->data4[1],
206			guid->data4[2], guid->data4[3], guid->data4[4],
207			guid->data4[5], guid->data4[6], guid->data4[7]);
208	if (res == 36)
209		return _guid_str;
210	if (!guid_str)
211		free(_guid_str);
212	errno = EINVAL;
213	return NULL;
214}
215
216/**
217 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
218 * @sid:	[IN]  SID for which to determine the maximum string size
219 *
220 * Determine the maximum multi byte string size in bytes which is needed to
221 * store the standard textual representation of the SID pointed to by @sid.
222 * See ntfs_sid_to_mbs(), below.
223 *
224 * On success return the maximum number of bytes needed to store the multi byte
225 * string and on failure return -1 with errno set to the error code.
226 */
227int ntfs_sid_to_mbs_size(const SID *sid)
228{
229	int size, i;
230
231	if (!ntfs_sid_is_valid(sid)) {
232		errno = EINVAL;
233		return -1;
234	}
235	/* Start with "S-". */
236	size = 2;
237	/*
238	 * Add the SID_REVISION.  Hopefully the compiler will optimize this
239	 * away as SID_REVISION is a constant.
240	 */
241	for (i = SID_REVISION; i > 0; i /= 10)
242		size++;
243	/* Add the "-". */
244	size++;
245	/*
246	 * Add the identifier authority.  If it needs to be in decimal, the
247	 * maximum is 2^32-1 = 4294967295 = 10 characters.  If it needs to be
248	 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
249	 */
250	if (!sid->identifier_authority.high_part)
251		size += 10;
252	else
253		size += 14;
254	/*
255	 * Finally, add the sub authorities.  For each we have a "-" followed
256	 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
257	 */
258	size += (1 + 10) * sid->sub_authority_count;
259	/* We need the zero byte at the end, too. */
260	size++;
261	return size * sizeof(char);
262}
263
264/**
265 * ntfs_sid_to_mbs - convert a SID to a multi byte string
266 * @sid:		[IN]  SID to convert
267 * @sid_str:		[OUT] string in which to return the SID (optional)
268 * @sid_str_size:	[IN]  size in bytes of @sid_str
269 *
270 * Convert the SID pointed to by @sid to its standard textual representation.
271 * @sid_str (if not NULL) needs to be able to store at least
272 * ntfs_sid_to_mbs_size() bytes.  @sid_str_size is the size in bytes of
273 * @sid_str if @sid_str is not NULL.
274 *
275 * The standard textual representation of the SID is of the form:
276 *	S-R-I-S-S...
277 * Where:
278 *    - The first "S" is the literal character 'S' identifying the following
279 *	digits as a SID.
280 *    - R is the revision level of the SID expressed as a sequence of digits
281 *	in decimal.
282 *    - I is the 48-bit identifier_authority, expressed as digits in decimal,
283 *	if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
284 *    - S... is one or more sub_authority values, expressed as digits in
285 *	decimal.
286 *
287 * If @sid_str is not NULL it will contain the converted SUID on return.  If it
288 * is NULL a string will be allocated and this will be returned.  The caller is
289 * responsible for free()ing the string in that case.
290 *
291 * On success return the converted string and on failure return NULL with errno
292 * set to the error code.
293 */
294char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
295{
296	u64 u;
297	le32 leauth;
298	char *s;
299	int i, j, cnt;
300
301	/*
302	 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
303	 * check @sid, too.  8 is the minimum SID string size.
304	 */
305	if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
306		errno = EINVAL;
307		return NULL;
308	}
309	/* Allocate string if not provided. */
310	if (!sid_str) {
311		cnt = ntfs_sid_to_mbs_size(sid);
312		if (cnt < 0)
313			return NULL;
314		s = (char*)ntfs_malloc(cnt);
315		if (!s)
316			return s;
317		sid_str = s;
318		/* So we know we allocated it. */
319		sid_str_size = 0;
320	} else {
321		s = sid_str;
322		cnt = sid_str_size;
323	}
324	/* Start with "S-R-". */
325	i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
326	if (i < 0 || i >= cnt)
327		goto err_out;
328	s += i;
329	cnt -= i;
330	/* Add the identifier authority. */
331	for (u = i = 0, j = 40; i < 6; i++, j -= 8)
332		u += (u64)sid->identifier_authority.value[i] << j;
333	if (!sid->identifier_authority.high_part)
334		i = snprintf(s, cnt, "%lu", (unsigned long)u);
335	else
336		i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
337	if (i < 0 || i >= cnt)
338		goto err_out;
339	s += i;
340	cnt -= i;
341	/* Finally, add the sub authorities. */
342	for (j = 0; j < sid->sub_authority_count; j++) {
343		leauth = sid->sub_authority[j];
344		i = snprintf(s, cnt, "-%u", (unsigned int)
345				le32_to_cpu(leauth));
346		if (i < 0 || i >= cnt)
347			goto err_out;
348		s += i;
349		cnt -= i;
350	}
351	return sid_str;
352err_out:
353	if (i >= cnt)
354		i = EMSGSIZE;
355	else
356		i = errno;
357	if (!sid_str_size)
358		free(sid_str);
359	errno = i;
360	return NULL;
361}
362
363/**
364 * ntfs_generate_guid - generatates a random current guid.
365 * @guid:	[OUT]   pointer to a GUID struct to hold the generated guid.
366 *
367 * perhaps not a very good random number generator though...
368 */
369void ntfs_generate_guid(GUID *guid)
370{
371	unsigned int i;
372	u8 *p = (u8 *)guid;
373
374	for (i = 0; i < sizeof(GUID); i++) {
375		p[i] = (u8)(random() & 0xFF);
376		if (i == 7)
377			p[7] = (p[7] & 0x0F) | 0x40;
378		if (i == 8)
379			p[8] = (p[8] & 0x3F) | 0x80;
380	}
381}
382
383/**
384 * ntfs_security_hash - calculate the hash of a security descriptor
385 * @sd:         self-relative security descriptor whose hash to calculate
386 * @length:     size in bytes of the security descritor @sd
387 *
388 * Calculate the hash of the self-relative security descriptor @sd of length
389 * @length bytes.
390 *
391 * This hash is used in the $Secure system file as the primary key for the $SDH
392 * index and is also stored in the header of each security descriptor in the
393 * $SDS data stream as well as in the index data of both the $SII and $SDH
394 * indexes.  In all three cases it forms part of the SDS_ENTRY_HEADER
395 * structure.
396 *
397 * Return the calculated security hash in little endian.
398 */
399le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len)
400{
401	const le32 *pos = (const le32*)sd;
402	const le32 *end = pos + (len >> 2);
403	u32 hash = 0;
404
405	while (pos < end) {
406		hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3);
407		pos++;
408	}
409	return cpu_to_le32(hash);
410}
411
412/*
413 *	Get the first entry of current index block
414 *	cut and pasted form ntfs_ie_get_first() in index.c
415 */
416
417static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih)
418{
419	return (INDEX_ENTRY*)((u8*)ih + le32_to_cpu(ih->entries_offset));
420}
421
422/*
423 *		Stuff a 256KB block into $SDS before writing descriptors
424 *	into the block.
425 *
426 *	This prevents $SDS from being automatically declared as sparse
427 *	when the second copy of the first security descriptor is written
428 *	256KB further ahead.
429 *
430 *	Having $SDS declared as a sparse file is not wrong by itself
431 *	and chkdsk leaves it as a sparse file. It does however complain
432 *	and add a sparse flag (0x0200) into field file_attributes of
433 *	STANDARD_INFORMATION of $Secure. This probably means that a
434 *	sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse
435 *	files (FILE_ATTR_SPARSE_FILE).
436 *
437 *	Windows normally does not convert to sparse attribute or sparse
438 *	file. Stuffing is just a way to get to the same result.
439 */
440
441static int entersecurity_stuff(ntfs_volume *vol, off_t offs)
442{
443	int res;
444	int written;
445	unsigned long total;
446	char *stuff;
447
448	res = 0;
449	total = 0;
450	stuff = (char*)ntfs_malloc(STUFFSZ);
451	if (stuff) {
452		memset(stuff, 0, STUFFSZ);
453		do {
454			written = ntfs_attr_data_write(vol->secure_ni,
455				STREAM_SDS, 4, stuff, STUFFSZ, offs);
456			if (written == STUFFSZ) {
457				total += STUFFSZ;
458				offs += STUFFSZ;
459			} else {
460				errno = ENOSPC;
461				res = -1;
462			}
463		} while (!res && (total < ALIGN_SDS_BLOCK));
464		free(stuff);
465	} else {
466		errno = ENOMEM;
467		res = -1;
468	}
469	return (res);
470}
471
472/*
473 *		Enter a new security descriptor into $Secure (data only)
474 *      it has to be written twice with an offset of 256KB
475 *
476 *	Should only be called by entersecurityattr() to ensure consistency
477 *
478 *	Returns zero if sucessful
479 */
480
481static int entersecurity_data(ntfs_volume *vol,
482			const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
483			le32 hash, le32 keyid, off_t offs, int gap)
484{
485	int res;
486	int written1;
487	int written2;
488	char *fullattr;
489	int fullsz;
490	SECURITY_DESCRIPTOR_HEADER *phsds;
491
492	res = -1;
493	fullsz = attrsz + gap + sizeof(SECURITY_DESCRIPTOR_HEADER);
494	fullattr = (char*)ntfs_malloc(fullsz);
495	if (fullattr) {
496			/*
497			 * Clear the gap from previous descriptor
498			 * this could be useful for appending the second
499			 * copy to the end of file. When creating a new
500			 * 256K block, the gap is cleared while writing
501			 * the first copy
502			 */
503		if (gap)
504			memset(fullattr,0,gap);
505		memcpy(&fullattr[gap + sizeof(SECURITY_DESCRIPTOR_HEADER)],
506				attr,attrsz);
507		phsds = (SECURITY_DESCRIPTOR_HEADER*)&fullattr[gap];
508		phsds->hash = hash;
509		phsds->security_id = keyid;
510		phsds->offset = cpu_to_le64(offs);
511		phsds->length = cpu_to_le32(fullsz - gap);
512		written1 = ntfs_attr_data_write(vol->secure_ni,
513			STREAM_SDS, 4, fullattr, fullsz,
514			offs - gap);
515		written2 = ntfs_attr_data_write(vol->secure_ni,
516			STREAM_SDS, 4, fullattr, fullsz,
517			offs - gap + ALIGN_SDS_BLOCK);
518		if ((written1 == fullsz)
519		     && (written2 == written1))
520			res = 0;
521		else
522			errno = ENOSPC;
523		free(fullattr);
524	} else
525		errno = ENOMEM;
526	return (res);
527}
528
529/*
530 *	Enter a new security descriptor in $Secure (indexes only)
531 *
532 *	Should only be called by entersecurityattr() to ensure consistency
533 *
534 *	Returns zero if sucessful
535 */
536
537static int entersecurity_indexes(ntfs_volume *vol, s64 attrsz,
538			le32 hash, le32 keyid, off_t offs)
539{
540	union {
541		struct {
542			le32 dataoffsl;
543			le32 dataoffsh;
544		} parts;
545		le64 all;
546	} realign;
547	int res;
548	ntfs_index_context *xsii;
549	ntfs_index_context *xsdh;
550	struct SII newsii;
551	struct SDH newsdh;
552
553	res = -1;
554				/* enter a new $SII record */
555
556	xsii = vol->secure_xsii;
557	ntfs_index_ctx_reinit(xsii);
558	newsii.offs = const_cpu_to_le16(20);
559	newsii.size = const_cpu_to_le16(sizeof(struct SII) - 20);
560	newsii.fill1 = const_cpu_to_le32(0);
561	newsii.indexsz = const_cpu_to_le16(sizeof(struct SII));
562	newsii.indexksz = const_cpu_to_le16(sizeof(SII_INDEX_KEY));
563	newsii.flags = const_cpu_to_le16(0);
564	newsii.fill2 = const_cpu_to_le16(0);
565	newsii.keysecurid = keyid;
566	newsii.hash = hash;
567	newsii.securid = keyid;
568	realign.all = cpu_to_le64(offs);
569	newsii.dataoffsh = realign.parts.dataoffsh;
570	newsii.dataoffsl = realign.parts.dataoffsl;
571	newsii.datasize = cpu_to_le32(attrsz
572			 + sizeof(SECURITY_DESCRIPTOR_HEADER));
573	if (!ntfs_ie_add(xsii,(INDEX_ENTRY*)&newsii)) {
574
575		/* enter a new $SDH record */
576
577		xsdh = vol->secure_xsdh;
578		ntfs_index_ctx_reinit(xsdh);
579		newsdh.offs = const_cpu_to_le16(24);
580		newsdh.size = const_cpu_to_le16(
581			sizeof(SECURITY_DESCRIPTOR_HEADER));
582		newsdh.fill1 = const_cpu_to_le32(0);
583		newsdh.indexsz = const_cpu_to_le16(
584				sizeof(struct SDH));
585		newsdh.indexksz = const_cpu_to_le16(
586				sizeof(SDH_INDEX_KEY));
587		newsdh.flags = const_cpu_to_le16(0);
588		newsdh.fill2 = const_cpu_to_le16(0);
589		newsdh.keyhash = hash;
590		newsdh.keysecurid = keyid;
591		newsdh.hash = hash;
592		newsdh.securid = keyid;
593		newsdh.dataoffsh = realign.parts.dataoffsh;
594		newsdh.dataoffsl = realign.parts.dataoffsl;
595		newsdh.datasize = cpu_to_le32(attrsz
596			 + sizeof(SECURITY_DESCRIPTOR_HEADER));
597                           /* special filler value, Windows generally */
598                           /* fills with 0x00490049, sometimes with zero */
599		newsdh.fill3 = const_cpu_to_le32(0x00490049);
600		if (!ntfs_ie_add(xsdh,(INDEX_ENTRY*)&newsdh))
601			res = 0;
602	}
603	return (res);
604}
605
606/*
607 *	Enter a new security descriptor in $Secure (data and indexes)
608 *	Returns id of entry, or zero if there is a problem.
609 *	(should not be called for NTFS version < 3.0)
610 *
611 *	important : calls have to be serialized, however no locking is
612 *	needed while fuse is not multithreaded
613 */
614
615static le32 entersecurityattr(ntfs_volume *vol,
616			const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
617			le32 hash)
618{
619	union {
620		struct {
621			le32 dataoffsl;
622			le32 dataoffsh;
623		} parts;
624		le64 all;
625	} realign;
626	le32 securid;
627	le32 keyid;
628	u32 newkey;
629	off_t offs;
630	int gap;
631	int size;
632	BOOL found;
633	struct SII *psii;
634	INDEX_ENTRY *entry;
635	INDEX_ENTRY *next;
636	ntfs_index_context *xsii;
637	int retries;
638	ntfs_attr *na;
639	int olderrno;
640
641	/* find the first available securid beyond the last key */
642	/* in $Secure:$SII. This also determines the first */
643	/* available location in $Secure:$SDS, as this stream */
644	/* is always appended to and the id's are allocated */
645	/* in sequence */
646
647	securid = const_cpu_to_le32(0);
648	xsii = vol->secure_xsii;
649	ntfs_index_ctx_reinit(xsii);
650	offs = size = 0;
651	keyid = const_cpu_to_le32(-1);
652	olderrno = errno;
653	found = !ntfs_index_lookup((char*)&keyid,
654			       sizeof(SII_INDEX_KEY), xsii);
655	if (!found && (errno != ENOENT)) {
656		ntfs_log_perror("Inconsistency in index $SII");
657		psii = (struct SII*)NULL;
658	} else {
659			/* restore errno to avoid misinterpretation */
660		errno = olderrno;
661		entry = xsii->entry;
662		psii = (struct SII*)xsii->entry;
663	}
664	if (psii) {
665		/*
666		 * Get last entry in block, but must get first one
667		 * one first, as we should already be beyond the
668		 * last one. For some reason the search for the last
669		 * entry sometimes does not return the last block...
670		 * we assume this can only happen in root block
671		 */
672		if (xsii->is_in_root)
673			entry = ntfs_ie_get_first
674				((INDEX_HEADER*)&xsii->ir->index);
675		else
676			entry = ntfs_ie_get_first
677				((INDEX_HEADER*)&xsii->ib->index);
678		/*
679		 * All index blocks should be at least half full
680		 * so there always is a last entry but one,
681		 * except when creating the first entry in index root.
682		 * This was however found not to be true : chkdsk
683		 * sometimes deletes all the (unused) keys in the last
684		 * index block without rebalancing the tree.
685		 * When this happens, a new search is restarted from
686		 * the smallest key.
687		 */
688		keyid = const_cpu_to_le32(0);
689		retries = 0;
690		while (entry) {
691			next = ntfs_index_next(entry,xsii);
692			if (next) {
693				psii = (struct SII*)next;
694					/* save last key and */
695					/* available position */
696				keyid = psii->keysecurid;
697				realign.parts.dataoffsh
698						 = psii->dataoffsh;
699				realign.parts.dataoffsl
700						 = psii->dataoffsl;
701				offs = le64_to_cpu(realign.all);
702				size = le32_to_cpu(psii->datasize);
703			}
704			entry = next;
705			if (!entry && !keyid && !retries) {
706				/* search failed, retry from smallest key */
707				ntfs_index_ctx_reinit(xsii);
708				found = !ntfs_index_lookup((char*)&keyid,
709					       sizeof(SII_INDEX_KEY), xsii);
710				if (!found && (errno != ENOENT)) {
711					ntfs_log_perror("Index $SII is broken");
712				} else {
713						/* restore errno */
714					errno = olderrno;
715					entry = xsii->entry;
716				}
717				retries++;
718			}
719		}
720	}
721	if (!keyid) {
722		/*
723		 * could not find any entry, before creating the first
724		 * entry, make a double check by making sure size of $SII
725		 * is less than needed for one entry
726		 */
727		securid = const_cpu_to_le32(0);
728		na = ntfs_attr_open(vol->secure_ni,AT_INDEX_ROOT,sii_stream,4);
729		if (na) {
730			if ((size_t)na->data_size < sizeof(struct SII)) {
731				ntfs_log_error("Creating the first security_id\n");
732				securid = const_cpu_to_le32(FIRST_SECURITY_ID);
733			}
734			ntfs_attr_close(na);
735		}
736		if (!securid) {
737			ntfs_log_error("Error creating a security_id\n");
738			errno = EIO;
739		}
740	} else {
741		newkey = le32_to_cpu(keyid) + 1;
742		securid = cpu_to_le32(newkey);
743	}
744	/*
745	 * The security attr has to be written twice 256KB
746	 * apart. This implies that offsets like
747	 * 0x40000*odd_integer must be left available for
748	 * the second copy. So align to next block when
749	 * the last byte overflows on a wrong block.
750	 */
751
752	if (securid) {
753		gap = (-size) & (ALIGN_SDS_ENTRY - 1);
754		offs += gap + size;
755		if ((offs + attrsz + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
756	 	   & ALIGN_SDS_BLOCK) {
757			offs = ((offs + attrsz
758				 + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
759			 	| (ALIGN_SDS_BLOCK - 1)) + 1;
760		}
761		if (!(offs & (ALIGN_SDS_BLOCK - 1)))
762			entersecurity_stuff(vol, offs);
763		/*
764		 * now write the security attr to storage :
765		 * first data, then SII, then SDH
766		 * If failure occurs while writing SDS, data will never
767		 *    be accessed through indexes, and will be overwritten
768		 *    by the next allocated descriptor
769		 * If failure occurs while writing SII, the id has not
770		 *    recorded and will be reallocated later
771		 * If failure occurs while writing SDH, the space allocated
772		 *    in SDS or SII will not be reused, an inconsistency
773		 *    will persist with no significant consequence
774		 */
775		if (entersecurity_data(vol, attr, attrsz, hash, securid, offs, gap)
776		    || entersecurity_indexes(vol, attrsz, hash, securid, offs))
777			securid = const_cpu_to_le32(0);
778	}
779		/* inode now is dirty, synchronize it all */
780	ntfs_index_entry_mark_dirty(vol->secure_xsii);
781	ntfs_index_ctx_reinit(vol->secure_xsii);
782	ntfs_index_entry_mark_dirty(vol->secure_xsdh);
783	ntfs_index_ctx_reinit(vol->secure_xsdh);
784	NInoSetDirty(vol->secure_ni);
785	if (ntfs_inode_sync(vol->secure_ni))
786		ntfs_log_perror("Could not sync $Secure\n");
787	return (securid);
788}
789
790/*
791 *		Find a matching security descriptor in $Secure,
792 *	if none, allocate a new id and write the descriptor to storage
793 *	Returns id of entry, or zero if there is a problem.
794 *
795 *	important : calls have to be serialized, however no locking is
796 *	needed while fuse is not multithreaded
797 */
798
799static le32 setsecurityattr(ntfs_volume *vol,
800			const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz)
801{
802	struct SDH *psdh;	/* this is an image of index (le) */
803	union {
804		struct {
805			le32 dataoffsl;
806			le32 dataoffsh;
807		} parts;
808		le64 all;
809	} realign;
810	BOOL found;
811	BOOL collision;
812	size_t size;
813	size_t rdsize;
814	s64 offs;
815	int res;
816	ntfs_index_context *xsdh;
817	char *oldattr;
818	SDH_INDEX_KEY key;
819	INDEX_ENTRY *entry;
820	le32 securid;
821	le32 hash;
822	int olderrno;
823
824	hash = ntfs_security_hash(attr,attrsz);
825	oldattr = (char*)NULL;
826	securid = const_cpu_to_le32(0);
827	res = 0;
828	xsdh = vol->secure_xsdh;
829	if (vol->secure_ni && xsdh && !vol->secure_reentry++) {
830		ntfs_index_ctx_reinit(xsdh);
831		/*
832		 * find the nearest key as (hash,0)
833		 * (do not search for partial key : in case of collision,
834		 * it could return a key which is not the first one which
835		 * collides)
836		 */
837		key.hash = hash;
838		key.security_id = const_cpu_to_le32(0);
839		olderrno = errno;
840		found = !ntfs_index_lookup((char*)&key,
841				 sizeof(SDH_INDEX_KEY), xsdh);
842		if (!found && (errno != ENOENT))
843			ntfs_log_perror("Inconsistency in index $SDH");
844		else {
845				/* restore errno to avoid misinterpretation */
846			errno = olderrno;
847			entry = xsdh->entry;
848			found = FALSE;
849			/*
850			 * lookup() may return a node with no data,
851			 * if so get next
852			 */
853			if (entry->ie_flags & INDEX_ENTRY_END)
854				entry = ntfs_index_next(entry,xsdh);
855			do {
856				collision = FALSE;
857				psdh = (struct SDH*)entry;
858				if (psdh)
859					size = (size_t) le32_to_cpu(psdh->datasize)
860						 - sizeof(SECURITY_DESCRIPTOR_HEADER);
861				else size = 0;
862			   /* if hash is not the same, the key is not present */
863				if (psdh && (size > 0)
864				   && (psdh->keyhash == hash)) {
865					   /* if hash is the same */
866					   /* check the whole record */
867					realign.parts.dataoffsh = psdh->dataoffsh;
868					realign.parts.dataoffsl = psdh->dataoffsl;
869					offs = le64_to_cpu(realign.all)
870						+ sizeof(SECURITY_DESCRIPTOR_HEADER);
871					oldattr = (char*)ntfs_malloc(size);
872					if (oldattr) {
873						rdsize = ntfs_attr_data_read(
874							vol->secure_ni,
875							STREAM_SDS, 4,
876							oldattr, size, offs);
877						found = (rdsize == size)
878							&& !memcmp(oldattr,attr,size);
879						free(oldattr);
880					  /* if the records do not compare */
881					  /* (hash collision), try next one */
882						if (!found) {
883							entry = ntfs_index_next(
884								entry,xsdh);
885							collision = TRUE;
886						}
887					} else
888						res = ENOMEM;
889				}
890			} while (collision && entry);
891			if (found)
892				securid = psdh->keysecurid;
893			else {
894				if (res) {
895					errno = res;
896					securid = const_cpu_to_le32(0);
897				} else {
898					/*
899					 * no matching key :
900					 * have to build a new one
901					 */
902					securid = entersecurityattr(vol,
903						attr, attrsz, hash);
904				}
905			}
906		}
907	}
908	if (--vol->secure_reentry)
909		ntfs_log_perror("Reentry error, check no multithreading\n");
910	return (securid);
911}
912
913
914/*
915 *		Update the security descriptor of a file
916 *	Either as an attribute (complying with pre v3.x NTFS version)
917 *	or, when possible, as an entry in $Secure (for NTFS v3.x)
918 *
919 *	returns 0 if success
920 */
921
922static int update_secur_descr(ntfs_volume *vol,
923				char *newattr, ntfs_inode *ni)
924{
925	int newattrsz;
926	int written;
927	int res;
928	ntfs_attr *na;
929
930	newattrsz = ntfs_attr_size(newattr);
931
932#if !FORCE_FORMAT_v1x
933	if ((vol->major_ver < 3) || !vol->secure_ni) {
934#endif
935
936		/* update for NTFS format v1.x */
937
938		/* update the old security attribute */
939		na = ntfs_attr_open(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0);
940		if (na) {
941			/* resize attribute */
942			res = ntfs_attr_truncate(na, (s64) newattrsz);
943			/* overwrite value */
944			if (!res) {
945				written = (int)ntfs_attr_pwrite(na, (s64) 0,
946					 (s64) newattrsz, newattr);
947				if (written != newattrsz) {
948					ntfs_log_error("Failed to update "
949						"a v1.x security descriptor\n");
950					errno = EIO;
951					res = -1;
952				}
953			}
954
955			ntfs_attr_close(na);
956			/* if old security attribute was found, also */
957			/* truncate standard information attribute to v1.x */
958			/* this is needed when security data is wanted */
959			/* as v1.x though volume is formatted for v3.x */
960			na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
961				AT_UNNAMED, 0);
962			if (na) {
963				clear_nino_flag(ni, v3_Extensions);
964			/*
965			 * Truncating the record does not sweep extensions
966			 * from copy in memory. Clear security_id to be safe
967			 */
968				ni->security_id = const_cpu_to_le32(0);
969				res = ntfs_attr_truncate(na, (s64)48);
970				ntfs_attr_close(na);
971				clear_nino_flag(ni, v3_Extensions);
972			}
973		} else {
974			/*
975			 * insert the new security attribute if there
976			 * were none
977			 */
978			res = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR,
979					    AT_UNNAMED, 0, (u8*)newattr,
980					    (s64) newattrsz);
981		}
982#if !FORCE_FORMAT_v1x
983	} else {
984
985		/* update for NTFS format v3.x */
986
987		le32 securid;
988
989		securid = setsecurityattr(vol,
990			(const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
991			(s64)newattrsz);
992		if (securid) {
993			na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
994				AT_UNNAMED, 0);
995			if (na) {
996				res = 0;
997				if (!test_nino_flag(ni, v3_Extensions)) {
998			/* expand standard information attribute to v3.x */
999					res = ntfs_attr_truncate(na,
1000					 (s64)sizeof(STANDARD_INFORMATION));
1001					ni->owner_id = const_cpu_to_le32(0);
1002					ni->quota_charged = const_cpu_to_le64(0);
1003					ni->usn = const_cpu_to_le64(0);
1004					ntfs_attr_remove(ni,
1005						AT_SECURITY_DESCRIPTOR,
1006						AT_UNNAMED, 0);
1007			}
1008				set_nino_flag(ni, v3_Extensions);
1009				ni->security_id = securid;
1010				ntfs_attr_close(na);
1011			} else {
1012				ntfs_log_error("Failed to update "
1013					"standard informations\n");
1014				errno = EIO;
1015				res = -1;
1016			}
1017		} else
1018			res = -1;
1019	}
1020#endif
1021
1022	/* mark node as dirty */
1023	NInoSetDirty(ni);
1024	return (res);
1025}
1026
1027/*
1028 *		Upgrade the security descriptor of a file
1029 *	This is intended to allow graceful upgrades for files which
1030 *	were created in previous versions, with a security attributes
1031 *	and no security id.
1032 *
1033 *      It will allocate a security id and replace the individual
1034 *	security attribute by a reference to the global one
1035 *
1036 *	Special files are not upgraded (currently / and files in
1037 *	directories /$*)
1038 *
1039 *	Though most code is similar to update_secur_desc() it has
1040 *	been kept apart to facilitate the further processing of
1041 *	special cases or even to remove it if found dangerous.
1042 *
1043 *	returns 0 if success,
1044 *		1 if not upgradable. This is not an error.
1045 *		-1 if there is a problem
1046 */
1047
1048static int upgrade_secur_desc(ntfs_volume *vol,
1049				const char *attr, ntfs_inode *ni)
1050{
1051	int attrsz;
1052	int res;
1053	le32 securid;
1054	ntfs_attr *na;
1055
1056		/*
1057		 * upgrade requires NTFS format v3.x
1058		 * also refuse upgrading for special files
1059		 * whose number is less than FILE_first_user
1060		 */
1061
1062	if ((vol->major_ver >= 3)
1063	    && (ni->mft_no >= FILE_first_user)) {
1064		attrsz = ntfs_attr_size(attr);
1065		securid = setsecurityattr(vol,
1066			(const SECURITY_DESCRIPTOR_RELATIVE*)attr,
1067			(s64)attrsz);
1068		if (securid) {
1069			na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
1070				AT_UNNAMED, 0);
1071			if (na) {
1072			/* expand standard information attribute to v3.x */
1073				res = ntfs_attr_truncate(na,
1074					 (s64)sizeof(STANDARD_INFORMATION));
1075				ni->owner_id = const_cpu_to_le32(0);
1076				ni->quota_charged = const_cpu_to_le64(0);
1077				ni->usn = const_cpu_to_le64(0);
1078				ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR,
1079						AT_UNNAMED, 0);
1080				set_nino_flag(ni, v3_Extensions);
1081				ni->security_id = securid;
1082				ntfs_attr_close(na);
1083			} else {
1084				ntfs_log_error("Failed to upgrade "
1085					"standard informations\n");
1086				errno = EIO;
1087				res = -1;
1088			}
1089		} else
1090			res = -1;
1091			/* mark node as dirty */
1092		NInoSetDirty(ni);
1093	} else
1094		res = 1;
1095
1096	return (res);
1097}
1098
1099/*
1100 *		Optional simplified checking of group membership
1101 *
1102 *	This only takes into account the groups defined in
1103 *	/etc/group at initialization time.
1104 *	It does not take into account the groups dynamically set by
1105 *	setgroups() nor the changes in /etc/group since initialization
1106 *
1107 *	This optional method could be useful if standard checking
1108 *	leads to a performance concern.
1109 *
1110 *	Should not be called for user root, however the group may be root
1111 *
1112 */
1113
1114static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1115{
1116	BOOL ingroup;
1117	int grcnt;
1118	gid_t *groups;
1119	struct MAPPING *user;
1120
1121	ingroup = FALSE;
1122	if (uid) {
1123		user = scx->mapping[MAPUSERS];
1124		while (user && ((uid_t)user->xid != uid))
1125			user = user->next;
1126		if (user) {
1127			groups = user->groups;
1128			grcnt = user->grcnt;
1129			while ((--grcnt >= 0) && (groups[grcnt] != gid)) { }
1130			ingroup = (grcnt >= 0);
1131		}
1132	}
1133	return (ingroup);
1134}
1135
1136
1137/*
1138 *		Check whether current thread owner is member of file group
1139 *
1140 *	Should not be called for user root, however the group may be root
1141 *
1142 * As indicated by Miklos Szeredi :
1143 *
1144 * The group list is available in
1145 *
1146 *   /proc/$PID/task/$TID/status
1147 *
1148 * and fuse supplies TID in get_fuse_context()->pid.  The only problem is
1149 * finding out PID, for which I have no good solution, except to iterate
1150 * through all processes.  This is rather slow, but may be speeded up
1151 * with caching and heuristics (for single threaded programs PID = TID).
1152 *
1153 * The following implementation gets the group list from
1154 *   /proc/$TID/task/$TID/status which apparently exists and
1155 * contains the same data.
1156 */
1157
1158#ifdef __HAIKU__
1159static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1160{
1161	return TRUE;
1162}
1163#else
1164static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1165{
1166	static char key[] = "\nGroups:";
1167	char buf[BUFSZ+1];
1168	char filename[64];
1169	enum { INKEY, INSEP, INNUM, INEND } state;
1170	int fd;
1171	char c;
1172	int matched;
1173	BOOL ismember;
1174	int got;
1175	char *p;
1176	gid_t grp;
1177	pid_t tid;
1178
1179	if (scx->vol->secure_flags & (1 << SECURITY_STATICGRPS))
1180		ismember = staticgroupmember(scx, uid, gid);
1181	else {
1182		ismember = FALSE; /* default return */
1183		tid = scx->tid;
1184		sprintf(filename,"/proc/%u/task/%u/status",tid,tid);
1185		fd = open(filename,O_RDONLY);
1186		if (fd >= 0) {
1187			got = read(fd, buf, BUFSZ);
1188			buf[got] = 0;
1189			state = INKEY;
1190			matched = 0;
1191			p = buf;
1192			grp = 0;
1193				/*
1194				 *  A simple automaton to process lines like
1195				 *  Groups: 14 500 513
1196				 */
1197			do {
1198				c = *p++;
1199				if (!c) {
1200					/* refill buffer */
1201					got = read(fd, buf, BUFSZ);
1202					buf[got] = 0;
1203					p = buf;
1204					c = *p++; /* 0 at end of file */
1205				}
1206				switch (state) {
1207				case INKEY :
1208					if (key[matched] == c) {
1209						if (!key[++matched])
1210							state = INSEP;
1211					} else
1212						if (key[0] == c)
1213							matched = 1;
1214						else
1215							matched = 0;
1216					break;
1217				case INSEP :
1218					if ((c >= '0') && (c <= '9')) {
1219						grp = c - '0';
1220						state = INNUM;
1221					} else
1222						if ((c != ' ') && (c != '\t'))
1223							state = INEND;
1224					break;
1225				case INNUM :
1226					if ((c >= '0') && (c <= '9'))
1227						grp = grp*10 + c - '0';
1228					else {
1229						ismember = (grp == gid);
1230						if ((c != ' ') && (c != '\t'))
1231							state = INEND;
1232						else
1233							state = INSEP;
1234					}
1235				default :
1236					break;
1237				}
1238			} while (!ismember && c && (state != INEND));
1239		close(fd);
1240		if (!c)
1241			ntfs_log_error("No group record found in %s\n",filename);
1242		} else
1243			ntfs_log_error("Could not open %s\n",filename);
1244	}
1245	return (ismember);
1246}
1247#endif
1248
1249/*
1250 *	Cacheing is done two-way :
1251 *	- from uid, gid and perm to securid (CACHED_SECURID)
1252 *	- from a securid to uid, gid and perm (CACHED_PERMISSIONS)
1253 *
1254 *	CACHED_SECURID data is kept in a most-recent-first list
1255 *	which should not be too long to be efficient. Its optimal
1256 *	size is depends on usage and is hard to determine.
1257 *
1258 *	CACHED_PERMISSIONS data is kept in a two-level indexed array. It
1259 *	is optimal at the expense of storage. Use of a most-recent-first
1260 *	list would save memory and provide similar performances for
1261 *	standard usage, but not for file servers with too many file
1262 *	owners
1263 *
1264 *	CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS
1265 *	for legacy directories which were not allocated a security_id
1266 *	it is organized in a most-recent-first list.
1267 *
1268 *	In main caches, data is never invalidated, as the meaning of
1269 *	a security_id only changes when user mapping is changed, which
1270 *	current implies remounting. However returned entries may be
1271 *	overwritten at next update, so data has to be copied elsewhere
1272 *	before another cache update is made.
1273 *	In legacy cache, data has to be invalidated when protection is
1274 *	changed.
1275 *
1276 *	Though the same data may be found in both list, they
1277 *	must be kept separately : the interpretation of ACL
1278 *	in both direction are approximations which could be non
1279 *	reciprocal for some configuration of the user mapping data
1280 *
1281 *	During the process of recompiling ntfs-3g from a tgz archive,
1282 *	security processing added 7.6% to the cpu time used by ntfs-3g
1283 *	and 30% if the cache is disabled.
1284 */
1285
1286static struct PERMISSIONS_CACHE *create_caches(struct SECURITY_CONTEXT *scx,
1287			u32 securindex)
1288{
1289	struct PERMISSIONS_CACHE *cache;
1290	unsigned int index1;
1291	unsigned int i;
1292
1293	cache = (struct PERMISSIONS_CACHE*)NULL;
1294		/* create the first permissions blocks */
1295	index1 = securindex >> CACHE_PERMISSIONS_BITS;
1296	cache = (struct PERMISSIONS_CACHE*)
1297		ntfs_malloc(sizeof(struct PERMISSIONS_CACHE)
1298		      + index1*sizeof(struct CACHED_PERMISSIONS*));
1299	if (cache) {
1300		cache->head.last = index1;
1301		cache->head.p_reads = 0;
1302		cache->head.p_hits = 0;
1303		cache->head.p_writes = 0;
1304		*scx->pseccache = cache;
1305		for (i=0; i<=index1; i++)
1306			cache->cachetable[i]
1307			   = (struct CACHED_PERMISSIONS*)NULL;
1308	}
1309	return (cache);
1310}
1311
1312/*
1313 *		Free memory used by caches
1314 *	The only purpose is to facilitate the detection of memory leaks
1315 */
1316
1317static void free_caches(struct SECURITY_CONTEXT *scx)
1318{
1319	unsigned int index1;
1320	struct PERMISSIONS_CACHE *pseccache;
1321
1322	pseccache = *scx->pseccache;
1323	if (pseccache) {
1324		for (index1=0; index1<=pseccache->head.last; index1++)
1325			if (pseccache->cachetable[index1]) {
1326#if POSIXACLS
1327				struct CACHED_PERMISSIONS *cacheentry;
1328				unsigned int index2;
1329
1330				for (index2=0; index2<(1<< CACHE_PERMISSIONS_BITS); index2++) {
1331					cacheentry = &pseccache->cachetable[index1][index2];
1332					if (cacheentry->valid
1333					    && cacheentry->pxdesc)
1334						free(cacheentry->pxdesc);
1335					}
1336#endif
1337				free(pseccache->cachetable[index1]);
1338			}
1339		free(pseccache);
1340	}
1341}
1342
1343static int compare(const struct CACHED_SECURID *cached,
1344			const struct CACHED_SECURID *item)
1345{
1346#if POSIXACLS
1347	size_t csize;
1348	size_t isize;
1349
1350		/* only compare data and sizes */
1351	csize = (cached->variable ?
1352		sizeof(struct POSIX_ACL)
1353		+ (((struct POSIX_SECURITY*)cached->variable)->acccnt
1354		   + ((struct POSIX_SECURITY*)cached->variable)->defcnt)
1355			*sizeof(struct POSIX_ACE) :
1356		0);
1357	isize = (item->variable ?
1358		sizeof(struct POSIX_ACL)
1359		+ (((struct POSIX_SECURITY*)item->variable)->acccnt
1360		   + ((struct POSIX_SECURITY*)item->variable)->defcnt)
1361			*sizeof(struct POSIX_ACE) :
1362		0);
1363	return ((cached->uid != item->uid)
1364		 || (cached->gid != item->gid)
1365		 || (cached->dmode != item->dmode)
1366		 || (csize != isize)
1367		 || (csize
1368		    && isize
1369		    && memcmp(&((struct POSIX_SECURITY*)cached->variable)->acl,
1370		       &((struct POSIX_SECURITY*)item->variable)->acl, csize)));
1371#else
1372	return ((cached->uid != item->uid)
1373		 || (cached->gid != item->gid)
1374		 || (cached->dmode != item->dmode));
1375#endif
1376}
1377
1378static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached,
1379			const struct CACHED_PERMISSIONS_LEGACY *item)
1380{
1381	return (cached->mft_no != item->mft_no);
1382}
1383
1384/*
1385 *	Resize permission cache table
1386 *	do not call unless resizing is needed
1387 *
1388 *	If allocation fails, the cache size is not updated
1389 *	Lack of memory is not considered as an error, the cache is left
1390 *	consistent and errno is not set.
1391 */
1392
1393static void resize_cache(struct SECURITY_CONTEXT *scx,
1394			u32 securindex)
1395{
1396	struct PERMISSIONS_CACHE *oldcache;
1397	struct PERMISSIONS_CACHE *newcache;
1398	int newcnt;
1399	int oldcnt;
1400	unsigned int index1;
1401	unsigned int i;
1402
1403	oldcache = *scx->pseccache;
1404	index1 = securindex >> CACHE_PERMISSIONS_BITS;
1405	newcnt = index1 + 1;
1406	if (newcnt <= ((CACHE_PERMISSIONS_SIZE
1407			+ (1 << CACHE_PERMISSIONS_BITS)
1408			- 1) >> CACHE_PERMISSIONS_BITS)) {
1409		/* expand cache beyond current end, do not use realloc() */
1410		/* to avoid losing data when there is no more memory */
1411		oldcnt = oldcache->head.last + 1;
1412		newcache = (struct PERMISSIONS_CACHE*)
1413			ntfs_malloc(
1414			    sizeof(struct PERMISSIONS_CACHE)
1415			      + (newcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
1416		if (newcache) {
1417			memcpy(newcache,oldcache,
1418			    sizeof(struct PERMISSIONS_CACHE)
1419			      + (oldcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
1420			free(oldcache);
1421			     /* mark new entries as not valid */
1422			for (i=newcache->head.last+1; i<=index1; i++)
1423				newcache->cachetable[i]
1424					 = (struct CACHED_PERMISSIONS*)NULL;
1425			newcache->head.last = index1;
1426			*scx->pseccache = newcache;
1427		}
1428	}
1429}
1430
1431/*
1432 *	Enter uid, gid and mode into cache, if possible
1433 *
1434 *	returns the updated or created cache entry,
1435 *	or NULL if not possible (typically if there is no
1436 *		security id associated)
1437 */
1438
1439#if POSIXACLS
1440static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
1441		ntfs_inode *ni, uid_t uid, gid_t gid,
1442		struct POSIX_SECURITY *pxdesc)
1443#else
1444static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
1445		ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode)
1446#endif
1447{
1448	struct CACHED_PERMISSIONS *cacheentry;
1449	struct CACHED_PERMISSIONS *cacheblock;
1450	struct PERMISSIONS_CACHE *pcache;
1451	u32 securindex;
1452#if POSIXACLS
1453	int pxsize;
1454	struct POSIX_SECURITY *pxcached;
1455#endif
1456	unsigned int index1;
1457	unsigned int index2;
1458	int i;
1459
1460	/* cacheing is only possible if a security_id has been defined */
1461	if (test_nino_flag(ni, v3_Extensions)
1462	   && ni->security_id) {
1463		/*
1464		 *  Immediately test the most frequent situation
1465		 *  where the entry exists
1466		 */
1467		securindex = le32_to_cpu(ni->security_id);
1468		index1 = securindex >> CACHE_PERMISSIONS_BITS;
1469		index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
1470		pcache = *scx->pseccache;
1471		if (pcache
1472		     && (pcache->head.last >= index1)
1473		     && pcache->cachetable[index1]) {
1474			cacheentry = &pcache->cachetable[index1][index2];
1475			cacheentry->uid = uid;
1476			cacheentry->gid = gid;
1477#if POSIXACLS
1478			if (cacheentry->valid && cacheentry->pxdesc)
1479				free(cacheentry->pxdesc);
1480			if (pxdesc) {
1481				pxsize = sizeof(struct POSIX_SECURITY)
1482					+ (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1483				pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
1484				if (pxcached) {
1485					memcpy(pxcached, pxdesc, pxsize);
1486					cacheentry->pxdesc = pxcached;
1487				} else {
1488					cacheentry->valid = 0;
1489					cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1490				}
1491				cacheentry->mode = pxdesc->mode & 07777;
1492			} else
1493				cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
1494#else
1495			cacheentry->mode = mode & 07777;
1496#endif
1497			cacheentry->inh_fileid = const_cpu_to_le32(0);
1498			cacheentry->inh_dirid = const_cpu_to_le32(0);
1499			cacheentry->valid = 1;
1500			pcache->head.p_writes++;
1501		} else {
1502			if (!pcache) {
1503				/* create the first cache block */
1504				pcache = create_caches(scx, securindex);
1505			} else {
1506				if (index1 > pcache->head.last) {
1507					resize_cache(scx, securindex);
1508					pcache = *scx->pseccache;
1509				}
1510			}
1511			/* allocate block, if cache table was allocated */
1512			if (pcache && (index1 <= pcache->head.last)) {
1513				cacheblock = (struct CACHED_PERMISSIONS*)
1514					malloc(sizeof(struct CACHED_PERMISSIONS)
1515						<< CACHE_PERMISSIONS_BITS);
1516				pcache->cachetable[index1] = cacheblock;
1517				for (i=0; i<(1 << CACHE_PERMISSIONS_BITS); i++)
1518					cacheblock[i].valid = 0;
1519				cacheentry = &cacheblock[index2];
1520				if (cacheentry) {
1521					cacheentry->uid = uid;
1522					cacheentry->gid = gid;
1523#if POSIXACLS
1524					if (pxdesc) {
1525						pxsize = sizeof(struct POSIX_SECURITY)
1526							+ (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1527						pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
1528						if (pxcached) {
1529							memcpy(pxcached, pxdesc, pxsize);
1530							cacheentry->pxdesc = pxcached;
1531						} else {
1532							cacheentry->valid = 0;
1533							cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1534						}
1535						cacheentry->mode = pxdesc->mode & 07777;
1536					} else
1537						cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
1538#else
1539					cacheentry->mode = mode & 07777;
1540#endif
1541					cacheentry->inh_fileid = const_cpu_to_le32(0);
1542					cacheentry->inh_dirid = const_cpu_to_le32(0);
1543					cacheentry->valid = 1;
1544					pcache->head.p_writes++;
1545				}
1546			} else
1547				cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1548		}
1549	} else {
1550		cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1551#if CACHE_LEGACY_SIZE
1552		if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1553			struct CACHED_PERMISSIONS_LEGACY wanted;
1554			struct CACHED_PERMISSIONS_LEGACY *legacy;
1555
1556			wanted.perm.uid = uid;
1557			wanted.perm.gid = gid;
1558#if POSIXACLS
1559			wanted.perm.mode = pxdesc->mode & 07777;
1560			wanted.perm.inh_fileid = const_cpu_to_le32(0);
1561			wanted.perm.inh_dirid = const_cpu_to_le32(0);
1562			wanted.mft_no = ni->mft_no;
1563			wanted.variable = (void*)pxdesc;
1564			wanted.varsize = sizeof(struct POSIX_SECURITY)
1565					+ (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1566#else
1567			wanted.perm.mode = mode & 07777;
1568			wanted.perm.inh_fileid = const_cpu_to_le32(0);
1569			wanted.perm.inh_dirid = const_cpu_to_le32(0);
1570			wanted.mft_no = ni->mft_no;
1571			wanted.variable = (void*)NULL;
1572			wanted.varsize = 0;
1573#endif
1574			legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_enter_cache(
1575				scx->vol->legacy_cache, GENERIC(&wanted),
1576				(cache_compare)leg_compare);
1577			if (legacy) {
1578				cacheentry = &legacy->perm;
1579#if POSIXACLS
1580				/*
1581				 * give direct access to the cached pxdesc
1582				 * in the permissions structure
1583				 */
1584				cacheentry->pxdesc = legacy->variable;
1585#endif
1586			}
1587		}
1588#endif
1589	}
1590	return (cacheentry);
1591}
1592
1593/*
1594 *	Fetch owner, group and permission of a file, if cached
1595 *
1596 *	Beware : do not use the returned entry after a cache update :
1597 *	the cache may be relocated making the returned entry meaningless
1598 *
1599 *	returns the cache entry, or NULL if not available
1600 */
1601
1602static struct CACHED_PERMISSIONS *fetch_cache(struct SECURITY_CONTEXT *scx,
1603		ntfs_inode *ni)
1604{
1605	struct CACHED_PERMISSIONS *cacheentry;
1606	struct PERMISSIONS_CACHE *pcache;
1607	u32 securindex;
1608	unsigned int index1;
1609	unsigned int index2;
1610
1611	/* cacheing is only possible if a security_id has been defined */
1612	cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1613	if (test_nino_flag(ni, v3_Extensions)
1614	   && (ni->security_id)) {
1615		securindex = le32_to_cpu(ni->security_id);
1616		index1 = securindex >> CACHE_PERMISSIONS_BITS;
1617		index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
1618		pcache = *scx->pseccache;
1619		if (pcache
1620		     && (pcache->head.last >= index1)
1621		     && pcache->cachetable[index1]) {
1622			cacheentry = &pcache->cachetable[index1][index2];
1623			/* reject if entry is not valid */
1624			if (!cacheentry->valid)
1625				cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1626			else
1627				pcache->head.p_hits++;
1628		if (pcache)
1629			pcache->head.p_reads++;
1630		}
1631	}
1632#if CACHE_LEGACY_SIZE
1633	else {
1634		cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1635		if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1636			struct CACHED_PERMISSIONS_LEGACY wanted;
1637			struct CACHED_PERMISSIONS_LEGACY *legacy;
1638
1639			wanted.mft_no = ni->mft_no;
1640			wanted.variable = (void*)NULL;
1641			wanted.varsize = 0;
1642			legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_fetch_cache(
1643				scx->vol->legacy_cache, GENERIC(&wanted),
1644				(cache_compare)leg_compare);
1645			if (legacy) cacheentry = &legacy->perm;
1646		}
1647	}
1648#endif
1649#if POSIXACLS
1650	if (cacheentry && !cacheentry->pxdesc) {
1651		ntfs_log_error("No Posix descriptor in cache\n");
1652		cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1653	}
1654#endif
1655	return (cacheentry);
1656}
1657
1658/*
1659 *	Retrieve a security attribute from $Secure
1660 */
1661
1662static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id)
1663{
1664	struct SII *psii;
1665	union {
1666		struct {
1667			le32 dataoffsl;
1668			le32 dataoffsh;
1669		} parts;
1670		le64 all;
1671	} realign;
1672	int found;
1673	size_t size;
1674	size_t rdsize;
1675	s64 offs;
1676	ntfs_inode *ni;
1677	ntfs_index_context *xsii;
1678	char *securattr;
1679
1680	securattr = (char*)NULL;
1681	ni = vol->secure_ni;
1682	xsii = vol->secure_xsii;
1683	if (ni && xsii) {
1684		ntfs_index_ctx_reinit(xsii);
1685		found =
1686		    !ntfs_index_lookup((char*)&id,
1687				       sizeof(SII_INDEX_KEY), xsii);
1688		if (found) {
1689			psii = (struct SII*)xsii->entry;
1690			size =
1691			    (size_t) le32_to_cpu(psii->datasize)
1692				 - sizeof(SECURITY_DESCRIPTOR_HEADER);
1693			/* work around bad alignment problem */
1694			realign.parts.dataoffsh = psii->dataoffsh;
1695			realign.parts.dataoffsl = psii->dataoffsl;
1696			offs = le64_to_cpu(realign.all)
1697				+ sizeof(SECURITY_DESCRIPTOR_HEADER);
1698
1699			securattr = (char*)ntfs_malloc(size);
1700			if (securattr) {
1701				rdsize = ntfs_attr_data_read(
1702					ni, STREAM_SDS, 4,
1703					securattr, size, offs);
1704				if ((rdsize != size)
1705					|| !ntfs_valid_descr(securattr,
1706						rdsize)) {
1707					/* error to be logged by caller */
1708					free(securattr);
1709					securattr = (char*)NULL;
1710				}
1711			}
1712		} else
1713			if (errno != ENOENT)
1714				ntfs_log_perror("Inconsistency in index $SII");
1715	}
1716	if (!securattr) {
1717		ntfs_log_error("Failed to retrieve a security descriptor\n");
1718		errno = EIO;
1719	}
1720	return (securattr);
1721}
1722
1723/*
1724 *		Get the security descriptor associated to a file
1725 *
1726 *	Either :
1727 *	   - read the security descriptor attribute (v1.x format)
1728 *	   - or find the descriptor in $Secure:$SDS (v3.x format)
1729 *
1730 *	in both case, sanity checks are done on the attribute and
1731 *	the descriptor can be assumed safe
1732 *
1733 *	The returned descriptor is dynamically allocated and has to be freed
1734 */
1735
1736static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni)
1737{
1738	SII_INDEX_KEY securid;
1739	char *securattr;
1740	s64 readallsz;
1741
1742		/*
1743		 * Warning : in some situations, after fixing by chkdsk,
1744		 * v3_Extensions are marked present (long standard informations)
1745		 * with a default security descriptor inserted in an
1746		 * attribute
1747		 */
1748	if (test_nino_flag(ni, v3_Extensions)
1749			&& vol->secure_ni && ni->security_id) {
1750			/* get v3.x descriptor in $Secure */
1751		securid.security_id = ni->security_id;
1752		securattr = retrievesecurityattr(vol,securid);
1753		if (!securattr)
1754			ntfs_log_error("Bad security descriptor for 0x%lx\n",
1755					(long)le32_to_cpu(ni->security_id));
1756	} else {
1757			/* get v1.x security attribute */
1758		readallsz = 0;
1759		securattr = ntfs_attr_readall(ni, AT_SECURITY_DESCRIPTOR,
1760				AT_UNNAMED, 0, &readallsz);
1761		if (securattr && !ntfs_valid_descr(securattr, readallsz)) {
1762			ntfs_log_error("Bad security descriptor for inode %lld\n",
1763				(long long)ni->mft_no);
1764			free(securattr);
1765			securattr = (char*)NULL;
1766		}
1767	}
1768	if (!securattr) {
1769			/*
1770			 * in some situations, there is no security
1771			 * descriptor, and chkdsk does not detect or fix
1772			 * anything. This could be a normal situation.
1773			 * When this happens, simulate a descriptor with
1774			 * minimum rights, so that a real descriptor can
1775			 * be created by chown or chmod
1776			 */
1777		ntfs_log_error("No security descriptor found for inode %lld\n",
1778				(long long)ni->mft_no);
1779		securattr = ntfs_build_descr(0, 0, adminsid, adminsid);
1780	}
1781	return (securattr);
1782}
1783
1784#if POSIXACLS
1785
1786/*
1787 *		Determine which access types to a file are allowed
1788 *	according to the relation of current process to the file
1789 *
1790 *	Do not call if default_permissions is set
1791 */
1792
1793static int access_check_posix(struct SECURITY_CONTEXT *scx,
1794			struct POSIX_SECURITY *pxdesc, mode_t request,
1795			uid_t uid, gid_t gid)
1796{
1797	struct POSIX_ACE *pxace;
1798	int userperms;
1799	int groupperms;
1800	int mask;
1801	BOOL somegroup;
1802	BOOL needgroups;
1803	mode_t perms;
1804	int i;
1805
1806	perms = pxdesc->mode;
1807					/* owner and root access */
1808	if (!scx->uid || (uid == scx->uid)) {
1809		if (!scx->uid) {
1810					/* root access if owner or other execution */
1811			if (perms & 0101)
1812				perms = 07777;
1813			else {
1814					/* root access if some group execution */
1815				groupperms = 0;
1816				mask = 7;
1817				for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1818					pxace = &pxdesc->acl.ace[i];
1819					switch (pxace->tag) {
1820					case POSIX_ACL_USER_OBJ :
1821					case POSIX_ACL_GROUP_OBJ :
1822					case POSIX_ACL_GROUP :
1823						groupperms |= pxace->perms;
1824						break;
1825					case POSIX_ACL_MASK :
1826						mask = pxace->perms & 7;
1827						break;
1828					default :
1829						break;
1830					}
1831				}
1832				perms = (groupperms & mask & 1) | 6;
1833			}
1834		} else
1835			perms &= 07700;
1836	} else {
1837				/*
1838				 * analyze designated users, get mask
1839				 * and identify whether we need to check
1840				 * the group memberships. The groups are
1841				 * not needed when all groups have the
1842				 * same permissions as other for the
1843				 * requested modes.
1844				 */
1845		userperms = -1;
1846		groupperms = -1;
1847		needgroups = FALSE;
1848		mask = 7;
1849		for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1850			pxace = &pxdesc->acl.ace[i];
1851			switch (pxace->tag) {
1852			case POSIX_ACL_USER :
1853				if ((uid_t)pxace->id == scx->uid)
1854					userperms = pxace->perms;
1855				break;
1856			case POSIX_ACL_MASK :
1857				mask = pxace->perms & 7;
1858				break;
1859			case POSIX_ACL_GROUP_OBJ :
1860			case POSIX_ACL_GROUP :
1861				if (((pxace->perms & mask) ^ perms)
1862				    & (request >> 6) & 7)
1863					needgroups = TRUE;
1864				break;
1865			default :
1866				break;
1867			}
1868		}
1869					/* designated users */
1870		if (userperms >= 0)
1871			perms = (perms & 07000) + (userperms & mask);
1872		else if (!needgroups)
1873				perms &= 07007;
1874		else {
1875					/* owning group */
1876			if (!(~(perms >> 3) & request & mask)
1877			    && ((gid == scx->gid)
1878				|| groupmember(scx, scx->uid, gid)))
1879				perms &= 07070;
1880			else {
1881					/* other groups */
1882				groupperms = -1;
1883				somegroup = FALSE;
1884				for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1885					pxace = &pxdesc->acl.ace[i];
1886					if ((pxace->tag == POSIX_ACL_GROUP)
1887					    && groupmember(scx, uid, pxace->id)) {
1888						if (!(~pxace->perms & request & mask))
1889							groupperms = pxace->perms;
1890						somegroup = TRUE;
1891					}
1892				}
1893				if (groupperms >= 0)
1894					perms = (perms & 07000) + (groupperms & mask);
1895				else
1896					if (somegroup)
1897						perms = 0;
1898					else
1899						perms &= 07007;
1900			}
1901		}
1902	}
1903	return (perms);
1904}
1905
1906/*
1907 *		Get permissions to access a file
1908 *	Takes into account the relation of user to file (owner, group, ...)
1909 *	Do no use as mode of the file
1910 *	Do no call if default_permissions is set
1911 *
1912 *	returns -1 if there is a problem
1913 */
1914
1915static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
1916		 ntfs_inode * ni, mode_t request)
1917{
1918	const SECURITY_DESCRIPTOR_RELATIVE *phead;
1919	const struct CACHED_PERMISSIONS *cached;
1920	char *securattr;
1921	const SID *usid;	/* owner of file/directory */
1922	const SID *gsid;	/* group of file/directory */
1923	uid_t uid;
1924	gid_t gid;
1925	int perm;
1926	BOOL isdir;
1927	struct POSIX_SECURITY *pxdesc;
1928
1929	if (!scx->mapping[MAPUSERS])
1930		perm = 07777;
1931	else {
1932		/* check whether available in cache */
1933		cached = fetch_cache(scx,ni);
1934		if (cached) {
1935			uid = cached->uid;
1936			gid = cached->gid;
1937			perm = access_check_posix(scx,cached->pxdesc,request,uid,gid);
1938		} else {
1939			perm = 0;	/* default to no permission */
1940			isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
1941				!= const_cpu_to_le16(0);
1942			securattr = getsecurityattr(scx->vol, ni);
1943			if (securattr) {
1944				phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
1945				    	securattr;
1946				gsid = (const SID*)&
1947					   securattr[le32_to_cpu(phead->group)];
1948				gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
1949#if OWNERFROMACL
1950				usid = ntfs_acl_owner(securattr);
1951				pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
1952						 usid, gsid, isdir);
1953				if (pxdesc)
1954					perm = pxdesc->mode & 07777;
1955				else
1956					perm = -1;
1957				uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
1958#else
1959				usid = (const SID*)&
1960					    securattr[le32_to_cpu(phead->owner)];
1961				pxdesc = ntfs_build_permissions_posix(scx,securattr,
1962						 usid, gsid, isdir);
1963				if (pxdesc)
1964					perm = pxdesc->mode & 07777;
1965				else
1966					perm = -1;
1967				if (!perm && ntfs_same_sid(usid, adminsid)) {
1968					uid = find_tenant(scx, securattr);
1969					if (uid)
1970						perm = 0700;
1971				} else
1972					uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
1973#endif
1974				/*
1975				 *  Create a security id if there were none
1976				 * and upgrade option is selected
1977				 */
1978				if (!test_nino_flag(ni, v3_Extensions)
1979				   && (perm >= 0)
1980				   && (scx->vol->secure_flags
1981				     & (1 << SECURITY_ADDSECURIDS))) {
1982					upgrade_secur_desc(scx->vol,
1983						securattr, ni);
1984					/*
1985					 * fetch owner and group for cacheing
1986					 * if there is a securid
1987					 */
1988				}
1989				if (test_nino_flag(ni, v3_Extensions)
1990				    && (perm >= 0)) {
1991					enter_cache(scx, ni, uid,
1992							gid, pxdesc);
1993				}
1994				if (pxdesc) {
1995					perm = access_check_posix(scx,pxdesc,request,uid,gid);
1996					free(pxdesc);
1997				}
1998				free(securattr);
1999			} else {
2000				perm = -1;
2001				uid = gid = 0;
2002			}
2003		}
2004	}
2005	return (perm);
2006}
2007
2008/*
2009 *		Get a Posix ACL
2010 *
2011 *	returns size or -errno if there is a problem
2012 *	if size was too small, no copy is done and errno is not set,
2013 *	the caller is expected to issue a new call
2014 */
2015
2016int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2017			const char *name, char *value, size_t size)
2018{
2019	const SECURITY_DESCRIPTOR_RELATIVE *phead;
2020	struct POSIX_SECURITY *pxdesc;
2021	const struct CACHED_PERMISSIONS *cached;
2022	char *securattr;
2023	const SID *usid;	/* owner of file/directory */
2024	const SID *gsid;	/* group of file/directory */
2025	uid_t uid;
2026	gid_t gid;
2027	BOOL isdir;
2028	size_t outsize;
2029
2030	outsize = 0;	/* default to error */
2031	if (!scx->mapping[MAPUSERS])
2032		errno = ENOTSUP;
2033	else {
2034			/* check whether available in cache */
2035		cached = fetch_cache(scx,ni);
2036		if (cached)
2037			pxdesc = cached->pxdesc;
2038		else {
2039			securattr = getsecurityattr(scx->vol, ni);
2040			isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2041				!= const_cpu_to_le16(0);
2042			if (securattr) {
2043				phead =
2044				    (const SECURITY_DESCRIPTOR_RELATIVE*)
2045			    			securattr;
2046				gsid = (const SID*)&
2047					  securattr[le32_to_cpu(phead->group)];
2048#if OWNERFROMACL
2049				usid = ntfs_acl_owner(securattr);
2050#else
2051				usid = (const SID*)&
2052					  securattr[le32_to_cpu(phead->owner)];
2053#endif
2054				pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2055					  usid, gsid, isdir);
2056
2057					/*
2058					 * fetch owner and group for cacheing
2059					 */
2060				if (pxdesc) {
2061				/*
2062				 *  Create a security id if there were none
2063				 * and upgrade option is selected
2064				 */
2065					if (!test_nino_flag(ni, v3_Extensions)
2066					   && (scx->vol->secure_flags
2067					     & (1 << SECURITY_ADDSECURIDS))) {
2068						upgrade_secur_desc(scx->vol,
2069							 securattr, ni);
2070					}
2071#if OWNERFROMACL
2072					uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2073#else
2074					if (!(pxdesc->mode & 07777)
2075					    && ntfs_same_sid(usid, adminsid)) {
2076						uid = find_tenant(scx,
2077								securattr);
2078					} else
2079						uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2080#endif
2081					gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2082					if (pxdesc->tagsset & POSIX_ACL_EXTENSIONS)
2083					enter_cache(scx, ni, uid,
2084							gid, pxdesc);
2085				}
2086				free(securattr);
2087			} else
2088				pxdesc = (struct POSIX_SECURITY*)NULL;
2089		}
2090
2091		if (pxdesc) {
2092			if (ntfs_valid_posix(pxdesc)) {
2093				if (!strcmp(name,"system.posix_acl_default")) {
2094					if (ni->mrec->flags
2095						    & MFT_RECORD_IS_DIRECTORY)
2096						outsize = sizeof(struct POSIX_ACL)
2097							+ pxdesc->defcnt*sizeof(struct POSIX_ACE);
2098					else {
2099					/*
2100					 * getting default ACL from plain file :
2101					 * return EACCES if size > 0 as
2102					 * indicated in the man, but return ok
2103					 * if size == 0, so that ls does not
2104					 * display an error
2105					 */
2106						if (size > 0) {
2107							outsize = 0;
2108							errno = EACCES;
2109						} else
2110							outsize = sizeof(struct POSIX_ACL);
2111					}
2112					if (outsize && (outsize <= size)) {
2113						memcpy(value,&pxdesc->acl,sizeof(struct POSIX_ACL));
2114						memcpy(&value[sizeof(struct POSIX_ACL)],
2115							&pxdesc->acl.ace[pxdesc->firstdef],
2116							outsize-sizeof(struct POSIX_ACL));
2117					}
2118				} else {
2119					outsize = sizeof(struct POSIX_ACL)
2120						+ pxdesc->acccnt*sizeof(struct POSIX_ACE);
2121					if (outsize <= size)
2122						memcpy(value,&pxdesc->acl,outsize);
2123				}
2124			} else {
2125				outsize = 0;
2126				errno = EIO;
2127				ntfs_log_error("Invalid Posix ACL built\n");
2128			}
2129			if (!cached)
2130				free(pxdesc);
2131		} else
2132			outsize = 0;
2133	}
2134	return (outsize ? (int)outsize : -errno);
2135}
2136
2137#else /* POSIXACLS */
2138
2139
2140/*
2141 *		Get permissions to access a file
2142 *	Takes into account the relation of user to file (owner, group, ...)
2143 *	Do no use as mode of the file
2144 *
2145 *	returns -1 if there is a problem
2146 */
2147
2148static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
2149		ntfs_inode *ni,	mode_t request)
2150{
2151	const SECURITY_DESCRIPTOR_RELATIVE *phead;
2152	const struct CACHED_PERMISSIONS *cached;
2153	char *securattr;
2154	const SID *usid;	/* owner of file/directory */
2155	const SID *gsid;	/* group of file/directory */
2156	BOOL isdir;
2157	uid_t uid;
2158	gid_t gid;
2159	int perm;
2160
2161	if (!scx->mapping[MAPUSERS] || (!scx->uid && !(request & S_IEXEC)))
2162		perm = 07777;
2163	else {
2164		/* check whether available in cache */
2165		cached = fetch_cache(scx,ni);
2166		if (cached) {
2167			perm = cached->mode;
2168			uid = cached->uid;
2169			gid = cached->gid;
2170		} else {
2171			perm = 0;	/* default to no permission */
2172			isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2173				!= const_cpu_to_le16(0);
2174			securattr = getsecurityattr(scx->vol, ni);
2175			if (securattr) {
2176				phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2177				    	securattr;
2178				gsid = (const SID*)&
2179					   securattr[le32_to_cpu(phead->group)];
2180				gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2181#if OWNERFROMACL
2182				usid = ntfs_acl_owner(securattr);
2183				perm = ntfs_build_permissions(securattr,
2184						 usid, gsid, isdir);
2185				uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2186#else
2187				usid = (const SID*)&
2188					    securattr[le32_to_cpu(phead->owner)];
2189				perm = ntfs_build_permissions(securattr,
2190						 usid, gsid, isdir);
2191				if (!perm && ntfs_same_sid(usid, adminsid)) {
2192					uid = find_tenant(scx, securattr);
2193					if (uid)
2194						perm = 0700;
2195				} else
2196					uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2197#endif
2198				/*
2199				 *  Create a security id if there were none
2200				 * and upgrade option is selected
2201				 */
2202				if (!test_nino_flag(ni, v3_Extensions)
2203				   && (perm >= 0)
2204				   && (scx->vol->secure_flags
2205				     & (1 << SECURITY_ADDSECURIDS))) {
2206					upgrade_secur_desc(scx->vol,
2207						securattr, ni);
2208					/*
2209					 * fetch owner and group for cacheing
2210					 * if there is a securid
2211					 */
2212				}
2213				if (test_nino_flag(ni, v3_Extensions)
2214				    && (perm >= 0)) {
2215					enter_cache(scx, ni, uid,
2216							gid, perm);
2217				}
2218				free(securattr);
2219			} else {
2220				perm = -1;
2221				uid = gid = 0;
2222			}
2223		}
2224		if (perm >= 0) {
2225			if (!scx->uid) {
2226				/* root access and execution */
2227				if (perm & 0111)
2228					perm = 07777;
2229				else
2230					perm = 0;
2231			} else
2232				if (uid == scx->uid)
2233					perm &= 07700;
2234				else
2235				/*
2236				 * avoid checking group membership
2237				 * when the requested perms for group
2238				 * are the same as perms for other
2239				 */
2240					if ((gid == scx->gid)
2241					  || ((((perm >> 3) ^ perm)
2242						& (request >> 6) & 7)
2243					    && groupmember(scx, scx->uid, gid)))
2244						perm &= 07070;
2245					else
2246						perm &= 07007;
2247		}
2248	}
2249	return (perm);
2250}
2251
2252#endif /* POSIXACLS */
2253
2254/*
2255 *		Get an NTFS ACL
2256 *
2257 *	Returns size or -errno if there is a problem
2258 *	if size was too small, no copy is done and errno is not set,
2259 *	the caller is expected to issue a new call
2260 */
2261
2262int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2263			char *value, size_t size)
2264{
2265	char *securattr;
2266	size_t outsize;
2267
2268	outsize = 0;	/* default to no data and no error */
2269	securattr = getsecurityattr(scx->vol, ni);
2270	if (securattr) {
2271		outsize = ntfs_attr_size(securattr);
2272		if (outsize <= size) {
2273			memcpy(value,securattr,outsize);
2274		}
2275		free(securattr);
2276	}
2277	return (outsize ? (int)outsize : -errno);
2278}
2279
2280/*
2281 *		Get owner, group and permissions in an stat structure
2282 *	returns permissions, or -1 if there is a problem
2283 */
2284
2285int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
2286		ntfs_inode * ni, struct stat *stbuf)
2287{
2288	const SECURITY_DESCRIPTOR_RELATIVE *phead;
2289	char *securattr;
2290	const SID *usid;	/* owner of file/directory */
2291	const SID *gsid;	/* group of file/directory */
2292	const struct CACHED_PERMISSIONS *cached;
2293	int perm;
2294	BOOL isdir;
2295#if POSIXACLS
2296	struct POSIX_SECURITY *pxdesc;
2297#endif
2298
2299	if (!scx->mapping[MAPUSERS])
2300		perm = 07777;
2301	else {
2302			/* check whether available in cache */
2303		cached = fetch_cache(scx,ni);
2304		if (cached) {
2305			perm = cached->mode;
2306			stbuf->st_uid = cached->uid;
2307			stbuf->st_gid = cached->gid;
2308			stbuf->st_mode = (stbuf->st_mode & ~07777) + perm;
2309		} else {
2310			perm = -1;	/* default to error */
2311			isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2312				!= const_cpu_to_le16(0);
2313			securattr = getsecurityattr(scx->vol, ni);
2314			if (securattr) {
2315				phead =
2316				    (const SECURITY_DESCRIPTOR_RELATIVE*)
2317					    	securattr;
2318				gsid = (const SID*)&
2319					  securattr[le32_to_cpu(phead->group)];
2320#if OWNERFROMACL
2321				usid = ntfs_acl_owner(securattr);
2322#else
2323				usid = (const SID*)&
2324					  securattr[le32_to_cpu(phead->owner)];
2325#endif
2326#if POSIXACLS
2327				pxdesc = ntfs_build_permissions_posix(scx->mapping, securattr,
2328					  usid, gsid, isdir);
2329				if (pxdesc)
2330					perm = pxdesc->mode & 07777;
2331				else
2332					perm = -1;
2333#else
2334				perm = ntfs_build_permissions(securattr,
2335					  usid, gsid, isdir);
2336#endif
2337					/*
2338					 * fetch owner and group for cacheing
2339					 */
2340				if (perm >= 0) {
2341				/*
2342				 *  Create a security id if there were none
2343				 * and upgrade option is selected
2344				 */
2345					if (!test_nino_flag(ni, v3_Extensions)
2346					   && (scx->vol->secure_flags
2347					     & (1 << SECURITY_ADDSECURIDS))) {
2348						upgrade_secur_desc(scx->vol,
2349							 securattr, ni);
2350					}
2351#if OWNERFROMACL
2352					stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2353#else
2354					if (!perm && ntfs_same_sid(usid, adminsid)) {
2355						stbuf->st_uid =
2356							find_tenant(scx,
2357								securattr);
2358						if (stbuf->st_uid)
2359							perm = 0700;
2360					} else
2361						stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2362#endif
2363					stbuf->st_gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2364					stbuf->st_mode =
2365					    (stbuf->st_mode & ~07777) + perm;
2366#if POSIXACLS
2367					enter_cache(scx, ni, stbuf->st_uid,
2368						stbuf->st_gid, pxdesc);
2369					free(pxdesc);
2370#else
2371					enter_cache(scx, ni, stbuf->st_uid,
2372						stbuf->st_gid, perm);
2373#endif
2374				}
2375				free(securattr);
2376			}
2377		}
2378	}
2379	return (perm);
2380}
2381
2382#if POSIXACLS
2383
2384/*
2385 *		Get the base for a Posix inheritance and
2386 *	build an inherited Posix descriptor
2387 */
2388
2389static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx,
2390			ntfs_inode *dir_ni, mode_t mode, BOOL isdir)
2391{
2392	const struct CACHED_PERMISSIONS *cached;
2393	const SECURITY_DESCRIPTOR_RELATIVE *phead;
2394	struct POSIX_SECURITY *pxdesc;
2395	struct POSIX_SECURITY *pydesc;
2396	char *securattr;
2397	const SID *usid;
2398	const SID *gsid;
2399	uid_t uid;
2400	gid_t gid;
2401
2402	pydesc = (struct POSIX_SECURITY*)NULL;
2403		/* check whether parent directory is available in cache */
2404	cached = fetch_cache(scx,dir_ni);
2405	if (cached) {
2406		uid = cached->uid;
2407		gid = cached->gid;
2408		pxdesc = cached->pxdesc;
2409		if (pxdesc) {
2410			pydesc = ntfs_build_inherited_posix(pxdesc,mode,
2411					scx->umask,isdir);
2412		}
2413	} else {
2414		securattr = getsecurityattr(scx->vol, dir_ni);
2415		if (securattr) {
2416			phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2417			    	securattr;
2418			gsid = (const SID*)&
2419				   securattr[le32_to_cpu(phead->group)];
2420			gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2421#if OWNERFROMACL
2422			usid = ntfs_acl_owner(securattr);
2423			pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2424						 usid, gsid, TRUE);
2425			uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2426#else
2427			usid = (const SID*)&
2428				    securattr[le32_to_cpu(phead->owner)];
2429			pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2430						 usid, gsid, TRUE);
2431			if (pxdesc && ntfs_same_sid(usid, adminsid)) {
2432				uid = find_tenant(scx, securattr);
2433			} else
2434				uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2435#endif
2436			if (pxdesc) {
2437				/*
2438				 *  Create a security id if there were none
2439				 * and upgrade option is selected
2440				 */
2441				if (!test_nino_flag(dir_ni, v3_Extensions)
2442				   && (scx->vol->secure_flags
2443				     & (1 << SECURITY_ADDSECURIDS))) {
2444					upgrade_secur_desc(scx->vol,
2445						securattr, dir_ni);
2446					/*
2447					 * fetch owner and group for cacheing
2448					 * if there is a securid
2449					 */
2450				}
2451				if (test_nino_flag(dir_ni, v3_Extensions)) {
2452					enter_cache(scx, dir_ni, uid,
2453							gid, pxdesc);
2454				}
2455				pydesc = ntfs_build_inherited_posix(pxdesc,
2456					mode, scx->umask, isdir);
2457				free(pxdesc);
2458			}
2459			free(securattr);
2460		}
2461	}
2462	return (pydesc);
2463}
2464
2465/*
2466 *		Allocate a security_id for a file being created
2467 *
2468 *	Returns zero if not possible (NTFS v3.x required)
2469 */
2470
2471le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
2472		uid_t uid, gid_t gid, ntfs_inode *dir_ni,
2473		mode_t mode, BOOL isdir)
2474{
2475#if !FORCE_FORMAT_v1x
2476	const struct CACHED_SECURID *cached;
2477	struct CACHED_SECURID wanted;
2478	struct POSIX_SECURITY *pxdesc;
2479	char *newattr;
2480	int newattrsz;
2481	const SID *usid;
2482	const SID *gsid;
2483	BIGSID defusid;
2484	BIGSID defgsid;
2485	le32 securid;
2486#endif
2487
2488	securid = const_cpu_to_le32(0);
2489
2490#if !FORCE_FORMAT_v1x
2491
2492	pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
2493	if (pxdesc) {
2494		/* check whether target securid is known in cache */
2495
2496		wanted.uid = uid;
2497		wanted.gid = gid;
2498		wanted.dmode = pxdesc->mode & mode & 07777;
2499		if (isdir) wanted.dmode |= 0x10000;
2500		wanted.variable = (void*)pxdesc;
2501		wanted.varsize = sizeof(struct POSIX_SECURITY)
2502				+ (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2503		cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2504				scx->vol->securid_cache, GENERIC(&wanted),
2505				(cache_compare)compare);
2506			/* quite simple, if we are lucky */
2507		if (cached)
2508			securid = cached->securid;
2509
2510			/* not in cache : make sure we can create ids */
2511
2512		if (!cached && (scx->vol->major_ver >= 3)) {
2513			usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2514			gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2515			if (!usid || !gsid) {
2516				ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2517						(int)uid, (int)gid);
2518				usid = gsid = adminsid;
2519			}
2520			newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2521					isdir, usid, gsid);
2522			if (newattr) {
2523				newattrsz = ntfs_attr_size(newattr);
2524				securid = setsecurityattr(scx->vol,
2525					(const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
2526					newattrsz);
2527				if (securid) {
2528					/* update cache, for subsequent use */
2529					wanted.securid = securid;
2530					ntfs_enter_cache(scx->vol->securid_cache,
2531							GENERIC(&wanted),
2532							(cache_compare)compare);
2533				}
2534				free(newattr);
2535			} else {
2536				/*
2537				 * could not build new security attribute
2538				 * errno set by ntfs_build_descr()
2539				 */
2540			}
2541		}
2542	free(pxdesc);
2543	}
2544#endif
2545	return (securid);
2546}
2547
2548/*
2549 *		Apply Posix inheritance to a newly created file
2550 *	(for NTFS 1.x only : no securid)
2551 */
2552
2553int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
2554		ntfs_inode *ni, uid_t uid, gid_t gid,
2555		ntfs_inode *dir_ni, mode_t mode)
2556{
2557	struct POSIX_SECURITY *pxdesc;
2558	char *newattr;
2559	const SID *usid;
2560	const SID *gsid;
2561	BIGSID defusid;
2562	BIGSID defgsid;
2563	BOOL isdir;
2564	int res;
2565
2566	res = -1;
2567	isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2568	pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
2569	if (pxdesc) {
2570		usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2571		gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2572		if (!usid || !gsid) {
2573			ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2574					(int)uid, (int)gid);
2575			usid = gsid = adminsid;
2576		}
2577		newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2578					isdir, usid, gsid);
2579		if (newattr) {
2580				/* Adjust Windows read-only flag */
2581			res = update_secur_descr(scx->vol, newattr, ni);
2582			if (!res && !isdir) {
2583				if (mode & S_IWUSR)
2584					ni->flags &= ~FILE_ATTR_READONLY;
2585				else
2586					ni->flags |= FILE_ATTR_READONLY;
2587			}
2588#if CACHE_LEGACY_SIZE
2589			/* also invalidate legacy cache */
2590			if (isdir && !ni->security_id) {
2591				struct CACHED_PERMISSIONS_LEGACY legacy;
2592
2593				legacy.mft_no = ni->mft_no;
2594				legacy.variable = pxdesc;
2595				legacy.varsize = sizeof(struct POSIX_SECURITY)
2596					+ (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2597				ntfs_invalidate_cache(scx->vol->legacy_cache,
2598						GENERIC(&legacy),
2599						(cache_compare)leg_compare,0);
2600			}
2601#endif
2602			free(newattr);
2603
2604		} else {
2605			/*
2606			 * could not build new security attribute
2607			 * errno set by ntfs_build_descr()
2608			 */
2609		}
2610	}
2611	return (res);
2612}
2613
2614#else
2615
2616le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
2617		uid_t uid, gid_t gid, mode_t mode, BOOL isdir)
2618{
2619#if !FORCE_FORMAT_v1x
2620	const struct CACHED_SECURID *cached;
2621	struct CACHED_SECURID wanted;
2622	char *newattr;
2623	int newattrsz;
2624	const SID *usid;
2625	const SID *gsid;
2626	BIGSID defusid;
2627	BIGSID defgsid;
2628	le32 securid;
2629#endif
2630
2631	securid = const_cpu_to_le32(0);
2632
2633#if !FORCE_FORMAT_v1x
2634		/* check whether target securid is known in cache */
2635
2636	wanted.uid = uid;
2637	wanted.gid = gid;
2638	wanted.dmode = mode & 07777;
2639	if (isdir) wanted.dmode |= 0x10000;
2640	wanted.variable = (void*)NULL;
2641	wanted.varsize = 0;
2642	cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2643			scx->vol->securid_cache, GENERIC(&wanted),
2644			(cache_compare)compare);
2645		/* quite simple, if we are lucky */
2646	if (cached)
2647		securid = cached->securid;
2648
2649		/* not in cache : make sure we can create ids */
2650
2651	if (!cached && (scx->vol->major_ver >= 3)) {
2652		usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2653		gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2654		if (!usid || !gsid) {
2655			ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2656					(int)uid, (int)gid);
2657			usid = gsid = adminsid;
2658		}
2659		newattr = ntfs_build_descr(mode, isdir, usid, gsid);
2660		if (newattr) {
2661			newattrsz = ntfs_attr_size(newattr);
2662			securid = setsecurityattr(scx->vol,
2663				(const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
2664				newattrsz);
2665			if (securid) {
2666				/* update cache, for subsequent use */
2667				wanted.securid = securid;
2668				ntfs_enter_cache(scx->vol->securid_cache,
2669						GENERIC(&wanted),
2670						(cache_compare)compare);
2671			}
2672			free(newattr);
2673		} else {
2674			/*
2675			 * could not build new security attribute
2676			 * errno set by ntfs_build_descr()
2677			 */
2678		}
2679	}
2680#endif
2681	return (securid);
2682}
2683
2684#endif
2685
2686/*
2687 *		Update ownership and mode of a file, reusing an existing
2688 *	security descriptor when possible
2689 *
2690 *	Returns zero if successful
2691 */
2692
2693#if POSIXACLS
2694int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2695		uid_t uid, gid_t gid, mode_t mode,
2696		struct POSIX_SECURITY *pxdesc)
2697#else
2698int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2699		uid_t uid, gid_t gid, mode_t mode)
2700#endif
2701{
2702	int res;
2703	const struct CACHED_SECURID *cached;
2704	struct CACHED_SECURID wanted;
2705	char *newattr;
2706	const SID *usid;
2707	const SID *gsid;
2708	BIGSID defusid;
2709	BIGSID defgsid;
2710	BOOL isdir;
2711
2712	res = 0;
2713
2714		/* check whether target securid is known in cache */
2715
2716	isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2717	wanted.uid = uid;
2718	wanted.gid = gid;
2719	wanted.dmode = mode & 07777;
2720	if (isdir) wanted.dmode |= 0x10000;
2721#if POSIXACLS
2722	wanted.variable = (void*)pxdesc;
2723	if (pxdesc)
2724		wanted.varsize = sizeof(struct POSIX_SECURITY)
2725			+ (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2726	else
2727		wanted.varsize = 0;
2728#else
2729	wanted.variable = (void*)NULL;
2730	wanted.varsize = 0;
2731#endif
2732	if (test_nino_flag(ni, v3_Extensions)) {
2733		cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2734				scx->vol->securid_cache, GENERIC(&wanted),
2735				(cache_compare)compare);
2736			/* quite simple, if we are lucky */
2737		if (cached) {
2738			ni->security_id = cached->securid;
2739			NInoSetDirty(ni);
2740		}
2741	} else cached = (struct CACHED_SECURID*)NULL;
2742
2743	if (!cached) {
2744			/*
2745			 * Do not use usid and gsid from former attributes,
2746			 * but recompute them to get repeatable results
2747			 * which can be kept in cache.
2748			 */
2749		usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2750		gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2751		if (!usid || !gsid) {
2752			ntfs_log_error("File made owned by an unmapped user/group %d/%d\n",
2753				uid, gid);
2754			usid = gsid = adminsid;
2755		}
2756#if POSIXACLS
2757		if (pxdesc)
2758			newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2759					 isdir, usid, gsid);
2760		else
2761			newattr = ntfs_build_descr(mode,
2762					 isdir, usid, gsid);
2763#else
2764		newattr = ntfs_build_descr(mode,
2765					 isdir, usid, gsid);
2766#endif
2767		if (newattr) {
2768			res = update_secur_descr(scx->vol, newattr, ni);
2769			if (!res) {
2770				/* adjust Windows read-only flag */
2771				if (!isdir) {
2772					if (mode & S_IWUSR)
2773						ni->flags &= ~FILE_ATTR_READONLY;
2774					else
2775						ni->flags |= FILE_ATTR_READONLY;
2776					NInoFileNameSetDirty(ni);
2777				}
2778				/* update cache, for subsequent use */
2779				if (test_nino_flag(ni, v3_Extensions)) {
2780					wanted.securid = ni->security_id;
2781					ntfs_enter_cache(scx->vol->securid_cache,
2782							GENERIC(&wanted),
2783							(cache_compare)compare);
2784				}
2785#if CACHE_LEGACY_SIZE
2786				/* also invalidate legacy cache */
2787				if (isdir && !ni->security_id) {
2788					struct CACHED_PERMISSIONS_LEGACY legacy;
2789
2790					legacy.mft_no = ni->mft_no;
2791#if POSIXACLS
2792					legacy.variable = wanted.variable;
2793					legacy.varsize = wanted.varsize;
2794#else
2795					legacy.variable = (void*)NULL;
2796					legacy.varsize = 0;
2797#endif
2798					ntfs_invalidate_cache(scx->vol->legacy_cache,
2799						GENERIC(&legacy),
2800						(cache_compare)leg_compare,0);
2801				}
2802#endif
2803			}
2804			free(newattr);
2805		} else {
2806			/*
2807			 * could not build new security attribute
2808			 * errno set by ntfs_build_descr()
2809			 */
2810			res = -1;
2811		}
2812	}
2813	return (res);
2814}
2815
2816/*
2817 *		Check whether user has ownership rights on a file
2818 *
2819 *	Returns TRUE if allowed
2820 *		if not, errno tells why
2821 */
2822
2823BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni)
2824{
2825	const struct CACHED_PERMISSIONS *cached;
2826	char *oldattr;
2827	const SID *usid;
2828	uid_t processuid;
2829	uid_t uid;
2830	BOOL gotowner;
2831	int allowed;
2832
2833	processuid = scx->uid;
2834/* TODO : use CAP_FOWNER process capability */
2835	/*
2836	 * Always allow for root
2837	 * Also always allow if no mapping has been defined
2838	 */
2839	if (!scx->mapping[MAPUSERS] || !processuid)
2840		allowed = TRUE;
2841	else {
2842		gotowner = FALSE; /* default */
2843		/* get the owner, either from cache or from old attribute  */
2844		cached = fetch_cache(scx, ni);
2845		if (cached) {
2846			uid = cached->uid;
2847			gotowner = TRUE;
2848		} else {
2849			oldattr = getsecurityattr(scx->vol, ni);
2850			if (oldattr) {
2851#if OWNERFROMACL
2852				usid = ntfs_acl_owner(oldattr);
2853#else
2854				const SECURITY_DESCRIPTOR_RELATIVE *phead;
2855
2856				phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2857								oldattr;
2858				usid = (const SID*)&oldattr
2859						[le32_to_cpu(phead->owner)];
2860#endif
2861				uid = ntfs_find_user(scx->mapping[MAPUSERS],
2862						usid);
2863				gotowner = TRUE;
2864				free(oldattr);
2865			}
2866		}
2867		allowed = FALSE;
2868		if (gotowner) {
2869/* TODO : use CAP_FOWNER process capability */
2870			if (!processuid || (processuid == uid))
2871				allowed = TRUE;
2872			else
2873				errno = EPERM;
2874		}
2875	}
2876	return (allowed);
2877}
2878
2879#ifdef HAVE_SETXATTR    /* extended attributes interface required */
2880
2881#if POSIXACLS
2882
2883/*
2884 *		Set a new access or default Posix ACL to a file
2885 *		(or remove ACL if no input data)
2886 *	Validity of input data is checked after merging
2887 *
2888 *	Returns 0, or -1 if there is a problem which errno describes
2889 */
2890
2891int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2892			const char *name, const char *value, size_t size,
2893			int flags)
2894{
2895	const SECURITY_DESCRIPTOR_RELATIVE *phead;
2896	const struct CACHED_PERMISSIONS *cached;
2897	char *oldattr;
2898	uid_t processuid;
2899	const SID *usid;
2900	const SID *gsid;
2901	uid_t uid;
2902	uid_t gid;
2903	int res;
2904	BOOL isdir;
2905	BOOL deflt;
2906	BOOL exist;
2907	int count;
2908	struct POSIX_SECURITY *oldpxdesc;
2909	struct POSIX_SECURITY *newpxdesc;
2910
2911	/* get the current pxsec, either from cache or from old attribute  */
2912	res = -1;
2913	deflt = !strcmp(name,"system.posix_acl_default");
2914	if (size)
2915		count = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE);
2916	else
2917		count = 0;
2918	isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2919	newpxdesc = (struct POSIX_SECURITY*)NULL;
2920	if ((!value
2921		|| (((const struct POSIX_ACL*)value)->version == POSIX_VERSION))
2922	    && (!deflt || isdir || (!size && !value))) {
2923		cached = fetch_cache(scx, ni);
2924		if (cached) {
2925			uid = cached->uid;
2926			gid = cached->gid;
2927			oldpxdesc = cached->pxdesc;
2928			if (oldpxdesc) {
2929				newpxdesc = ntfs_replace_acl(oldpxdesc,
2930						(const struct POSIX_ACL*)value,count,deflt);
2931				}
2932		} else {
2933			oldattr = getsecurityattr(scx->vol, ni);
2934			if (oldattr) {
2935				phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
2936#if OWNERFROMACL
2937				usid = ntfs_acl_owner(oldattr);
2938#else
2939				usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
2940#endif
2941				gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
2942				uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2943				gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2944				oldpxdesc = ntfs_build_permissions_posix(scx->mapping,
2945					oldattr, usid, gsid, isdir);
2946				if (oldpxdesc) {
2947					if (deflt)
2948						exist = oldpxdesc->defcnt > 0;
2949					else
2950						exist = oldpxdesc->acccnt > 3;
2951					if ((exist && (flags & XATTR_CREATE))
2952					  || (!exist && (flags & XATTR_REPLACE))) {
2953						errno = (exist ? EEXIST : ENODATA);
2954					} else {
2955						newpxdesc = ntfs_replace_acl(oldpxdesc,
2956							(const struct POSIX_ACL*)value,count,deflt);
2957					}
2958					free(oldpxdesc);
2959				}
2960				free(oldattr);
2961			}
2962		}
2963	} else
2964		errno = EINVAL;
2965
2966	if (newpxdesc) {
2967		processuid = scx->uid;
2968/* TODO : use CAP_FOWNER process capability */
2969		if (!processuid || (uid == processuid)) {
2970				/*
2971				 * clear setgid if file group does
2972				 * not match process group
2973				 */
2974			if (processuid && (gid != scx->gid)
2975			    && !groupmember(scx, scx->uid, gid)) {
2976				newpxdesc->mode &= ~S_ISGID;
2977			}
2978			res = ntfs_set_owner_mode(scx, ni, uid, gid,
2979				newpxdesc->mode, newpxdesc);
2980		} else
2981			errno = EPERM;
2982		free(newpxdesc);
2983	}
2984	return (res ? -1 : 0);
2985}
2986
2987/*
2988 *		Remove a default Posix ACL from a file
2989 *
2990 *	Returns 0, or -1 if there is a problem which errno describes
2991 */
2992
2993int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2994			const char *name)
2995{
2996	return (ntfs_set_posix_acl(scx, ni, name,
2997			(const char*)NULL, 0, 0));
2998}
2999
3000#endif
3001
3002/*
3003 *		Set a new NTFS ACL to a file
3004 *
3005 *	Returns 0, or -1 if there is a problem
3006 */
3007
3008int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
3009			const char *value, size_t size,	int flags)
3010{
3011	char *attr;
3012	int res;
3013
3014	res = -1;
3015	if ((size > 0)
3016	   && !(flags & XATTR_CREATE)
3017	   && ntfs_valid_descr(value,size)
3018	   && (ntfs_attr_size(value) == size)) {
3019			/* need copying in order to write */
3020		attr = (char*)ntfs_malloc(size);
3021		if (attr) {
3022			memcpy(attr,value,size);
3023			res = update_secur_descr(scx->vol, attr, ni);
3024			/*
3025			 * No need to invalidate standard caches :
3026			 * the relation between a securid and
3027			 * the associated protection is unchanged,
3028			 * only the relation between a file and
3029			 * its securid and protection is changed.
3030			 */
3031#if CACHE_LEGACY_SIZE
3032			/*
3033			 * we must however invalidate the legacy
3034			 * cache, which is based on inode numbers.
3035			 * For safety, invalidate even if updating
3036			 * failed.
3037			 */
3038			if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3039			   && !ni->security_id) {
3040				struct CACHED_PERMISSIONS_LEGACY legacy;
3041
3042				legacy.mft_no = ni->mft_no;
3043				legacy.variable = (char*)NULL;
3044				legacy.varsize = 0;
3045				ntfs_invalidate_cache(scx->vol->legacy_cache,
3046					GENERIC(&legacy),
3047					(cache_compare)leg_compare,0);
3048			}
3049#endif
3050			free(attr);
3051		} else
3052			errno = ENOMEM;
3053	} else
3054		errno = EINVAL;
3055	return (res ? -1 : 0);
3056}
3057
3058#endif /* HAVE_SETXATTR */
3059
3060/*
3061 *		Set new permissions to a file
3062 *	Checks user mapping has been defined before request for setting
3063 *
3064 *	rejected if request is not originated by owner or root
3065 *
3066 *	returns 0 on success
3067 *		-1 on failure, with errno = EIO
3068 */
3069
3070int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode)
3071{
3072	const SECURITY_DESCRIPTOR_RELATIVE *phead;
3073	const struct CACHED_PERMISSIONS *cached;
3074	char *oldattr;
3075	const SID *usid;
3076	const SID *gsid;
3077	uid_t processuid;
3078	uid_t uid;
3079	uid_t gid;
3080	int res;
3081#if POSIXACLS
3082	BOOL isdir;
3083	int pxsize;
3084	const struct POSIX_SECURITY *oldpxdesc;
3085	struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
3086#endif
3087
3088	/* get the current owner, either from cache or from old attribute  */
3089	res = 0;
3090	cached = fetch_cache(scx, ni);
3091	if (cached) {
3092		uid = cached->uid;
3093		gid = cached->gid;
3094#if POSIXACLS
3095		oldpxdesc = cached->pxdesc;
3096		if (oldpxdesc) {
3097				/* must copy before merging */
3098			pxsize = sizeof(struct POSIX_SECURITY)
3099				+ (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
3100			newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
3101			if (newpxdesc) {
3102				memcpy(newpxdesc, oldpxdesc, pxsize);
3103				if (ntfs_merge_mode_posix(newpxdesc, mode))
3104					res = -1;
3105			} else
3106				res = -1;
3107		} else
3108			newpxdesc = (struct POSIX_SECURITY*)NULL;
3109#endif
3110	} else {
3111		oldattr = getsecurityattr(scx->vol, ni);
3112		if (oldattr) {
3113			phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
3114#if OWNERFROMACL
3115			usid = ntfs_acl_owner(oldattr);
3116#else
3117			usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
3118#endif
3119			gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
3120			uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3121			gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3122#if POSIXACLS
3123			isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
3124			newpxdesc = ntfs_build_permissions_posix(scx->mapping,
3125				oldattr, usid, gsid, isdir);
3126			if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
3127				res = -1;
3128#endif
3129			free(oldattr);
3130		} else
3131			res = -1;
3132	}
3133
3134	if (!res) {
3135		processuid = scx->uid;
3136/* TODO : use CAP_FOWNER process capability */
3137		if (!processuid || (uid == processuid)) {
3138				/*
3139				 * clear setgid if file group does
3140				 * not match process group
3141				 */
3142			if (processuid && (gid != scx->gid)
3143			    && !groupmember(scx, scx->uid, gid))
3144				mode &= ~S_ISGID;
3145#if POSIXACLS
3146			if (newpxdesc) {
3147				newpxdesc->mode = mode;
3148				res = ntfs_set_owner_mode(scx, ni, uid, gid,
3149					mode, newpxdesc);
3150			} else
3151				res = ntfs_set_owner_mode(scx, ni, uid, gid,
3152					mode, newpxdesc);
3153#else
3154			res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3155#endif
3156		} else {
3157			errno = EPERM;
3158			res = -1;	/* neither owner nor root */
3159		}
3160	} else {
3161		/*
3162		 * Should not happen : a default descriptor is generated
3163		 * by getsecurityattr() when there are none
3164		 */
3165		ntfs_log_error("File has no security descriptor\n");
3166		res = -1;
3167		errno = EIO;
3168	}
3169#if POSIXACLS
3170	if (newpxdesc) free(newpxdesc);
3171#endif
3172	return (res ? -1 : 0);
3173}
3174
3175/*
3176 *	Create a default security descriptor for files whose descriptor
3177 *	cannot be inherited
3178 */
3179
3180int ntfs_sd_add_everyone(ntfs_inode *ni)
3181{
3182	/* JPA SECURITY_DESCRIPTOR_ATTR *sd; */
3183	SECURITY_DESCRIPTOR_RELATIVE *sd;
3184	ACL *acl;
3185	ACCESS_ALLOWED_ACE *ace;
3186	SID *sid;
3187	int ret, sd_len;
3188
3189	/* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
3190	/*
3191	 * Calculate security descriptor length. We have 2 sub-authorities in
3192	 * owner and group SIDs, but structure SID contain only one, so add
3193	 * 4 bytes to every SID.
3194	 */
3195	sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
3196		sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
3197	sd = (SECURITY_DESCRIPTOR_RELATIVE*)ntfs_calloc(sd_len);
3198	if (!sd)
3199		return -1;
3200
3201	sd->revision = SECURITY_DESCRIPTOR_REVISION;
3202	sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
3203
3204	sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
3205	sid->revision = SID_REVISION;
3206	sid->sub_authority_count = 2;
3207	sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
3208	sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
3209	sid->identifier_authority.value[5] = 5;
3210	sd->owner = cpu_to_le32((u8*)sid - (u8*)sd);
3211
3212	sid = (SID*)((u8*)sid + sizeof(SID) + 4);
3213	sid->revision = SID_REVISION;
3214	sid->sub_authority_count = 2;
3215	sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
3216	sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
3217	sid->identifier_authority.value[5] = 5;
3218	sd->group = cpu_to_le32((u8*)sid - (u8*)sd);
3219
3220	acl = (ACL*)((u8*)sid + sizeof(SID) + 4);
3221	acl->revision = ACL_REVISION;
3222	acl->size = const_cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
3223	acl->ace_count = const_cpu_to_le16(1);
3224	sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd);
3225
3226	ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL));
3227	ace->type = ACCESS_ALLOWED_ACE_TYPE;
3228	ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
3229	ace->size = const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
3230	ace->mask = const_cpu_to_le32(0x1f01ff); /* FIXME */
3231	ace->sid.revision = SID_REVISION;
3232	ace->sid.sub_authority_count = 1;
3233	ace->sid.sub_authority[0] = const_cpu_to_le32(0);
3234	ace->sid.identifier_authority.value[5] = 1;
3235
3236	ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8*)sd,
3237			    sd_len);
3238	if (ret)
3239		ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR");
3240
3241	free(sd);
3242	return ret;
3243}
3244
3245/*
3246 *		Check whether user can access a file in a specific way
3247 *
3248 *	Returns 1 if access is allowed, including user is root or no
3249 *		  user mapping defined
3250 *		2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX
3251 *		0 and sets errno if there is a problem or if access
3252 *		  is not allowed
3253 *
3254 *	This is used for Posix ACL and checking creation of DOS file names
3255 */
3256
3257int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
3258		ntfs_inode *ni,
3259		int accesstype) /* access type required (S_Ixxx values) */
3260{
3261	int perm;
3262	int res;
3263	int allow;
3264	struct stat stbuf;
3265
3266	/*
3267	 * Always allow for root unless execution is requested.
3268	 * (was checked by fuse until kernel 2.6.29)
3269	 * Also always allow if no mapping has been defined
3270	 */
3271	if (!scx->mapping[MAPUSERS]
3272	    || (!scx->uid
3273		&& (!(accesstype & S_IEXEC)
3274		    || (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY))))
3275		allow = 1;
3276	else {
3277		perm = ntfs_get_perm(scx, ni, accesstype);
3278		if (perm >= 0) {
3279			res = EACCES;
3280			switch (accesstype) {
3281			case S_IEXEC:
3282				allow = (perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
3283				break;
3284			case S_IWRITE:
3285				allow = (perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0;
3286				break;
3287			case S_IWRITE + S_IEXEC:
3288				allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3289				    && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3290				break;
3291			case S_IREAD:
3292				allow = (perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0;
3293				break;
3294			case S_IREAD + S_IEXEC:
3295				allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3296				    && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3297				break;
3298			case S_IREAD + S_IWRITE:
3299				allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3300				    && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0);
3301				break;
3302			case S_IWRITE + S_IEXEC + S_ISVTX:
3303				if (perm & S_ISVTX) {
3304					if ((ntfs_get_owner_mode(scx,ni,&stbuf) >= 0)
3305					    && (stbuf.st_uid == scx->uid))
3306						allow = 1;
3307					else
3308						allow = 2;
3309				} else
3310					allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3311					    && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3312				break;
3313			case S_IREAD + S_IWRITE + S_IEXEC:
3314				allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
3315				    && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
3316				    && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
3317				break;
3318			default :
3319				res = EINVAL;
3320				allow = 0;
3321				break;
3322			}
3323			if (!allow)
3324				errno = res;
3325		} else
3326			allow = 0;
3327	}
3328	return (allow);
3329}
3330
3331#if 0 /* not needed any more */
3332
3333/*
3334 *		Check whether user can access the parent directory
3335 *	of a file in a specific way
3336 *
3337 *	Returns true if access is allowed, including user is root and
3338 *		no user mapping defined
3339 *
3340 *	Sets errno if there is a problem or if not allowed
3341 *
3342 *	This is used for Posix ACL and checking creation of DOS file names
3343 */
3344
3345BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
3346		const char *path, int accesstype)
3347{
3348	int allow;
3349	char *dirpath;
3350	char *name;
3351	ntfs_inode *ni;
3352	ntfs_inode *dir_ni;
3353	struct stat stbuf;
3354
3355	allow = 0;
3356	dirpath = strdup(path);
3357	if (dirpath) {
3358		/* the root of file system is seen as a parent of itself */
3359		/* is that correct ? */
3360		name = strrchr(dirpath, '/');
3361		*name = 0;
3362		dir_ni = ntfs_pathname_to_inode(scx->vol, NULL, dirpath);
3363		if (dir_ni) {
3364			allow = ntfs_allowed_access(scx,
3365				 dir_ni, accesstype);
3366			ntfs_inode_close(dir_ni);
3367				/*
3368				 * for an not-owned sticky directory, have to
3369				 * check whether file itself is owned
3370				 */
3371			if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX))
3372			   && (allow == 2)) {
3373				ni = ntfs_pathname_to_inode(scx->vol, NULL,
3374					 path);
3375				allow = FALSE;
3376				if (ni) {
3377					allow = (ntfs_get_owner_mode(scx,ni,&stbuf) >= 0)
3378						&& (stbuf.st_uid == scx->uid);
3379				ntfs_inode_close(ni);
3380				}
3381			}
3382		}
3383		free(dirpath);
3384	}
3385	return (allow);		/* errno is set if not allowed */
3386}
3387
3388#endif
3389
3390/*
3391 *		Define a new owner/group to a file
3392 *
3393 *	returns zero if successful
3394 */
3395
3396int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
3397			uid_t uid, gid_t gid)
3398{
3399	const SECURITY_DESCRIPTOR_RELATIVE *phead;
3400	const struct CACHED_PERMISSIONS *cached;
3401	char *oldattr;
3402	const SID *usid;
3403	const SID *gsid;
3404	uid_t fileuid;
3405	uid_t filegid;
3406	mode_t mode;
3407	int perm;
3408	BOOL isdir;
3409	int res;
3410#if POSIXACLS
3411	struct POSIX_SECURITY *pxdesc;
3412	BOOL pxdescbuilt = FALSE;
3413#endif
3414
3415	res = 0;
3416	/* get the current owner and mode from cache or security attributes */
3417	oldattr = (char*)NULL;
3418	cached = fetch_cache(scx,ni);
3419	if (cached) {
3420		fileuid = cached->uid;
3421		filegid = cached->gid;
3422		mode = cached->mode;
3423#if POSIXACLS
3424		pxdesc = cached->pxdesc;
3425		if (!pxdesc)
3426			res = -1;
3427#endif
3428	} else {
3429		fileuid = 0;
3430		filegid = 0;
3431		mode = 0;
3432		oldattr = getsecurityattr(scx->vol, ni);
3433		if (oldattr) {
3434			isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3435				!= const_cpu_to_le16(0);
3436			phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
3437				oldattr;
3438			gsid = (const SID*)
3439				&oldattr[le32_to_cpu(phead->group)];
3440#if OWNERFROMACL
3441			usid = ntfs_acl_owner(oldattr);
3442#else
3443			usid = (const SID*)
3444				&oldattr[le32_to_cpu(phead->owner)];
3445#endif
3446#if POSIXACLS
3447			pxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
3448					usid, gsid, isdir);
3449			if (pxdesc) {
3450				pxdescbuilt = TRUE;
3451				fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3452				filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3453				mode = perm = pxdesc->mode;
3454			} else
3455				res = -1;
3456#else
3457			mode = perm = ntfs_build_permissions(oldattr,
3458					 usid, gsid, isdir);
3459			if (perm >= 0) {
3460				fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3461				filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3462			} else
3463				res = -1;
3464#endif
3465			free(oldattr);
3466		} else
3467			res = -1;
3468	}
3469	if (!res) {
3470		/* check requested by root */
3471		/* or chgrp requested by owner to an owned group */
3472		if (!scx->uid
3473		   || ((((int)uid < 0) || (uid == fileuid))
3474		      && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
3475		      && (fileuid == scx->uid))) {
3476			/* replace by the new usid and gsid */
3477			/* or reuse old gid and sid for cacheing */
3478			if ((int)uid < 0)
3479				uid = fileuid;
3480			if ((int)gid < 0)
3481				gid = filegid;
3482			/* clear setuid and setgid if owner has changed */
3483                        /* unless request originated by root */
3484			if (uid && (fileuid != uid))
3485				mode &= 01777;
3486#if POSIXACLS
3487			res = ntfs_set_owner_mode(scx, ni, uid, gid,
3488				mode, pxdesc);
3489#else
3490			res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3491#endif
3492		} else {
3493			res = -1;	/* neither owner nor root */
3494			errno = EPERM;
3495		}
3496#if POSIXACLS
3497		if (pxdescbuilt)
3498			free(pxdesc);
3499#endif
3500	} else {
3501		/*
3502		 * Should not happen : a default descriptor is generated
3503		 * by getsecurityattr() when there are none
3504		 */
3505		ntfs_log_error("File has no security descriptor\n");
3506		res = -1;
3507		errno = EIO;
3508	}
3509	return (res ? -1 : 0);
3510}
3511
3512/*
3513 *		Define new owner/group and mode to a file
3514 *
3515 *	returns zero if successful
3516 */
3517
3518int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
3519			uid_t uid, gid_t gid, const mode_t mode)
3520{
3521	const struct CACHED_PERMISSIONS *cached;
3522	char *oldattr;
3523	uid_t fileuid;
3524	uid_t filegid;
3525	int res;
3526#if POSIXACLS
3527	const SECURITY_DESCRIPTOR_RELATIVE *phead;
3528	const SID *usid;
3529	const SID *gsid;
3530	BOOL isdir;
3531	const struct POSIX_SECURITY *oldpxdesc;
3532	struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
3533	int pxsize;
3534#endif
3535
3536	res = 0;
3537	/* get the current owner and mode from cache or security attributes */
3538	oldattr = (char*)NULL;
3539	cached = fetch_cache(scx,ni);
3540	if (cached) {
3541		fileuid = cached->uid;
3542		filegid = cached->gid;
3543#if POSIXACLS
3544		oldpxdesc = cached->pxdesc;
3545		if (oldpxdesc) {
3546				/* must copy before merging */
3547			pxsize = sizeof(struct POSIX_SECURITY)
3548				+ (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
3549			newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
3550			if (newpxdesc) {
3551				memcpy(newpxdesc, oldpxdesc, pxsize);
3552				if (ntfs_merge_mode_posix(newpxdesc, mode))
3553					res = -1;
3554			} else
3555				res = -1;
3556		}
3557#endif
3558	} else {
3559		fileuid = 0;
3560		filegid = 0;
3561		oldattr = getsecurityattr(scx->vol, ni);
3562		if (oldattr) {
3563#if POSIXACLS
3564			isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3565				!= const_cpu_to_le16(0);
3566			phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
3567				oldattr;
3568			gsid = (const SID*)
3569				&oldattr[le32_to_cpu(phead->group)];
3570#if OWNERFROMACL
3571			usid = ntfs_acl_owner(oldattr);
3572#else
3573			usid = (const SID*)
3574				&oldattr[le32_to_cpu(phead->owner)];
3575#endif
3576			newpxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
3577					usid, gsid, isdir);
3578			if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
3579				res = -1;
3580			else {
3581				fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3582				filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3583			}
3584#endif
3585			free(oldattr);
3586		} else
3587			res = -1;
3588	}
3589	if (!res) {
3590		/* check requested by root */
3591		/* or chgrp requested by owner to an owned group */
3592		if (!scx->uid
3593		   || ((((int)uid < 0) || (uid == fileuid))
3594		      && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
3595		      && (fileuid == scx->uid))) {
3596			/* replace by the new usid and gsid */
3597			/* or reuse old gid and sid for cacheing */
3598			if ((int)uid < 0)
3599				uid = fileuid;
3600			if ((int)gid < 0)
3601				gid = filegid;
3602#if POSIXACLS
3603			res = ntfs_set_owner_mode(scx, ni, uid, gid,
3604				mode, newpxdesc);
3605#else
3606			res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3607#endif
3608		} else {
3609			res = -1;	/* neither owner nor root */
3610			errno = EPERM;
3611		}
3612	} else {
3613		/*
3614		 * Should not happen : a default descriptor is generated
3615		 * by getsecurityattr() when there are none
3616		 */
3617		ntfs_log_error("File has no security descriptor\n");
3618		res = -1;
3619		errno = EIO;
3620	}
3621#if POSIXACLS
3622	free(newpxdesc);
3623#endif
3624	return (res ? -1 : 0);
3625}
3626
3627/*
3628 *		Build a security id for a descriptor inherited from
3629 *	parent directory the Windows way
3630 */
3631
3632static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
3633			const char *parentattr, BOOL fordir)
3634{
3635	const SECURITY_DESCRIPTOR_RELATIVE *pphead;
3636	const ACL *ppacl;
3637	const SID *usid;
3638	const SID *gsid;
3639	BIGSID defusid;
3640	BIGSID defgsid;
3641	int offpacl;
3642	int offowner;
3643	int offgroup;
3644	SECURITY_DESCRIPTOR_RELATIVE *pnhead;
3645	ACL *pnacl;
3646	int parentattrsz;
3647	char *newattr;
3648	int newattrsz;
3649	int aclsz;
3650	int usidsz;
3651	int gsidsz;
3652	int pos;
3653	le32 securid;
3654
3655	parentattrsz = ntfs_attr_size(parentattr);
3656	pphead = (const SECURITY_DESCRIPTOR_RELATIVE*)parentattr;
3657	if (scx->mapping[MAPUSERS]) {
3658		usid = ntfs_find_usid(scx->mapping[MAPUSERS], scx->uid, (SID*)&defusid);
3659		gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS], scx->gid, (SID*)&defgsid);
3660		if (!usid)
3661			usid = adminsid;
3662		if (!gsid)
3663			gsid = adminsid;
3664	} else {
3665		/*
3666		 * If there is no user mapping, we have to copy owner
3667		 * and group from parent directory.
3668		 * Windows never has to do that, because it can always
3669		 * rely on a user mapping
3670		 */
3671		offowner = le32_to_cpu(pphead->owner);
3672		usid = (const SID*)&parentattr[offowner];
3673		offgroup = le32_to_cpu(pphead->group);
3674		gsid = (const SID*)&parentattr[offgroup];
3675	}
3676		/*
3677		 * new attribute is smaller than parent's
3678		 * except for differences in SIDs which appear in
3679		 * owner, group and possible grants and denials in
3680		 * generic creator-owner and creator-group ACEs.
3681		 * For directories, an ACE may be duplicated for
3682		 * access and inheritance, so we double the count.
3683		 */
3684	usidsz = ntfs_sid_size(usid);
3685	gsidsz = ntfs_sid_size(gsid);
3686	newattrsz = parentattrsz + 3*usidsz + 3*gsidsz;
3687	if (fordir)
3688		newattrsz *= 2;
3689	newattr = (char*)ntfs_malloc(newattrsz);
3690	if (newattr) {
3691		pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr;
3692		pnhead->revision = SECURITY_DESCRIPTOR_REVISION;
3693		pnhead->alignment = 0;
3694		pnhead->control = SE_SELF_RELATIVE;
3695		pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
3696			/*
3697			 * locate and inherit DACL
3698			 * do not test SE_DACL_PRESENT (wrong for "DR Watson")
3699			 */
3700		pnhead->dacl = const_cpu_to_le32(0);
3701		if (pphead->dacl) {
3702			offpacl = le32_to_cpu(pphead->dacl);
3703			ppacl = (const ACL*)&parentattr[offpacl];
3704			pnacl = (ACL*)&newattr[pos];
3705			aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
3706			if (aclsz) {
3707				pnhead->dacl = cpu_to_le32(pos);
3708				pos += aclsz;
3709				pnhead->control |= SE_DACL_PRESENT;
3710			}
3711		}
3712			/*
3713			 * locate and inherit SACL
3714			 */
3715		pnhead->sacl = const_cpu_to_le32(0);
3716		if (pphead->sacl) {
3717			offpacl = le32_to_cpu(pphead->sacl);
3718			ppacl = (const ACL*)&parentattr[offpacl];
3719			pnacl = (ACL*)&newattr[pos];
3720			aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
3721			if (aclsz) {
3722				pnhead->sacl = cpu_to_le32(pos);
3723				pos += aclsz;
3724				pnhead->control |= SE_SACL_PRESENT;
3725			}
3726		}
3727			/*
3728			 * inherit or redefine owner
3729			 */
3730		memcpy(&newattr[pos],usid,usidsz);
3731		pnhead->owner = cpu_to_le32(pos);
3732		pos += usidsz;
3733			/*
3734			 * inherit or redefine group
3735			 */
3736		memcpy(&newattr[pos],gsid,gsidsz);
3737		pnhead->group = cpu_to_le32(pos);
3738		pos += usidsz;
3739		securid = setsecurityattr(scx->vol,
3740			(SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos);
3741		free(newattr);
3742	} else
3743		securid = const_cpu_to_le32(0);
3744	return (securid);
3745}
3746
3747/*
3748 *		Get an inherited security id
3749 *
3750 *	For Windows compatibility, the normal initial permission setting
3751 *	may be inherited from the parent directory instead of being
3752 *	defined by the creation arguments.
3753 *
3754 *	The following creates an inherited id for that purpose.
3755 *
3756 *	Note : the owner and group of parent directory are also
3757 *	inherited (which is not the case on Windows) if no user mapping
3758 *	is defined.
3759 *
3760 *	Returns the inherited id, or zero if not possible (eg on NTFS 1.x)
3761 */
3762
3763le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
3764			ntfs_inode *dir_ni, BOOL fordir)
3765{
3766	struct CACHED_PERMISSIONS *cached;
3767	char *parentattr;
3768	le32 securid;
3769
3770	securid = const_cpu_to_le32(0);
3771	cached = (struct CACHED_PERMISSIONS*)NULL;
3772		/*
3773		 * Try to get inherited id from cache
3774		 */
3775	if (test_nino_flag(dir_ni, v3_Extensions)
3776			&& dir_ni->security_id) {
3777		cached = fetch_cache(scx, dir_ni);
3778		if (cached)
3779			securid = (fordir ? cached->inh_dirid
3780					: cached->inh_fileid);
3781	}
3782		/*
3783		 * Not cached or not available in cache, compute it all
3784		 * Note : if parent directory has no id, it is not cacheable
3785		 */
3786	if (!securid) {
3787		parentattr = getsecurityattr(scx->vol, dir_ni);
3788		if (parentattr) {
3789			securid = build_inherited_id(scx,
3790						parentattr, fordir);
3791			free(parentattr);
3792			/*
3793			 * Store the result into cache for further use
3794			 */
3795			if (securid) {
3796				cached = fetch_cache(scx, dir_ni);
3797				if (cached) {
3798					if (fordir)
3799						cached->inh_dirid = securid;
3800					else
3801						cached->inh_fileid = securid;
3802				}
3803			}
3804		}
3805	}
3806	return (securid);
3807}
3808
3809/*
3810 *		Link a group to a member of group
3811 *
3812 *	Returns 0 if OK, -1 (and errno set) if error
3813 */
3814
3815static int link_single_group(struct MAPPING *usermapping, struct passwd *user,
3816			gid_t gid)
3817{
3818	struct group *group;
3819	char **grmem;
3820	int grcnt;
3821	gid_t *groups;
3822	int res;
3823
3824	res = 0;
3825	group = getgrgid(gid);
3826	if (group && group->gr_mem) {
3827		grcnt = usermapping->grcnt;
3828		groups = usermapping->groups;
3829		grmem = group->gr_mem;
3830		while (*grmem && strcmp(user->pw_name, *grmem))
3831			grmem++;
3832		if (*grmem) {
3833			if (!grcnt)
3834				groups = (gid_t*)malloc(sizeof(gid_t));
3835			else
3836				groups = (gid_t*)realloc(groups,
3837					(grcnt+1)*sizeof(gid_t));
3838			if (groups)
3839				groups[grcnt++]	= gid;
3840			else {
3841				res = -1;
3842				errno = ENOMEM;
3843			}
3844		}
3845		usermapping->grcnt = grcnt;
3846		usermapping->groups = groups;
3847	}
3848	return (res);
3849}
3850
3851
3852/*
3853 *		Statically link group to users
3854 *	This is based on groups defined in /etc/group and does not take
3855 *	the groups dynamically set by setgroups() nor any changes in
3856 *	/etc/group into account
3857 *
3858 *	Only mapped groups and root group are linked to mapped users
3859 *
3860 *	Returns 0 if OK, -1 (and errno set) if error
3861 *
3862 */
3863
3864static int link_group_members(struct SECURITY_CONTEXT *scx)
3865{
3866	struct MAPPING *usermapping;
3867	struct MAPPING *groupmapping;
3868	struct passwd *user;
3869	int res;
3870
3871	res = 0;
3872	for (usermapping=scx->mapping[MAPUSERS]; usermapping && !res;
3873			usermapping=usermapping->next) {
3874		usermapping->grcnt = 0;
3875		usermapping->groups = (gid_t*)NULL;
3876		user = getpwuid(usermapping->xid);
3877		if (user && user->pw_name) {
3878			for (groupmapping=scx->mapping[MAPGROUPS];
3879					groupmapping && !res;
3880					groupmapping=groupmapping->next) {
3881				if (link_single_group(usermapping, user,
3882				    groupmapping->xid))
3883					res = -1;
3884				}
3885			if (!res && link_single_group(usermapping,
3886					 user, (gid_t)0))
3887				res = -1;
3888		}
3889	}
3890	return (res);
3891}
3892
3893/*
3894 *		Apply default single user mapping
3895 *	returns zero if successful
3896 */
3897
3898static int ntfs_do_default_mapping(struct SECURITY_CONTEXT *scx,
3899			 uid_t uid, gid_t gid, const SID *usid)
3900{
3901	struct MAPPING *usermapping;
3902	struct MAPPING *groupmapping;
3903	SID *sid;
3904	int sidsz;
3905	int res;
3906
3907	res = -1;
3908	sidsz = ntfs_sid_size(usid);
3909	sid = (SID*)ntfs_malloc(sidsz);
3910	if (sid) {
3911		memcpy(sid,usid,sidsz);
3912		usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
3913		if (usermapping) {
3914			groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
3915			if (groupmapping) {
3916				usermapping->sid = sid;
3917				usermapping->xid = uid;
3918				usermapping->next = (struct MAPPING*)NULL;
3919				groupmapping->sid = sid;
3920				groupmapping->xid = gid;
3921				groupmapping->next = (struct MAPPING*)NULL;
3922				scx->mapping[MAPUSERS] = usermapping;
3923				scx->mapping[MAPGROUPS] = groupmapping;
3924				res = 0;
3925			}
3926		}
3927	}
3928	return (res);
3929}
3930
3931/*
3932 *		Make sure there are no ambiguous mapping
3933 *	Ambiguous mapping may lead to undesired configurations and
3934 *	we had rather be safe until the consequences are understood
3935 */
3936
3937#if 0 /* not activated for now */
3938
3939static BOOL check_mapping(const struct MAPPING *usermapping,
3940		const struct MAPPING *groupmapping)
3941{
3942	const struct MAPPING *mapping1;
3943	const struct MAPPING *mapping2;
3944	BOOL ambiguous;
3945
3946	ambiguous = FALSE;
3947	for (mapping1=usermapping; mapping1; mapping1=mapping1->next)
3948		for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
3949			if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
3950				if (mapping1->xid != mapping2->xid)
3951					ambiguous = TRUE;
3952			} else {
3953				if (mapping1->xid == mapping2->xid)
3954					ambiguous = TRUE;
3955			}
3956	for (mapping1=groupmapping; mapping1; mapping1=mapping1->next)
3957		for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
3958			if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
3959				if (mapping1->xid != mapping2->xid)
3960					ambiguous = TRUE;
3961			} else {
3962				if (mapping1->xid == mapping2->xid)
3963					ambiguous = TRUE;
3964			}
3965	return (ambiguous);
3966}
3967
3968#endif
3969
3970#if 0 /* not used any more */
3971
3972/*
3973 *		Try and apply default single user mapping
3974 *	returns zero if successful
3975 */
3976
3977static int ntfs_default_mapping(struct SECURITY_CONTEXT *scx)
3978{
3979	const SECURITY_DESCRIPTOR_RELATIVE *phead;
3980	ntfs_inode *ni;
3981	char *securattr;
3982	const SID *usid;
3983	int res;
3984
3985	res = -1;
3986	ni = ntfs_pathname_to_inode(scx->vol, NULL, "/.");
3987	if (ni) {
3988		securattr = getsecurityattr(scx->vol, ni);
3989		if (securattr) {
3990			phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr;
3991			usid = (SID*)&securattr[le32_to_cpu(phead->owner)];
3992			if (ntfs_is_user_sid(usid))
3993				res = ntfs_do_default_mapping(scx,
3994						scx->uid, scx->gid, usid);
3995			free(securattr);
3996		}
3997		ntfs_inode_close(ni);
3998	}
3999	return (res);
4000}
4001
4002#endif
4003
4004/*
4005 *		Basic read from a user mapping file on another volume
4006 */
4007
4008static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused)))
4009{
4010	return (read(*(int*)fileid, buf, size));
4011}
4012
4013
4014/*
4015 *		Read from a user mapping file on current NTFS partition
4016 */
4017
4018static int localread(void *fileid, char *buf, size_t size, off_t offs)
4019{
4020	return (ntfs_attr_data_read((ntfs_inode*)fileid,
4021			AT_UNNAMED, 0, buf, size, offs));
4022}
4023
4024/*
4025 *		Build the user mapping
4026 *	- according to a mapping file if defined (or default present),
4027 *	- or try default single user mapping if possible
4028 *
4029 *	The mapping is specific to a mounted device
4030 *	No locking done, mounting assumed non multithreaded
4031 *
4032 *	returns zero if mapping is successful
4033 *	(failure should not be interpreted as an error)
4034 */
4035
4036int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
4037			BOOL allowdef)
4038{
4039	struct MAPLIST *item;
4040	struct MAPLIST *firstitem;
4041	struct MAPPING *usermapping;
4042	struct MAPPING *groupmapping;
4043	ntfs_inode *ni;
4044	int fd;
4045	static struct {
4046		u8 revision;
4047		u8 levels;
4048		be16 highbase;
4049		be32 lowbase;
4050		le32 level1;
4051		le32 level2;
4052		le32 level3;
4053		le32 level4;
4054		le32 level5;
4055	} defmap = {
4056		1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5),
4057		const_cpu_to_le32(21),
4058		const_cpu_to_le32(DEFSECAUTH1), const_cpu_to_le32(DEFSECAUTH2),
4059		const_cpu_to_le32(DEFSECAUTH3), const_cpu_to_le32(DEFSECBASE)
4060	} ;
4061
4062	/* be sure not to map anything until done */
4063	scx->mapping[MAPUSERS] = (struct MAPPING*)NULL;
4064	scx->mapping[MAPGROUPS] = (struct MAPPING*)NULL;
4065
4066	if (!usermap_path) usermap_path = MAPPINGFILE;
4067	if (usermap_path[0] == '/') {
4068		fd = open(usermap_path,O_RDONLY);
4069		if (fd > 0) {
4070			firstitem = ntfs_read_mapping(basicread, (void*)&fd);
4071			close(fd);
4072		} else
4073			firstitem = (struct MAPLIST*)NULL;
4074	} else {
4075		ni = ntfs_pathname_to_inode(scx->vol, NULL, usermap_path);
4076		if (ni) {
4077			firstitem = ntfs_read_mapping(localread, ni);
4078			ntfs_inode_close(ni);
4079		} else
4080			firstitem = (struct MAPLIST*)NULL;
4081	}
4082
4083
4084	if (firstitem) {
4085		usermapping = ntfs_do_user_mapping(firstitem);
4086		groupmapping = ntfs_do_group_mapping(firstitem);
4087		if (usermapping && groupmapping) {
4088			scx->mapping[MAPUSERS] = usermapping;
4089			scx->mapping[MAPGROUPS] = groupmapping;
4090		} else
4091			ntfs_log_error("There were no valid user or no valid group\n");
4092		/* now we can free the memory copy of input text */
4093		/* and rely on internal representation */
4094		while (firstitem) {
4095			item = firstitem->next;
4096			free(firstitem);
4097			firstitem = item;
4098		}
4099	} else {
4100			/* no mapping file, try a default mapping */
4101		if (allowdef) {
4102			if (!ntfs_do_default_mapping(scx,
4103					0, 0, (const SID*)&defmap))
4104				ntfs_log_info("Using default user mapping\n");
4105		}
4106	}
4107	return (!scx->mapping[MAPUSERS] || link_group_members(scx));
4108}
4109
4110#ifdef HAVE_SETXATTR    /* extended attributes interface required */
4111
4112/*
4113 *		Get the ntfs attribute into an extended attribute
4114 *	The attribute is returned according to cpu endianness
4115 */
4116
4117int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size)
4118{
4119	u32 attrib;
4120	size_t outsize;
4121
4122	outsize = 0;	/* default to no data and no error */
4123	if (ni) {
4124		attrib = le32_to_cpu(ni->flags);
4125		if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
4126			attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4127		else
4128			attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4129		if (!attrib)
4130			attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
4131		outsize = sizeof(FILE_ATTR_FLAGS);
4132		if (size >= outsize) {
4133			if (value)
4134				memcpy(value,&attrib,outsize);
4135			else
4136				errno = EINVAL;
4137		}
4138	}
4139	return (outsize ? (int)outsize : -errno);
4140}
4141
4142/*
4143 *		Return the ntfs attribute into an extended attribute
4144 *	The attribute is expected according to cpu endianness
4145 *
4146 *	Returns 0, or -1 if there is a problem
4147 */
4148
4149int ntfs_set_ntfs_attrib(ntfs_inode *ni,
4150			const char *value, size_t size,	int flags)
4151{
4152	u32 attrib;
4153	le32 settable;
4154	ATTR_FLAGS dirflags;
4155	int res;
4156
4157	res = -1;
4158	if (ni && value && (size >= sizeof(FILE_ATTR_FLAGS))) {
4159		if (!(flags & XATTR_CREATE)) {
4160			/* copy to avoid alignment problems */
4161			memcpy(&attrib,value,sizeof(FILE_ATTR_FLAGS));
4162			settable = FILE_ATTR_SETTABLE;
4163			res = 0;
4164			if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4165				/*
4166				 * Accept changing compression for a directory
4167				 * and set index root accordingly
4168				 */
4169				settable |= FILE_ATTR_COMPRESSED;
4170				if ((ni->flags ^ cpu_to_le32(attrib))
4171				             & FILE_ATTR_COMPRESSED) {
4172					if (ni->flags & FILE_ATTR_COMPRESSED)
4173						dirflags = const_cpu_to_le16(0);
4174					else
4175						dirflags = ATTR_IS_COMPRESSED;
4176					res = ntfs_attr_set_flags(ni,
4177						AT_INDEX_ROOT,
4178					        NTFS_INDEX_I30, 4,
4179						dirflags,
4180						ATTR_COMPRESSION_MASK);
4181				}
4182			}
4183			if (!res) {
4184				ni->flags = (ni->flags & ~settable)
4185					 | (cpu_to_le32(attrib) & settable);
4186				NInoFileNameSetDirty(ni);
4187				NInoSetDirty(ni);
4188			}
4189		} else
4190			errno = EEXIST;
4191	} else
4192		errno = EINVAL;
4193	return (res ? -1 : 0);
4194}
4195
4196#endif /* HAVE_SETXATTR */
4197
4198/*
4199 *	Open $Secure once for all
4200 *	returns zero if it succeeds
4201 *		non-zero if it fails. This is not an error (on NTFS v1.x)
4202 */
4203
4204
4205int ntfs_open_secure(ntfs_volume *vol)
4206{
4207	ntfs_inode *ni;
4208	int res;
4209
4210	res = -1;
4211	vol->secure_ni = (ntfs_inode*)NULL;
4212	vol->secure_xsii = (ntfs_index_context*)NULL;
4213	vol->secure_xsdh = (ntfs_index_context*)NULL;
4214	if (vol->major_ver >= 3) {
4215			/* make sure this is a genuine $Secure inode 9 */
4216		ni = ntfs_pathname_to_inode(vol, NULL, "$Secure");
4217		if (ni && (ni->mft_no == 9)) {
4218			vol->secure_reentry = 0;
4219			vol->secure_xsii = ntfs_index_ctx_get(ni,
4220						sii_stream, 4);
4221			vol->secure_xsdh = ntfs_index_ctx_get(ni,
4222						sdh_stream, 4);
4223			if (ni && vol->secure_xsii && vol->secure_xsdh) {
4224				vol->secure_ni = ni;
4225				res = 0;
4226			}
4227		}
4228	}
4229	return (res);
4230}
4231
4232/*
4233 *		Final cleaning
4234 *	Allocated memory is freed to facilitate the detection of memory leaks
4235 */
4236
4237void ntfs_close_secure(struct SECURITY_CONTEXT *scx)
4238{
4239	ntfs_volume *vol;
4240
4241	vol = scx->vol;
4242	if (vol->secure_ni) {
4243		ntfs_index_ctx_put(vol->secure_xsii);
4244		ntfs_index_ctx_put(vol->secure_xsdh);
4245		ntfs_inode_close(vol->secure_ni);
4246
4247	}
4248	ntfs_free_mapping(scx->mapping);
4249	free_caches(scx);
4250}
4251
4252/*
4253 *		API for direct access to security descriptors
4254 *	based on Win32 API
4255 */
4256
4257
4258/*
4259 *		Selective feeding of a security descriptor into user buffer
4260 *
4261 *	Returns TRUE if successful
4262 */
4263
4264static BOOL feedsecurityattr(const char *attr, u32 selection,
4265		char *buf, u32 buflen, u32 *psize)
4266{
4267	const SECURITY_DESCRIPTOR_RELATIVE *phead;
4268	SECURITY_DESCRIPTOR_RELATIVE *pnhead;
4269	const ACL *pdacl;
4270	const ACL *psacl;
4271	const SID *pusid;
4272	const SID *pgsid;
4273	unsigned int offdacl;
4274	unsigned int offsacl;
4275	unsigned int offowner;
4276	unsigned int offgroup;
4277	unsigned int daclsz;
4278	unsigned int saclsz;
4279	unsigned int usidsz;
4280	unsigned int gsidsz;
4281	unsigned int size; /* size of requested attributes */
4282	BOOL ok;
4283	unsigned int pos;
4284	unsigned int avail;
4285	le16 control;
4286
4287	avail = 0;
4288	control = SE_SELF_RELATIVE;
4289	phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4290	size = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4291
4292		/* locate DACL if requested and available */
4293	if (phead->dacl && (selection & DACL_SECURITY_INFORMATION)) {
4294		offdacl = le32_to_cpu(phead->dacl);
4295		pdacl = (const ACL*)&attr[offdacl];
4296		daclsz = le16_to_cpu(pdacl->size);
4297		size += daclsz;
4298		avail |= DACL_SECURITY_INFORMATION;
4299	} else
4300		offdacl = daclsz = 0;
4301
4302		/* locate owner if requested and available */
4303	offowner = le32_to_cpu(phead->owner);
4304	if (offowner && (selection & OWNER_SECURITY_INFORMATION)) {
4305			/* find end of USID */
4306		pusid = (const SID*)&attr[offowner];
4307		usidsz = ntfs_sid_size(pusid);
4308		size += usidsz;
4309		avail |= OWNER_SECURITY_INFORMATION;
4310	} else
4311		offowner = usidsz = 0;
4312
4313		/* locate group if requested and available */
4314	offgroup = le32_to_cpu(phead->group);
4315	if (offgroup && (selection & GROUP_SECURITY_INFORMATION)) {
4316			/* find end of GSID */
4317		pgsid = (const SID*)&attr[offgroup];
4318		gsidsz = ntfs_sid_size(pgsid);
4319		size += gsidsz;
4320		avail |= GROUP_SECURITY_INFORMATION;
4321	} else
4322		offgroup = gsidsz = 0;
4323
4324		/* locate SACL if requested and available */
4325	if (phead->sacl && (selection & SACL_SECURITY_INFORMATION)) {
4326			/* find end of SACL */
4327		offsacl = le32_to_cpu(phead->sacl);
4328		psacl = (const ACL*)&attr[offsacl];
4329		saclsz = le16_to_cpu(psacl->size);
4330		size += saclsz;
4331		avail |= SACL_SECURITY_INFORMATION;
4332	} else
4333		offsacl = saclsz = 0;
4334
4335		/*
4336		 * Check having enough size in destination buffer
4337		 * (required size is returned nevertheless so that
4338		 * the request can be reissued with adequate size)
4339		 */
4340	if (size > buflen) {
4341		*psize = size;
4342		errno = EINVAL;
4343		ok = FALSE;
4344	} else {
4345		if (selection & OWNER_SECURITY_INFORMATION)
4346			control |= phead->control & SE_OWNER_DEFAULTED;
4347		if (selection & GROUP_SECURITY_INFORMATION)
4348			control |= phead->control & SE_GROUP_DEFAULTED;
4349		if (selection & DACL_SECURITY_INFORMATION)
4350			control |= phead->control
4351					& (SE_DACL_PRESENT
4352					   | SE_DACL_DEFAULTED
4353					   | SE_DACL_AUTO_INHERITED
4354					   | SE_DACL_PROTECTED);
4355		if (selection & SACL_SECURITY_INFORMATION)
4356			control |= phead->control
4357					& (SE_SACL_PRESENT
4358					   | SE_SACL_DEFAULTED
4359					   | SE_SACL_AUTO_INHERITED
4360					   | SE_SACL_PROTECTED);
4361		/*
4362		 * copy header and feed new flags, even if no detailed data
4363		 */
4364		memcpy(buf,attr,sizeof(SECURITY_DESCRIPTOR_RELATIVE));
4365		pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)buf;
4366		pnhead->control = control;
4367		pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4368
4369		/* copy DACL if requested and available */
4370		if (selection & avail & DACL_SECURITY_INFORMATION) {
4371			pnhead->dacl = cpu_to_le32(pos);
4372			memcpy(&buf[pos],&attr[offdacl],daclsz);
4373			pos += daclsz;
4374		} else
4375			pnhead->dacl = const_cpu_to_le32(0);
4376
4377		/* copy SACL if requested and available */
4378		if (selection & avail & SACL_SECURITY_INFORMATION) {
4379			pnhead->sacl = cpu_to_le32(pos);
4380			memcpy(&buf[pos],&attr[offsacl],saclsz);
4381			pos += saclsz;
4382		} else
4383			pnhead->sacl = const_cpu_to_le32(0);
4384
4385		/* copy owner if requested and available */
4386		if (selection & avail & OWNER_SECURITY_INFORMATION) {
4387			pnhead->owner = cpu_to_le32(pos);
4388			memcpy(&buf[pos],&attr[offowner],usidsz);
4389			pos += usidsz;
4390		} else
4391			pnhead->owner = const_cpu_to_le32(0);
4392
4393		/* copy group if requested and available */
4394		if (selection & avail & GROUP_SECURITY_INFORMATION) {
4395			pnhead->group = cpu_to_le32(pos);
4396			memcpy(&buf[pos],&attr[offgroup],gsidsz);
4397			pos += gsidsz;
4398		} else
4399			pnhead->group = const_cpu_to_le32(0);
4400		if (pos != size)
4401			ntfs_log_error("Error in security descriptor size\n");
4402		*psize = size;
4403		ok = TRUE;
4404	}
4405
4406	return (ok);
4407}
4408
4409/*
4410 *		Merge a new security descriptor into the old one
4411 *	and assign to designated file
4412 *
4413 *	Returns TRUE if successful
4414 */
4415
4416static BOOL mergesecurityattr(ntfs_volume *vol, const char *oldattr,
4417		const char *newattr, u32 selection, ntfs_inode *ni)
4418{
4419	const SECURITY_DESCRIPTOR_RELATIVE *oldhead;
4420	const SECURITY_DESCRIPTOR_RELATIVE *newhead;
4421	SECURITY_DESCRIPTOR_RELATIVE *targhead;
4422	const ACL *pdacl;
4423	const ACL *psacl;
4424	const SID *powner;
4425	const SID *pgroup;
4426	int offdacl;
4427	int offsacl;
4428	int offowner;
4429	int offgroup;
4430	unsigned int size;
4431	le16 control;
4432	char *target;
4433	int pos;
4434	int oldattrsz;
4435	int newattrsz;
4436	BOOL ok;
4437
4438	ok = FALSE; /* default return */
4439	oldhead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
4440	newhead = (const SECURITY_DESCRIPTOR_RELATIVE*)newattr;
4441	oldattrsz = ntfs_attr_size(oldattr);
4442	newattrsz = ntfs_attr_size(newattr);
4443	target = (char*)ntfs_malloc(oldattrsz + newattrsz);
4444	if (target) {
4445		targhead = (SECURITY_DESCRIPTOR_RELATIVE*)target;
4446		pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4447		control = SE_SELF_RELATIVE;
4448			/*
4449			 * copy new DACL if selected
4450			 * or keep old DACL if any
4451			 */
4452		if ((selection & DACL_SECURITY_INFORMATION) ?
4453				newhead->dacl : oldhead->dacl) {
4454			if (selection & DACL_SECURITY_INFORMATION) {
4455				offdacl = le32_to_cpu(newhead->dacl);
4456				pdacl = (const ACL*)&newattr[offdacl];
4457			} else {
4458				offdacl = le32_to_cpu(oldhead->dacl);
4459				pdacl = (const ACL*)&oldattr[offdacl];
4460			}
4461			size = le16_to_cpu(pdacl->size);
4462			memcpy(&target[pos], pdacl, size);
4463			targhead->dacl = cpu_to_le32(pos);
4464			pos += size;
4465		} else
4466			targhead->dacl = const_cpu_to_le32(0);
4467		if (selection & DACL_SECURITY_INFORMATION) {
4468			control |= newhead->control
4469					& (SE_DACL_PRESENT
4470					   | SE_DACL_DEFAULTED
4471					   | SE_DACL_PROTECTED);
4472			if (newhead->control & SE_DACL_AUTO_INHERIT_REQ)
4473				control |= SE_DACL_AUTO_INHERITED;
4474		} else
4475			control |= oldhead->control
4476					& (SE_DACL_PRESENT
4477					   | SE_DACL_DEFAULTED
4478					   | SE_DACL_AUTO_INHERITED
4479					   | SE_DACL_PROTECTED);
4480			/*
4481			 * copy new SACL if selected
4482			 * or keep old SACL if any
4483			 */
4484		if ((selection & SACL_SECURITY_INFORMATION) ?
4485				newhead->sacl : oldhead->sacl) {
4486			if (selection & SACL_SECURITY_INFORMATION) {
4487				offsacl = le32_to_cpu(newhead->sacl);
4488				psacl = (const ACL*)&newattr[offsacl];
4489			} else {
4490				offsacl = le32_to_cpu(oldhead->sacl);
4491				psacl = (const ACL*)&oldattr[offsacl];
4492			}
4493			size = le16_to_cpu(psacl->size);
4494			memcpy(&target[pos], psacl, size);
4495			targhead->sacl = cpu_to_le32(pos);
4496			pos += size;
4497		} else
4498			targhead->sacl = const_cpu_to_le32(0);
4499		if (selection & SACL_SECURITY_INFORMATION) {
4500			control |= newhead->control
4501					& (SE_SACL_PRESENT
4502					   | SE_SACL_DEFAULTED
4503					   | SE_SACL_PROTECTED);
4504			if (newhead->control & SE_SACL_AUTO_INHERIT_REQ)
4505				control |= SE_SACL_AUTO_INHERITED;
4506		} else
4507			control |= oldhead->control
4508					& (SE_SACL_PRESENT
4509					   | SE_SACL_DEFAULTED
4510					   | SE_SACL_AUTO_INHERITED
4511					   | SE_SACL_PROTECTED);
4512			/*
4513			 * copy new OWNER if selected
4514			 * or keep old OWNER if any
4515			 */
4516		if ((selection & OWNER_SECURITY_INFORMATION) ?
4517				newhead->owner : oldhead->owner) {
4518			if (selection & OWNER_SECURITY_INFORMATION) {
4519				offowner = le32_to_cpu(newhead->owner);
4520				powner = (const SID*)&newattr[offowner];
4521			} else {
4522				offowner = le32_to_cpu(oldhead->owner);
4523				powner = (const SID*)&oldattr[offowner];
4524			}
4525			size = ntfs_sid_size(powner);
4526			memcpy(&target[pos], powner, size);
4527			targhead->owner = cpu_to_le32(pos);
4528			pos += size;
4529		} else
4530			targhead->owner = const_cpu_to_le32(0);
4531		if (selection & OWNER_SECURITY_INFORMATION)
4532			control |= newhead->control & SE_OWNER_DEFAULTED;
4533		else
4534			control |= oldhead->control & SE_OWNER_DEFAULTED;
4535			/*
4536			 * copy new GROUP if selected
4537			 * or keep old GROUP if any
4538			 */
4539		if ((selection & GROUP_SECURITY_INFORMATION) ?
4540				newhead->group : oldhead->group) {
4541			if (selection & GROUP_SECURITY_INFORMATION) {
4542				offgroup = le32_to_cpu(newhead->group);
4543				pgroup = (const SID*)&newattr[offgroup];
4544				control |= newhead->control
4545						 & SE_GROUP_DEFAULTED;
4546			} else {
4547				offgroup = le32_to_cpu(oldhead->group);
4548				pgroup = (const SID*)&oldattr[offgroup];
4549				control |= oldhead->control
4550						 & SE_GROUP_DEFAULTED;
4551			}
4552			size = ntfs_sid_size(pgroup);
4553			memcpy(&target[pos], pgroup, size);
4554			targhead->group = cpu_to_le32(pos);
4555			pos += size;
4556		} else
4557			targhead->group = const_cpu_to_le32(0);
4558		if (selection & GROUP_SECURITY_INFORMATION)
4559			control |= newhead->control & SE_GROUP_DEFAULTED;
4560		else
4561			control |= oldhead->control & SE_GROUP_DEFAULTED;
4562		targhead->revision = SECURITY_DESCRIPTOR_REVISION;
4563		targhead->alignment = 0;
4564		targhead->control = control;
4565		ok = !update_secur_descr(vol, target, ni);
4566		free(target);
4567	}
4568	return (ok);
4569}
4570
4571/*
4572 *		Return the security descriptor of a file
4573 *	This is intended to be similar to GetFileSecurity() from Win32
4574 *	in order to facilitate the development of portable tools
4575 *
4576 *	returns zero if unsuccessful (following Win32 conventions)
4577 *		-1 if no securid
4578 *		the securid if any
4579 *
4580 *  The Win32 API is :
4581 *
4582 *  BOOL WINAPI GetFileSecurity(
4583 *    __in          LPCTSTR lpFileName,
4584 *    __in          SECURITY_INFORMATION RequestedInformation,
4585 *    __out_opt     PSECURITY_DESCRIPTOR pSecurityDescriptor,
4586 *    __in          DWORD nLength,
4587 *    __out         LPDWORD lpnLengthNeeded
4588 *  );
4589 *
4590 */
4591
4592int ntfs_get_file_security(struct SECURITY_API *scapi,
4593		const char *path, u32 selection,
4594		char *buf, u32 buflen, u32 *psize)
4595{
4596	ntfs_inode *ni;
4597	char *attr;
4598	int res;
4599
4600	res = 0; /* default return */
4601	if (scapi && (scapi->magic == MAGIC_API)) {
4602		ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4603		if (ni) {
4604			attr = getsecurityattr(scapi->security.vol, ni);
4605			if (attr) {
4606				if (feedsecurityattr(attr,selection,
4607						buf,buflen,psize)) {
4608					if (test_nino_flag(ni, v3_Extensions)
4609					    && ni->security_id)
4610						res = le32_to_cpu(
4611							ni->security_id);
4612					else
4613						res = -1;
4614				}
4615				free(attr);
4616			}
4617			ntfs_inode_close(ni);
4618		} else
4619			errno = ENOENT;
4620		if (!res) *psize = 0;
4621	} else
4622		errno = EINVAL; /* do not clear *psize */
4623	return (res);
4624}
4625
4626
4627/*
4628 *		Set the security descriptor of a file or directory
4629 *	This is intended to be similar to SetFileSecurity() from Win32
4630 *	in order to facilitate the development of portable tools
4631 *
4632 *	returns zero if unsuccessful (following Win32 conventions)
4633 *		-1 if no securid
4634 *		the securid if any
4635 *
4636 *  The Win32 API is :
4637 *
4638 *  BOOL WINAPI SetFileSecurity(
4639 *    __in          LPCTSTR lpFileName,
4640 *    __in          SECURITY_INFORMATION SecurityInformation,
4641 *    __in          PSECURITY_DESCRIPTOR pSecurityDescriptor
4642 *  );
4643 */
4644
4645int ntfs_set_file_security(struct SECURITY_API *scapi,
4646		const char *path, u32 selection, const char *attr)
4647{
4648	const SECURITY_DESCRIPTOR_RELATIVE *phead;
4649	ntfs_inode *ni;
4650	int attrsz;
4651	BOOL missing;
4652	char *oldattr;
4653	int res;
4654
4655	res = 0; /* default return */
4656	if (scapi && (scapi->magic == MAGIC_API) && attr) {
4657		phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4658		attrsz = ntfs_attr_size(attr);
4659		/* if selected, owner and group must be present or defaulted */
4660		missing = ((selection & OWNER_SECURITY_INFORMATION)
4661				&& !phead->owner
4662				&& !(phead->control & SE_OWNER_DEFAULTED))
4663			|| ((selection & GROUP_SECURITY_INFORMATION)
4664				&& !phead->group
4665				&& !(phead->control & SE_GROUP_DEFAULTED));
4666		if (!missing
4667		    && (phead->control & SE_SELF_RELATIVE)
4668		    && ntfs_valid_descr(attr, attrsz)) {
4669			ni = ntfs_pathname_to_inode(scapi->security.vol,
4670				NULL, path);
4671			if (ni) {
4672				oldattr = getsecurityattr(scapi->security.vol,
4673						ni);
4674				if (oldattr) {
4675					if (mergesecurityattr(
4676						scapi->security.vol,
4677						oldattr, attr,
4678						selection, ni)) {
4679						if (test_nino_flag(ni,
4680							    v3_Extensions))
4681							res = le32_to_cpu(
4682							    ni->security_id);
4683						else
4684							res = -1;
4685					}
4686					free(oldattr);
4687				}
4688				ntfs_inode_close(ni);
4689			}
4690		} else
4691			errno = EINVAL;
4692	} else
4693		errno = EINVAL;
4694	return (res);
4695}
4696
4697
4698/*
4699 *		Return the attributes of a file
4700 *	This is intended to be similar to GetFileAttributes() from Win32
4701 *	in order to facilitate the development of portable tools
4702 *
4703 *	returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES)
4704 *
4705 *  The Win32 API is :
4706 *
4707 *  DWORD WINAPI GetFileAttributes(
4708 *   __in  LPCTSTR lpFileName
4709 *  );
4710 */
4711
4712int ntfs_get_file_attributes(struct SECURITY_API *scapi, const char *path)
4713{
4714	ntfs_inode *ni;
4715	s32 attrib;
4716
4717	attrib = -1; /* default return */
4718	if (scapi && (scapi->magic == MAGIC_API) && path) {
4719		ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4720		if (ni) {
4721			attrib = le32_to_cpu(ni->flags);
4722			if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
4723				attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4724			else
4725				attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4726			if (!attrib)
4727				attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
4728
4729			ntfs_inode_close(ni);
4730		} else
4731			errno = ENOENT;
4732	} else
4733		errno = EINVAL; /* do not clear *psize */
4734	return (attrib);
4735}
4736
4737
4738/*
4739 *		Set attributes to a file or directory
4740 *	This is intended to be similar to SetFileAttributes() from Win32
4741 *	in order to facilitate the development of portable tools
4742 *
4743 *	Only a few flags can be set (same list as Win32)
4744 *
4745 *	returns zero if unsuccessful (following Win32 conventions)
4746 *		nonzero if successful
4747 *
4748 *  The Win32 API is :
4749 *
4750 *  BOOL WINAPI SetFileAttributes(
4751 *    __in  LPCTSTR lpFileName,
4752 *    __in  DWORD dwFileAttributes
4753 *  );
4754 */
4755
4756BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi,
4757		const char *path, s32 attrib)
4758{
4759	ntfs_inode *ni;
4760	le32 settable;
4761	ATTR_FLAGS dirflags;
4762	int res;
4763
4764	res = 0; /* default return */
4765	if (scapi && (scapi->magic == MAGIC_API) && path) {
4766		ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4767		if (ni) {
4768			settable = FILE_ATTR_SETTABLE;
4769			if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4770				/*
4771				 * Accept changing compression for a directory
4772				 * and set index root accordingly
4773				 */
4774				settable |= FILE_ATTR_COMPRESSED;
4775				if ((ni->flags ^ cpu_to_le32(attrib))
4776				             & FILE_ATTR_COMPRESSED) {
4777					if (ni->flags & FILE_ATTR_COMPRESSED)
4778						dirflags = const_cpu_to_le16(0);
4779					else
4780						dirflags = ATTR_IS_COMPRESSED;
4781					res = ntfs_attr_set_flags(ni,
4782						AT_INDEX_ROOT,
4783					        NTFS_INDEX_I30, 4,
4784						dirflags,
4785						ATTR_COMPRESSION_MASK);
4786				}
4787			}
4788			if (!res) {
4789				ni->flags = (ni->flags & ~settable)
4790					 | (cpu_to_le32(attrib) & settable);
4791				NInoSetDirty(ni);
4792				NInoFileNameSetDirty(ni);
4793			}
4794			if (!ntfs_inode_close(ni))
4795				res = -1;
4796		} else
4797			errno = ENOENT;
4798	}
4799	return (res);
4800}
4801
4802
4803BOOL ntfs_read_directory(struct SECURITY_API *scapi,
4804		const char *path, ntfs_filldir_t callback, void *context)
4805{
4806	ntfs_inode *ni;
4807	BOOL ok;
4808	s64 pos;
4809
4810	ok = FALSE; /* default return */
4811	if (scapi && (scapi->magic == MAGIC_API) && callback) {
4812		ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4813		if (ni) {
4814			if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4815				pos = 0;
4816				ntfs_readdir(ni,&pos,context,callback);
4817				ok = !ntfs_inode_close(ni);
4818			} else {
4819				ntfs_inode_close(ni);
4820				errno = ENOTDIR;
4821			}
4822		} else
4823			errno = ENOENT;
4824	} else
4825		errno = EINVAL; /* do not clear *psize */
4826	return (ok);
4827}
4828
4829/*
4830 *		read $SDS (for auditing security data)
4831 *
4832 *	Returns the number or read bytes, or -1 if there is an error
4833 */
4834
4835int ntfs_read_sds(struct SECURITY_API *scapi,
4836		char *buf, u32 size, u32 offset)
4837{
4838	int got;
4839
4840	got = -1; /* default return */
4841	if (scapi && (scapi->magic == MAGIC_API)) {
4842		if (scapi->security.vol->secure_ni)
4843			got = ntfs_attr_data_read(scapi->security.vol->secure_ni,
4844				STREAM_SDS, 4, buf, size, offset);
4845		else
4846			errno = EOPNOTSUPP;
4847	} else
4848		errno = EINVAL;
4849	return (got);
4850}
4851
4852/*
4853 *		read $SII (for auditing security data)
4854 *
4855 *	Returns next entry, or NULL if there is an error
4856 */
4857
4858INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
4859		INDEX_ENTRY *entry)
4860{
4861	SII_INDEX_KEY key;
4862	INDEX_ENTRY *ret;
4863	BOOL found;
4864	ntfs_index_context *xsii;
4865
4866	ret = (INDEX_ENTRY*)NULL; /* default return */
4867	if (scapi && (scapi->magic == MAGIC_API)) {
4868		xsii = scapi->security.vol->secure_xsii;
4869		if (xsii) {
4870			if (!entry) {
4871				key.security_id = const_cpu_to_le32(0);
4872				found = !ntfs_index_lookup((char*)&key,
4873						sizeof(SII_INDEX_KEY), xsii);
4874				/* not supposed to find */
4875				if (!found && (errno == ENOENT))
4876					ret = xsii->entry;
4877			} else
4878				ret = ntfs_index_next(entry,xsii);
4879			if (!ret)
4880				errno = ENODATA;
4881		} else
4882			errno = EOPNOTSUPP;
4883	} else
4884		errno = EINVAL;
4885	return (ret);
4886}
4887
4888/*
4889 *		read $SDH (for auditing security data)
4890 *
4891 *	Returns next entry, or NULL if there is an error
4892 */
4893
4894INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
4895		INDEX_ENTRY *entry)
4896{
4897	SDH_INDEX_KEY key;
4898	INDEX_ENTRY *ret;
4899	BOOL found;
4900	ntfs_index_context *xsdh;
4901
4902	ret = (INDEX_ENTRY*)NULL; /* default return */
4903	if (scapi && (scapi->magic == MAGIC_API)) {
4904		xsdh = scapi->security.vol->secure_xsdh;
4905		if (xsdh) {
4906			if (!entry) {
4907				key.hash = const_cpu_to_le32(0);
4908				key.security_id = const_cpu_to_le32(0);
4909				found = !ntfs_index_lookup((char*)&key,
4910						sizeof(SDH_INDEX_KEY), xsdh);
4911				/* not supposed to find */
4912				if (!found && (errno == ENOENT))
4913					ret = xsdh->entry;
4914			} else
4915				ret = ntfs_index_next(entry,xsdh);
4916			if (!ret)
4917				errno = ENODATA;
4918		} else errno = ENOTSUP;
4919	} else
4920		errno = EINVAL;
4921	return (ret);
4922}
4923
4924/*
4925 *		Get the mapped user SID
4926 *	A buffer of 40 bytes has to be supplied
4927 *
4928 *	returns the size of the SID, or zero and errno set if not found
4929 */
4930
4931int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf)
4932{
4933	const SID *usid;
4934	BIGSID defusid;
4935	int size;
4936
4937	size = 0;
4938	if (scapi && (scapi->magic == MAGIC_API)) {
4939		usid = ntfs_find_usid(scapi->security.mapping[MAPUSERS], uid, (SID*)&defusid);
4940		if (usid) {
4941			size = ntfs_sid_size(usid);
4942			memcpy(buf,usid,size);
4943		} else
4944			errno = ENODATA;
4945	} else
4946		errno = EINVAL;
4947	return (size);
4948}
4949
4950/*
4951 *		Get the mapped group SID
4952 *	A buffer of 40 bytes has to be supplied
4953 *
4954 *	returns the size of the SID, or zero and errno set if not found
4955 */
4956
4957int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf)
4958{
4959	const SID *gsid;
4960	BIGSID defgsid;
4961	int size;
4962
4963	size = 0;
4964	if (scapi && (scapi->magic == MAGIC_API)) {
4965		gsid = ntfs_find_gsid(scapi->security.mapping[MAPGROUPS], gid, (SID*)&defgsid);
4966		if (gsid) {
4967			size = ntfs_sid_size(gsid);
4968			memcpy(buf,gsid,size);
4969		} else
4970			errno = ENODATA;
4971	} else
4972		errno = EINVAL;
4973	return (size);
4974}
4975
4976/*
4977 *		Get the user mapped to a SID
4978 *
4979 *	returns the uid, or -1 if not found
4980 */
4981
4982int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid)
4983{
4984	int uid;
4985
4986	uid = -1;
4987	if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(usid)) {
4988		if (ntfs_same_sid(usid,adminsid))
4989			uid = 0;
4990		else {
4991			uid = ntfs_find_user(scapi->security.mapping[MAPUSERS], usid);
4992			if (!uid) {
4993				uid = -1;
4994				errno = ENODATA;
4995			}
4996		}
4997	} else
4998		errno = EINVAL;
4999	return (uid);
5000}
5001
5002/*
5003 *		Get the group mapped to a SID
5004 *
5005 *	returns the uid, or -1 if not found
5006 */
5007
5008int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid)
5009{
5010	int gid;
5011
5012	gid = -1;
5013	if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(gsid)) {
5014		if (ntfs_same_sid(gsid,adminsid))
5015			gid = 0;
5016		else {
5017			gid = ntfs_find_group(scapi->security.mapping[MAPGROUPS], gsid);
5018			if (!gid) {
5019				gid = -1;
5020				errno = ENODATA;
5021			}
5022		}
5023	} else
5024		errno = EINVAL;
5025	return (gid);
5026}
5027
5028/*
5029 *		Initializations before calling ntfs_get_file_security()
5030 *	ntfs_set_file_security() and ntfs_read_directory()
5031 *
5032 *	Only allowed for root
5033 *
5034 *	Returns an (obscured) struct SECURITY_API* needed for further calls
5035 *		NULL if not root (EPERM) or device is mounted (EBUSY)
5036 */
5037
5038struct SECURITY_API *ntfs_initialize_file_security(const char *device,
5039				unsigned long flags)
5040{
5041	ntfs_volume *vol;
5042	unsigned long mntflag;
5043	int mnt;
5044	struct SECURITY_API *scapi;
5045	struct SECURITY_CONTEXT *scx;
5046
5047	scapi = (struct SECURITY_API*)NULL;
5048	mnt = ntfs_check_if_mounted(device, &mntflag);
5049	if (!mnt && !(mntflag & NTFS_MF_MOUNTED) && !getuid()) {
5050		vol = ntfs_mount(device, flags);
5051		if (vol) {
5052			scapi = (struct SECURITY_API*)
5053				ntfs_malloc(sizeof(struct SECURITY_API));
5054			if (!ntfs_volume_get_free_space(vol)
5055			    && scapi) {
5056				scapi->magic = MAGIC_API;
5057				scapi->seccache = (struct PERMISSIONS_CACHE*)NULL;
5058				scx = &scapi->security;
5059				scx->vol = vol;
5060				scx->uid = getuid();
5061				scx->gid = getgid();
5062				scx->pseccache = &scapi->seccache;
5063				scx->vol->secure_flags = 0;
5064					/* accept no mapping and no $Secure */
5065				ntfs_build_mapping(scx,(const char*)NULL,TRUE);
5066				ntfs_open_secure(vol);
5067			} else {
5068				if (scapi)
5069					free(scapi);
5070				else
5071					errno = ENOMEM;
5072				mnt = ntfs_umount(vol,FALSE);
5073				scapi = (struct SECURITY_API*)NULL;
5074			}
5075		}
5076	} else
5077		if (getuid())
5078			errno = EPERM;
5079		else
5080			errno = EBUSY;
5081	return (scapi);
5082}
5083
5084/*
5085 *		Leaving after ntfs_initialize_file_security()
5086 *
5087 *	Returns FALSE if FAILED
5088 */
5089
5090BOOL ntfs_leave_file_security(struct SECURITY_API *scapi)
5091{
5092	int ok;
5093	ntfs_volume *vol;
5094
5095	ok = FALSE;
5096	if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) {
5097		vol = scapi->security.vol;
5098		ntfs_close_secure(&scapi->security);
5099		free(scapi);
5100 		if (!ntfs_umount(vol, 0))
5101			ok = TRUE;
5102	}
5103	return (ok);
5104}
5105
5106