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