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