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