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