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