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