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