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