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