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