NTFS apply fixes
[wimlib] / src / ntfs-3g_security.c
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-2010 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 #include "util.h"
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35 #ifdef HAVE_STRING_H
36 #include <string.h>
37 #endif
38 #include <errno.h>
39 #include <fcntl.h>
40 #ifdef HAVE_SETXATTR
41 #include <sys/xattr.h>
42 #endif
43 #ifdef HAVE_SYS_STAT_H
44 #include <sys/stat.h>
45 #endif
46
47 #include <stdarg.h>
48
49 #include <unistd.h>
50 #include <pwd.h>
51 #include <grp.h>
52
53 #include <ntfs-3g/param.h>
54 #include <ntfs-3g/types.h>
55 #include <ntfs-3g/layout.h>
56 #include <ntfs-3g/attrib.h>
57 #include <ntfs-3g/index.h>
58 #include <ntfs-3g/dir.h>
59 #include <ntfs-3g/bitmap.h>
60 #include <ntfs-3g/security.h>
61 #include <ntfs-3g/acls.h>
62 #include <ntfs-3g/cache.h>
63 #include <ntfs-3g/misc.h>
64
65 /*
66  *      JPA NTFS constants or structs
67  *      should be moved to layout.h
68  */
69
70 #define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */
71 #define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */
72 #define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */
73 #define FIRST_SECURITY_ID 0x100 /* Lowest security id */
74
75         /* Mask for attributes which can be forced */
76 #define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY         \
77                                 | FILE_ATTR_HIDDEN      \
78                                 | FILE_ATTR_SYSTEM      \
79                                 | FILE_ATTR_ARCHIVE     \
80                                 | FILE_ATTR_TEMPORARY   \
81                                 | FILE_ATTR_OFFLINE     \
82                                 | FILE_ATTR_NOT_CONTENT_INDEXED )
83
84 struct SII {            /* this is an image of an $SII index entry */
85         le16 offs;
86         le16 size;
87         le32 fill1;
88         le16 indexsz;
89         le16 indexksz;
90         le16 flags;
91         le16 fill2;
92         le32 keysecurid;
93
94         /* did not find official description for the following */
95         le32 hash;
96         le32 securid;
97         le32 dataoffsl; /* documented as badly aligned */
98         le32 dataoffsh;
99         le32 datasize;
100 } ;
101
102 struct SDH {            /* this is an image of an $SDH index entry */
103         le16 offs;
104         le16 size;
105         le32 fill1;
106         le16 indexsz;
107         le16 indexksz;
108         le16 flags;
109         le16 fill2;
110         le32 keyhash;
111         le32 keysecurid;
112
113         /* did not find official description for the following */
114         le32 hash;
115         le32 securid;
116         le32 dataoffsl;
117         le32 dataoffsh;
118         le32 datasize;
119         le32 fill3;
120         } ;
121
122 /*
123  *      A few useful constants
124  */
125
126 static ntfschar sii_stream[] = { const_cpu_to_le16('$'),
127                                  const_cpu_to_le16('S'),
128                                  const_cpu_to_le16('I'),   
129                                  const_cpu_to_le16('I'),   
130                                  const_cpu_to_le16(0) };
131 static ntfschar sdh_stream[] = { const_cpu_to_le16('$'),
132                                  const_cpu_to_le16('S'),
133                                  const_cpu_to_le16('D'),
134                                  const_cpu_to_le16('H'),
135                                  const_cpu_to_le16(0) };
136
137 /*
138  *              null SID (S-1-0-0)
139  */
140
141 extern const SID *nullsid;
142
143 /*
144  * The zero GUID.
145  */
146
147 static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
148                 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
149 static const GUID *const zero_guid = &__zero_guid;
150
151 /**
152  * ntfs_guid_is_zero - check if a GUID is zero
153  * @guid:       [IN] guid to check
154  *
155  * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
156  * and FALSE otherwise.
157  */
158 BOOL ntfs_guid_is_zero(const GUID *guid)
159 {
160         return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
161 }
162
163 /**
164  * ntfs_guid_to_mbs - convert a GUID to a multi byte string
165  * @guid:       [IN]  guid to convert
166  * @guid_str:   [OUT] string in which to return the GUID (optional)
167  *
168  * Convert the GUID pointed to by @guid to a multi byte string of the form
169  * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".  Therefore, @guid_str (if not NULL)
170  * needs to be able to store at least 37 bytes.
171  *
172  * If @guid_str is not NULL it will contain the converted GUID on return.  If
173  * it is NULL a string will be allocated and this will be returned.  The caller
174  * is responsible for free()ing the string in that case.
175  *
176  * On success return the converted string and on failure return NULL with errno
177  * set to the error code.
178  */
179 char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
180 {
181         char *_guid_str;
182         int res;
183
184         if (!guid) {
185                 errno = EINVAL;
186                 return NULL;
187         }
188         _guid_str = guid_str;
189         if (!_guid_str) {
190                 _guid_str = (char*)ntfs_malloc(37);
191                 if (!_guid_str)
192                         return _guid_str;
193         }
194         res = snprintf(_guid_str, 37,
195                         "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
196                         (unsigned int)le32_to_cpu(guid->data1),
197                         le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
198                         guid->data4[0], guid->data4[1],
199                         guid->data4[2], guid->data4[3], guid->data4[4],
200                         guid->data4[5], guid->data4[6], guid->data4[7]);
201         if (res == 36)
202                 return _guid_str;
203         if (!guid_str)
204                 free(_guid_str);
205         errno = EINVAL;
206         return NULL;
207 }
208
209 /**
210  * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
211  * @sid:        [IN]  SID for which to determine the maximum string size
212  *
213  * Determine the maximum multi byte string size in bytes which is needed to
214  * store the standard textual representation of the SID pointed to by @sid.
215  * See ntfs_sid_to_mbs(), below.
216  *
217  * On success return the maximum number of bytes needed to store the multi byte
218  * string and on failure return -1 with errno set to the error code.
219  */
220 int ntfs_sid_to_mbs_size(const SID *sid)
221 {
222         int size, i;
223
224         if (!ntfs_sid_is_valid(sid)) {
225                 errno = EINVAL;
226                 return -1;
227         }
228         /* Start with "S-". */
229         size = 2;
230         /*
231          * Add the SID_REVISION.  Hopefully the compiler will optimize this
232          * away as SID_REVISION is a constant.
233          */
234         for (i = SID_REVISION; i > 0; i /= 10)
235                 size++;
236         /* Add the "-". */
237         size++;
238         /*
239          * Add the identifier authority.  If it needs to be in decimal, the
240          * maximum is 2^32-1 = 4294967295 = 10 characters.  If it needs to be
241          * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
242          */
243         if (!sid->identifier_authority.high_part)
244                 size += 10;
245         else
246                 size += 14;
247         /*
248          * Finally, add the sub authorities.  For each we have a "-" followed
249          * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
250          */
251         size += (1 + 10) * sid->sub_authority_count;
252         /* We need the zero byte at the end, too. */
253         size++;
254         return size * sizeof(char);
255 }
256
257 /**
258  * ntfs_sid_to_mbs - convert a SID to a multi byte string
259  * @sid:                [IN]  SID to convert
260  * @sid_str:            [OUT] string in which to return the SID (optional)
261  * @sid_str_size:       [IN]  size in bytes of @sid_str
262  *
263  * Convert the SID pointed to by @sid to its standard textual representation.
264  * @sid_str (if not NULL) needs to be able to store at least
265  * ntfs_sid_to_mbs_size() bytes.  @sid_str_size is the size in bytes of
266  * @sid_str if @sid_str is not NULL.
267  *
268  * The standard textual representation of the SID is of the form:
269  *      S-R-I-S-S...
270  * Where:
271  *    - The first "S" is the literal character 'S' identifying the following
272  *      digits as a SID.
273  *    - R is the revision level of the SID expressed as a sequence of digits
274  *      in decimal.
275  *    - I is the 48-bit identifier_authority, expressed as digits in decimal,
276  *      if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
277  *    - S... is one or more sub_authority values, expressed as digits in
278  *      decimal.
279  *
280  * If @sid_str is not NULL it will contain the converted SUID on return.  If it
281  * is NULL a string will be allocated and this will be returned.  The caller is
282  * responsible for free()ing the string in that case.
283  *
284  * On success return the converted string and on failure return NULL with errno
285  * set to the error code.
286  */
287 char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
288 {
289         u64 u;
290         le32 leauth;
291         char *s;
292         int i, j, cnt;
293
294         /*
295          * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
296          * check @sid, too.  8 is the minimum SID string size.
297          */
298         if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
299                 errno = EINVAL;
300                 return NULL;
301         }
302         /* Allocate string if not provided. */
303         if (!sid_str) {
304                 cnt = ntfs_sid_to_mbs_size(sid);
305                 if (cnt < 0)
306                         return NULL;
307                 s = (char*)ntfs_malloc(cnt);
308                 if (!s)
309                         return s;
310                 sid_str = s;
311                 /* So we know we allocated it. */
312                 sid_str_size = 0;
313         } else {
314                 s = sid_str;
315                 cnt = sid_str_size;
316         }
317         /* Start with "S-R-". */
318         i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
319         if (i < 0 || i >= cnt)
320                 goto err_out;
321         s += i;
322         cnt -= i;
323         /* Add the identifier authority. */
324         for (u = i = 0, j = 40; i < 6; i++, j -= 8)
325                 u += (u64)sid->identifier_authority.value[i] << j;
326         if (!sid->identifier_authority.high_part)
327                 i = snprintf(s, cnt, "%lu", (unsigned long)u);
328         else
329                 i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
330         if (i < 0 || i >= cnt)
331                 goto err_out;
332         s += i;
333         cnt -= i;
334         /* Finally, add the sub authorities. */
335         for (j = 0; j < sid->sub_authority_count; j++) {
336                 leauth = sid->sub_authority[j];
337                 i = snprintf(s, cnt, "-%u", (unsigned int)
338                                 le32_to_cpu(leauth));
339                 if (i < 0 || i >= cnt)
340                         goto err_out;
341                 s += i;
342                 cnt -= i;
343         }
344         return sid_str;
345 err_out:
346         if (i >= cnt)
347                 i = EMSGSIZE;
348         else
349                 i = errno;
350         if (!sid_str_size)
351                 free(sid_str);
352         errno = i;
353         return NULL;
354 }
355
356 /**
357  * ntfs_generate_guid - generatates a random current guid.
358  * @guid:       [OUT]   pointer to a GUID struct to hold the generated guid.
359  *
360  * perhaps not a very good random number generator though...
361  */
362 void ntfs_generate_guid(GUID *guid)
363 {
364         unsigned int i;
365         u8 *p = (u8 *)guid;
366
367         for (i = 0; i < sizeof(GUID); i++) {
368                 p[i] = (u8)(random() & 0xFF);
369                 if (i == 7)
370                         p[7] = (p[7] & 0x0F) | 0x40;
371                 if (i == 8)
372                         p[8] = (p[8] & 0x3F) | 0x80;
373         }
374 }
375
376 /**
377  * ntfs_security_hash - calculate the hash of a security descriptor
378  * @sd:         self-relative security descriptor whose hash to calculate
379  * @length:     size in bytes of the security descritor @sd
380  *
381  * Calculate the hash of the self-relative security descriptor @sd of length
382  * @length bytes.
383  *
384  * This hash is used in the $Secure system file as the primary key for the $SDH
385  * index and is also stored in the header of each security descriptor in the
386  * $SDS data stream as well as in the index data of both the $SII and $SDH
387  * indexes.  In all three cases it forms part of the SDS_ENTRY_HEADER
388  * structure.
389  *
390  * Return the calculated security hash in little endian.
391  */
392 le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len)
393 {
394         const le32 *pos = (const le32*)sd;
395         const le32 *end = pos + (len >> 2);
396         u32 hash = 0;
397
398         while (pos < end) {
399                 hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3);
400                 pos++;
401         }
402         return cpu_to_le32(hash);
403 }
404
405 /*
406  *      Get the first entry of current index block
407  *      cut and pasted form ntfs_ie_get_first() in index.c
408  */
409
410 static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih)
411 {
412         return (INDEX_ENTRY*)((u8*)ih + le32_to_cpu(ih->entries_offset));
413 }
414
415 /*
416  *              Stuff a 256KB block into $SDS before writing descriptors
417  *      into the block.
418  *
419  *      This prevents $SDS from being automatically declared as sparse
420  *      when the second copy of the first security descriptor is written
421  *      256KB further ahead.
422  *
423  *      Having $SDS declared as a sparse file is not wrong by itself
424  *      and chkdsk leaves it as a sparse file. It does however complain
425  *      and add a sparse flag (0x0200) into field file_attributes of
426  *      STANDARD_INFORMATION of $Secure. This probably means that a
427  *      sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse
428  *      files (FILE_ATTR_SPARSE_FILE).
429  *
430  *      Windows normally does not convert to sparse attribute or sparse
431  *      file. Stuffing is just a way to get to the same result.
432  */
433
434 static int entersecurity_stuff(ntfs_volume *vol, off_t offs)
435 {
436         int res;
437         int written;
438         unsigned long total;
439         char *stuff;
440
441         res = 0;
442         total = 0;
443         stuff = (char*)ntfs_malloc(STUFFSZ);
444         if (stuff) {
445                 memset(stuff, 0, STUFFSZ);
446                 do {
447                         written = ntfs_attr_data_write(vol->secure_ni,
448                                 STREAM_SDS, 4, stuff, STUFFSZ, offs);
449                         if (written == STUFFSZ) {
450                                 total += STUFFSZ;
451                                 offs += STUFFSZ;
452                         } else {
453                                 errno = ENOSPC;
454                                 res = -1;
455                         }
456                 } while (!res && (total < ALIGN_SDS_BLOCK));
457                 free(stuff);
458         } else {
459                 errno = ENOMEM;
460                 res = -1;
461         }
462         return (res);
463 }
464
465 /*
466  *              Enter a new security descriptor into $Secure (data only)
467  *      it has to be written twice with an offset of 256KB
468  *
469  *      Should only be called by entersecurityattr() to ensure consistency
470  *
471  *      Returns zero if sucessful
472  */
473
474 static int entersecurity_data(ntfs_volume *vol,
475                         const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
476                         le32 hash, le32 keyid, off_t offs, int gap)
477 {
478         int res;
479         int written1;
480         int written2;
481         char *fullattr;
482         int fullsz;
483         SECURITY_DESCRIPTOR_HEADER *phsds;
484
485         res = -1;
486         fullsz = attrsz + gap + sizeof(SECURITY_DESCRIPTOR_HEADER);
487         fullattr = (char*)ntfs_malloc(fullsz);
488         if (fullattr) {
489                         /*
490                          * Clear the gap from previous descriptor
491                          * this could be useful for appending the second
492                          * copy to the end of file. When creating a new
493                          * 256K block, the gap is cleared while writing
494                          * the first copy
495                          */
496                 if (gap)
497                         memset(fullattr,0,gap);
498                 memcpy(&fullattr[gap + sizeof(SECURITY_DESCRIPTOR_HEADER)],
499                                 attr,attrsz);
500                 phsds = (SECURITY_DESCRIPTOR_HEADER*)&fullattr[gap];
501                 phsds->hash = hash;
502                 phsds->security_id = keyid;
503                 phsds->offset = cpu_to_le64(offs);
504                 phsds->length = cpu_to_le32(fullsz - gap);
505                 written1 = ntfs_attr_data_write(vol->secure_ni,
506                         STREAM_SDS, 4, fullattr, fullsz,
507                         offs - gap);
508                 written2 = ntfs_attr_data_write(vol->secure_ni,
509                         STREAM_SDS, 4, fullattr, fullsz,
510                         offs - gap + ALIGN_SDS_BLOCK);
511                 if ((written1 == fullsz)
512                      && (written2 == written1))
513                         res = 0;
514                 else
515                         errno = ENOSPC;
516                 free(fullattr);
517         } else
518                 errno = ENOMEM;
519         return (res);
520 }
521
522 /*
523  *      Enter a new security descriptor in $Secure (indexes only)
524  *
525  *      Should only be called by entersecurityattr() to ensure consistency
526  *
527  *      Returns zero if sucessful
528  */
529
530 static int entersecurity_indexes(ntfs_volume *vol, s64 attrsz,
531                         le32 hash, le32 keyid, off_t offs)
532 {
533         union {
534                 struct {
535                         le32 dataoffsl;
536                         le32 dataoffsh;
537                 } parts;
538                 le64 all;
539         } realign;
540         int res;
541         ntfs_index_context *xsii;
542         ntfs_index_context *xsdh;
543         struct SII newsii;
544         struct SDH newsdh;
545
546         res = -1;
547                                 /* enter a new $SII record */
548
549         xsii = vol->secure_xsii;
550         ntfs_index_ctx_reinit(xsii);
551         newsii.offs = const_cpu_to_le16(20);
552         newsii.size = const_cpu_to_le16(sizeof(struct SII) - 20);
553         newsii.fill1 = const_cpu_to_le32(0);
554         newsii.indexsz = const_cpu_to_le16(sizeof(struct SII));
555         newsii.indexksz = const_cpu_to_le16(sizeof(SII_INDEX_KEY));
556         newsii.flags = const_cpu_to_le16(0);
557         newsii.fill2 = const_cpu_to_le16(0);
558         newsii.keysecurid = keyid;
559         newsii.hash = hash;
560         newsii.securid = keyid;
561         realign.all = cpu_to_le64(offs);
562         newsii.dataoffsh = realign.parts.dataoffsh;
563         newsii.dataoffsl = realign.parts.dataoffsl;
564         newsii.datasize = cpu_to_le32(attrsz
565                          + sizeof(SECURITY_DESCRIPTOR_HEADER));
566         if (!ntfs_ie_add(xsii,(INDEX_ENTRY*)&newsii)) {
567
568                 /* enter a new $SDH record */
569
570                 xsdh = vol->secure_xsdh;
571                 ntfs_index_ctx_reinit(xsdh);
572                 newsdh.offs = const_cpu_to_le16(24);
573                 newsdh.size = const_cpu_to_le16(
574                         sizeof(SECURITY_DESCRIPTOR_HEADER));
575                 newsdh.fill1 = const_cpu_to_le32(0);
576                 newsdh.indexsz = const_cpu_to_le16(
577                                 sizeof(struct SDH));
578                 newsdh.indexksz = const_cpu_to_le16(
579                                 sizeof(SDH_INDEX_KEY));
580                 newsdh.flags = const_cpu_to_le16(0);
581                 newsdh.fill2 = const_cpu_to_le16(0);
582                 newsdh.keyhash = hash;
583                 newsdh.keysecurid = keyid;
584                 newsdh.hash = hash;
585                 newsdh.securid = keyid;
586                 newsdh.dataoffsh = realign.parts.dataoffsh;
587                 newsdh.dataoffsl = realign.parts.dataoffsl;
588                 newsdh.datasize = cpu_to_le32(attrsz
589                          + sizeof(SECURITY_DESCRIPTOR_HEADER));
590                            /* special filler value, Windows generally */
591                            /* fills with 0x00490049, sometimes with zero */
592                 newsdh.fill3 = const_cpu_to_le32(0x00490049);
593                 if (!ntfs_ie_add(xsdh,(INDEX_ENTRY*)&newsdh))
594                         res = 0;
595         }
596         return (res);
597 }
598
599 /*
600  *      Enter a new security descriptor in $Secure (data and indexes)
601  *      Returns id of entry, or zero if there is a problem.
602  *      (should not be called for NTFS version < 3.0)
603  *
604  *      important : calls have to be serialized, however no locking is
605  *      needed while fuse is not multithreaded
606  */
607
608 static le32 entersecurityattr(ntfs_volume *vol,
609                         const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
610                         le32 hash)
611 {
612         union {
613                 struct {
614                         le32 dataoffsl;
615                         le32 dataoffsh;
616                 } parts;
617                 le64 all;
618         } realign;
619         le32 securid;
620         le32 keyid;
621         u32 newkey;
622         off_t offs;
623         int gap;
624         int size;
625         BOOL found;
626         struct SII *psii;
627         INDEX_ENTRY *entry;
628         INDEX_ENTRY *next;
629         ntfs_index_context *xsii;
630         int retries;
631         ntfs_attr *na;
632         int olderrno;
633
634         /* find the first available securid beyond the last key */
635         /* in $Secure:$SII. This also determines the first */
636         /* available location in $Secure:$SDS, as this stream */
637         /* is always appended to and the id's are allocated */
638         /* in sequence */
639
640         securid = const_cpu_to_le32(0);
641         xsii = vol->secure_xsii;
642         ntfs_index_ctx_reinit(xsii);
643         offs = size = 0;
644         keyid = const_cpu_to_le32(-1);
645         olderrno = errno;
646         found = !ntfs_index_lookup((char*)&keyid,
647                                sizeof(SII_INDEX_KEY), xsii);
648         if (!found && (errno != ENOENT)) {
649                 ntfs_log_perror("Inconsistency in index $SII");
650                 psii = (struct SII*)NULL;
651         } else {
652                         /* restore errno to avoid misinterpretation */
653                 errno = olderrno;
654                 entry = xsii->entry;
655                 psii = (struct SII*)xsii->entry;
656         }
657         if (psii) {
658                 /*
659                  * Get last entry in block, but must get first one
660                  * one first, as we should already be beyond the
661                  * last one. For some reason the search for the last
662                  * entry sometimes does not return the last block...
663                  * we assume this can only happen in root block
664                  */
665                 if (xsii->is_in_root)
666                         entry = ntfs_ie_get_first
667                                 ((INDEX_HEADER*)&xsii->ir->index);
668                 else
669                         entry = ntfs_ie_get_first
670                                 ((INDEX_HEADER*)&xsii->ib->index);
671                 /*
672                  * All index blocks should be at least half full
673                  * so there always is a last entry but one,
674                  * except when creating the first entry in index root.
675                  * This was however found not to be true : chkdsk
676                  * sometimes deletes all the (unused) keys in the last
677                  * index block without rebalancing the tree.
678                  * When this happens, a new search is restarted from
679                  * the smallest key.
680                  */
681                 keyid = const_cpu_to_le32(0);
682                 retries = 0;
683                 while (entry) {
684                         next = ntfs_index_next(entry,xsii);
685                         if (next) { 
686                                 psii = (struct SII*)next;
687                                         /* save last key and */
688                                         /* available position */
689                                 keyid = psii->keysecurid;
690                                 realign.parts.dataoffsh
691                                                  = psii->dataoffsh;
692                                 realign.parts.dataoffsl
693                                                  = psii->dataoffsl;
694                                 offs = le64_to_cpu(realign.all);
695                                 size = le32_to_cpu(psii->datasize);
696                         }
697                         entry = next;
698                         if (!entry && !keyid && !retries) {
699                                 /* search failed, retry from smallest key */
700                                 ntfs_index_ctx_reinit(xsii);
701                                 found = !ntfs_index_lookup((char*)&keyid,
702                                                sizeof(SII_INDEX_KEY), xsii);
703                                 if (!found && (errno != ENOENT)) {
704                                         ntfs_log_perror("Index $SII is broken");
705                                 } else {
706                                                 /* restore errno */
707                                         errno = olderrno;
708                                         entry = xsii->entry;
709                                 }
710                                 retries++;
711                         }
712                 }
713         }
714         if (!keyid) {
715                 /*
716                  * could not find any entry, before creating the first
717                  * entry, make a double check by making sure size of $SII
718                  * is less than needed for one entry
719                  */
720                 securid = const_cpu_to_le32(0);
721                 na = ntfs_attr_open(vol->secure_ni,AT_INDEX_ROOT,sii_stream,4);
722                 if (na) {
723                         if ((size_t)na->data_size < sizeof(struct SII)) {
724                                 ntfs_log_error("Creating the first security_id\n");
725                                 securid = const_cpu_to_le32(FIRST_SECURITY_ID);
726                         }
727                         ntfs_attr_close(na);
728                 }
729                 if (!securid) {
730                         ntfs_log_error("Error creating a security_id\n");
731                         errno = EIO;
732                 }
733         } else {
734                 newkey = le32_to_cpu(keyid) + 1;
735                 securid = cpu_to_le32(newkey);
736         }
737         /*
738          * The security attr has to be written twice 256KB
739          * apart. This implies that offsets like
740          * 0x40000*odd_integer must be left available for
741          * the second copy. So align to next block when
742          * the last byte overflows on a wrong block.
743          */
744
745         if (securid) {
746                 gap = (-size) & (ALIGN_SDS_ENTRY - 1);
747                 offs += gap + size;
748                 if ((offs + attrsz + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
749                    & ALIGN_SDS_BLOCK) {
750                         offs = ((offs + attrsz
751                                  + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
752                                 | (ALIGN_SDS_BLOCK - 1)) + 1;
753                 }
754                 if (!(offs & (ALIGN_SDS_BLOCK - 1)))
755                         entersecurity_stuff(vol, offs);
756                 /*
757                  * now write the security attr to storage :
758                  * first data, then SII, then SDH
759                  * If failure occurs while writing SDS, data will never
760                  *    be accessed through indexes, and will be overwritten
761                  *    by the next allocated descriptor
762                  * If failure occurs while writing SII, the id has not
763                  *    recorded and will be reallocated later
764                  * If failure occurs while writing SDH, the space allocated
765                  *    in SDS or SII will not be reused, an inconsistency
766                  *    will persist with no significant consequence
767                  */
768                 if (entersecurity_data(vol, attr, attrsz, hash, securid, offs, gap)
769                     || entersecurity_indexes(vol, attrsz, hash, securid, offs))
770                         securid = const_cpu_to_le32(0);
771         }
772                 /* inode now is dirty, synchronize it all */
773         ntfs_index_entry_mark_dirty(vol->secure_xsii);
774         ntfs_index_ctx_reinit(vol->secure_xsii);
775         ntfs_index_entry_mark_dirty(vol->secure_xsdh);
776         ntfs_index_ctx_reinit(vol->secure_xsdh);
777         NInoSetDirty(vol->secure_ni);
778         if (ntfs_inode_sync(vol->secure_ni))
779                 ntfs_log_perror("Could not sync $Secure\n");
780         return (securid);
781 }
782
783 /*
784  *              Find a matching security descriptor in $Secure,
785  *      if none, allocate a new id and write the descriptor to storage
786  *      Returns id of entry, or zero if there is a problem.
787  *
788  *      important : calls have to be serialized, however no locking is
789  *      needed while fuse is not multithreaded
790  */
791
792 static le32 setsecurityattr(ntfs_volume *vol,
793                         const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz)
794 {
795         struct SDH *psdh;       /* this is an image of index (le) */
796         union {
797                 struct {
798                         le32 dataoffsl;
799                         le32 dataoffsh;
800                 } parts;
801                 le64 all;
802         } realign;
803         BOOL found;
804         BOOL collision;
805         size_t size;
806         size_t rdsize;
807         s64 offs;
808         int res;
809         ntfs_index_context *xsdh;
810         char *oldattr;
811         SDH_INDEX_KEY key;
812         INDEX_ENTRY *entry;
813         le32 securid;
814         le32 hash;
815         int olderrno;
816
817         hash = ntfs_security_hash(attr,attrsz);
818         oldattr = (char*)NULL;
819         securid = const_cpu_to_le32(0);
820         res = 0;
821         xsdh = vol->secure_xsdh;
822         if (vol->secure_ni && xsdh && !vol->secure_reentry++) {
823                 ntfs_index_ctx_reinit(xsdh);
824                 /*
825                  * find the nearest key as (hash,0)
826                  * (do not search for partial key : in case of collision,
827                  * it could return a key which is not the first one which
828                  * collides)
829                  */
830                 key.hash = hash;
831                 key.security_id = const_cpu_to_le32(0);
832                 olderrno = errno;
833                 found = !ntfs_index_lookup((char*)&key,
834                                  sizeof(SDH_INDEX_KEY), xsdh);
835                 if (!found && (errno != ENOENT))
836                         ntfs_log_perror("Inconsistency in index $SDH");
837                 else {
838                                 /* restore errno to avoid misinterpretation */
839                         errno = olderrno;
840                         entry = xsdh->entry;
841                         found = FALSE;
842                         /*
843                          * lookup() may return a node with no data,
844                          * if so get next
845                          */
846                         if (entry->ie_flags & INDEX_ENTRY_END)
847                                 entry = ntfs_index_next(entry,xsdh);
848                         do {
849                                 collision = FALSE;
850                                 psdh = (struct SDH*)entry;
851                                 if (psdh)
852                                         size = (size_t) le32_to_cpu(psdh->datasize)
853                                                  - sizeof(SECURITY_DESCRIPTOR_HEADER);
854                                 else size = 0;
855                            /* if hash is not the same, the key is not present */
856                                 if (psdh && (size > 0)
857                                    && (psdh->keyhash == hash)) {
858                                            /* if hash is the same */
859                                            /* check the whole record */
860                                         realign.parts.dataoffsh = psdh->dataoffsh;
861                                         realign.parts.dataoffsl = psdh->dataoffsl;
862                                         offs = le64_to_cpu(realign.all)
863                                                 + sizeof(SECURITY_DESCRIPTOR_HEADER);
864                                         oldattr = (char*)ntfs_malloc(size);
865                                         if (oldattr) {
866                                                 rdsize = ntfs_attr_data_read(
867                                                         vol->secure_ni,
868                                                         STREAM_SDS, 4,
869                                                         oldattr, size, offs);
870                                                 found = (rdsize == size)
871                                                         && !memcmp(oldattr,attr,size);
872                                                 free(oldattr);
873                                           /* if the records do not compare */
874                                           /* (hash collision), try next one */
875                                                 if (!found) {
876                                                         entry = ntfs_index_next(
877                                                                 entry,xsdh);
878                                                         collision = TRUE;
879                                                 }
880                                         } else
881                                                 res = ENOMEM;
882                                 }
883                         } while (collision && entry);
884                         if (found)
885                                 securid = psdh->keysecurid;
886                         else {
887                                 if (res) {
888                                         errno = res;
889                                         securid = const_cpu_to_le32(0);
890                                 } else {
891                                         /*
892                                          * no matching key :
893                                          * have to build a new one
894                                          */
895                                         securid = entersecurityattr(vol,
896                                                 attr, attrsz, hash);
897                                 }
898                         }
899                 }
900         }
901         if (--vol->secure_reentry)
902                 ntfs_log_perror("Reentry error, check no multithreading\n");
903         return (securid);
904 }
905
906
907 /*
908  *              Update the security descriptor of a file
909  *      Either as an attribute (complying with pre v3.x NTFS version)
910  *      or, when possible, as an entry in $Secure (for NTFS v3.x)
911  *
912  *      returns 0 if success
913  */
914
915 static int update_secur_descr(ntfs_volume *vol,
916                                 char *newattr, ntfs_inode *ni)
917 {
918         int newattrsz;
919         int written;
920         int res;
921         ntfs_attr *na;
922
923         newattrsz = ntfs_attr_size(newattr);
924
925 #if !FORCE_FORMAT_v1x
926         if ((vol->major_ver < 3) || !vol->secure_ni) {
927 #endif
928
929                 /* update for NTFS format v1.x */
930
931                 /* update the old security attribute */
932                 na = ntfs_attr_open(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0);
933                 if (na) {
934                         /* resize attribute */
935                         res = ntfs_attr_truncate(na, (s64) newattrsz);
936                         /* overwrite value */
937                         if (!res) {
938                                 written = (int)ntfs_attr_pwrite(na, (s64) 0,
939                                          (s64) newattrsz, newattr);
940                                 if (written != newattrsz) {
941                                         ntfs_log_error("Failed to update "
942                                                 "a v1.x security descriptor\n");
943                                         errno = EIO;
944                                         res = -1;
945                                 }
946                         }
947
948                         ntfs_attr_close(na);
949                         /* if old security attribute was found, also */
950                         /* truncate standard information attribute to v1.x */
951                         /* this is needed when security data is wanted */
952                         /* as v1.x though volume is formatted for v3.x */
953                         na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
954                                 AT_UNNAMED, 0);
955                         if (na) {
956                                 clear_nino_flag(ni, v3_Extensions);
957                         /*
958                          * Truncating the record does not sweep extensions
959                          * from copy in memory. Clear security_id to be safe
960                          */
961                                 ni->security_id = const_cpu_to_le32(0);
962                                 res = ntfs_attr_truncate(na, (s64)48);
963                                 ntfs_attr_close(na);
964                                 clear_nino_flag(ni, v3_Extensions);
965                         }
966                 } else {
967                         /*
968                          * insert the new security attribute if there
969                          * were none
970                          */
971                         res = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR,
972                                             AT_UNNAMED, 0, (u8*)newattr,
973                                             (s64) newattrsz);
974                 }
975 #if !FORCE_FORMAT_v1x
976         } else {
977
978                 /* update for NTFS format v3.x */
979
980                 le32 securid;
981
982                 securid = setsecurityattr(vol,
983                         (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
984                         (s64)newattrsz);
985                 if (securid) {
986                         na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
987                                 AT_UNNAMED, 0);
988                         if (na) {
989                                 res = 0;
990                                 if (!test_nino_flag(ni, v3_Extensions)) {
991                         /* expand standard information attribute to v3.x */
992                                         res = ntfs_attr_truncate(na,
993                                          (s64)sizeof(STANDARD_INFORMATION));
994                                         ni->owner_id = const_cpu_to_le32(0);
995                                         ni->quota_charged = const_cpu_to_le64(0);
996                                         ni->usn = const_cpu_to_le64(0);
997                                         ntfs_attr_remove(ni,
998                                                 AT_SECURITY_DESCRIPTOR,
999                                                 AT_UNNAMED, 0);
1000                         }
1001                                 set_nino_flag(ni, v3_Extensions);
1002                                 ni->security_id = securid;
1003                                 ntfs_attr_close(na);
1004                         } else {
1005                                 ntfs_log_error("Failed to update "
1006                                         "standard informations\n");
1007                                 errno = EIO;
1008                                 res = -1;
1009                         }
1010                 } else
1011                         res = -1;
1012         }
1013 #endif
1014
1015         /* mark node as dirty */
1016         NInoSetDirty(ni);
1017         return (res);
1018 }
1019
1020 /*
1021  *              Upgrade the security descriptor of a file
1022  *      This is intended to allow graceful upgrades for files which
1023  *      were created in previous versions, with a security attributes
1024  *      and no security id.
1025  *      
1026  *      It will allocate a security id and replace the individual
1027  *      security attribute by a reference to the global one
1028  *
1029  *      Special files are not upgraded (currently / and files in
1030  *      directories /$*)
1031  *
1032  *      Though most code is similar to update_secur_desc() it has
1033  *      been kept apart to facilitate the further processing of
1034  *      special cases or even to remove it if found dangerous.
1035  *
1036  *      returns 0 if success,
1037  *              1 if not upgradable. This is not an error.
1038  *              -1 if there is a problem
1039  */
1040
1041 static int upgrade_secur_desc(ntfs_volume *vol,
1042                                 const char *attr, ntfs_inode *ni)
1043 {
1044         int attrsz;
1045         int res;
1046         le32 securid;
1047         ntfs_attr *na;
1048
1049                 /*
1050                  * upgrade requires NTFS format v3.x
1051                  * also refuse upgrading for special files
1052                  * whose number is less than FILE_first_user
1053                  */
1054
1055         if ((vol->major_ver >= 3)
1056             && (ni->mft_no >= FILE_first_user)) {
1057                 attrsz = ntfs_attr_size(attr);
1058                 securid = setsecurityattr(vol,
1059                         (const SECURITY_DESCRIPTOR_RELATIVE*)attr,
1060                         (s64)attrsz);
1061                 if (securid) {
1062                         na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
1063                                 AT_UNNAMED, 0);
1064                         if (na) {
1065                         /* expand standard information attribute to v3.x */
1066                                 res = ntfs_attr_truncate(na,
1067                                          (s64)sizeof(STANDARD_INFORMATION));
1068                                 ni->owner_id = const_cpu_to_le32(0);
1069                                 ni->quota_charged = const_cpu_to_le64(0);
1070                                 ni->usn = const_cpu_to_le64(0);
1071                                 ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR,
1072                                                 AT_UNNAMED, 0);
1073                                 set_nino_flag(ni, v3_Extensions);
1074                                 ni->security_id = securid;
1075                                 ntfs_attr_close(na);
1076                         } else {
1077                                 ntfs_log_error("Failed to upgrade "
1078                                         "standard informations\n");
1079                                 errno = EIO;
1080                                 res = -1;
1081                         }
1082                 } else
1083                         res = -1;
1084                         /* mark node as dirty */
1085                 NInoSetDirty(ni);
1086         } else
1087                 res = 1;
1088
1089         return (res);
1090 }
1091
1092 /*
1093  *              Optional simplified checking of group membership
1094  *
1095  *      This only takes into account the groups defined in
1096  *      /etc/group at initialization time.
1097  *      It does not take into account the groups dynamically set by
1098  *      setgroups() nor the changes in /etc/group since initialization
1099  *
1100  *      This optional method could be useful if standard checking
1101  *      leads to a performance concern.
1102  *
1103  *      Should not be called for user root, however the group may be root
1104  *
1105  */
1106
1107 static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1108 {
1109         BOOL ingroup;
1110         int grcnt;
1111         gid_t *groups;
1112         struct MAPPING *user;
1113
1114         ingroup = FALSE;
1115         if (uid) {
1116                 user = scx->mapping[MAPUSERS];
1117                 while (user && ((uid_t)user->xid != uid))
1118                         user = user->next;
1119                 if (user) {
1120                         groups = user->groups;
1121                         grcnt = user->grcnt;
1122                         while ((--grcnt >= 0) && (groups[grcnt] != gid)) { }
1123                         ingroup = (grcnt >= 0);
1124                 }
1125         }
1126         return (ingroup);
1127 }
1128
1129
1130 /*
1131  *              Check whether current thread owner is member of file group
1132  *
1133  *      Should not be called for user root, however the group may be root
1134  *
1135  * As indicated by Miklos Szeredi :
1136  *
1137  * The group list is available in
1138  *
1139  *   /proc/$PID/task/$TID/status
1140  *
1141  * and fuse supplies TID in get_fuse_context()->pid.  The only problem is
1142  * finding out PID, for which I have no good solution, except to iterate
1143  * through all processes.  This is rather slow, but may be speeded up
1144  * with caching and heuristics (for single threaded programs PID = TID).
1145  *
1146  * The following implementation gets the group list from
1147  *   /proc/$TID/task/$TID/status which apparently exists and
1148  * contains the same data.
1149  */
1150
1151 static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
1152 {
1153         static char key[] = "\nGroups:";
1154         char buf[BUFSZ+1];
1155         char filename[64];
1156         enum { INKEY, INSEP, INNUM, INEND } state;
1157         int fd;
1158         char c;
1159         int matched;
1160         BOOL ismember;
1161         int got;
1162         char *p;
1163         gid_t grp;
1164         pid_t tid;
1165
1166         if (scx->vol->secure_flags & (1 << SECURITY_STATICGRPS))
1167                 ismember = staticgroupmember(scx, uid, gid);
1168         else {
1169                 ismember = FALSE; /* default return */
1170                 tid = scx->tid;
1171                 sprintf(filename,"/proc/%u/task/%u/status",tid,tid);
1172                 fd = open(filename,O_RDONLY);
1173                 if (fd >= 0) {
1174                         got = read(fd, buf, BUFSZ);
1175                         buf[got] = 0;
1176                         state = INKEY;
1177                         matched = 0;
1178                         p = buf;
1179                         grp = 0;
1180                                 /*
1181                                  *  A simple automaton to process lines like
1182                                  *  Groups: 14 500 513
1183                                  */
1184                         do {
1185                                 c = *p++;
1186                                 if (!c) {
1187                                         /* refill buffer */
1188                                         got = read(fd, buf, BUFSZ);
1189                                         buf[got] = 0;
1190                                         p = buf;
1191                                         c = *p++; /* 0 at end of file */
1192                                 }
1193                                 switch (state) {
1194                                 case INKEY :
1195                                         if (key[matched] == c) {
1196                                                 if (!key[++matched])
1197                                                         state = INSEP;
1198                                         } else
1199                                                 if (key[0] == c)
1200                                                         matched = 1;
1201                                                 else
1202                                                         matched = 0;
1203                                         break;
1204                                 case INSEP :
1205                                         if ((c >= '0') && (c <= '9')) {
1206                                                 grp = c - '0';
1207                                                 state = INNUM;
1208                                         } else
1209                                                 if ((c != ' ') && (c != '\t'))
1210                                                         state = INEND;
1211                                         break;
1212                                 case INNUM :
1213                                         if ((c >= '0') && (c <= '9'))
1214                                                 grp = grp*10 + c - '0';
1215                                         else {
1216                                                 ismember = (grp == gid);
1217                                                 if ((c != ' ') && (c != '\t'))
1218                                                         state = INEND;
1219                                                 else
1220                                                         state = INSEP;
1221                                         }
1222                                 default :
1223                                         break;
1224                                 }
1225                         } while (!ismember && c && (state != INEND));
1226                 close(fd);
1227                 if (!c)
1228                         ntfs_log_error("No group record found in %s\n",filename);
1229                 } else
1230                         ntfs_log_error("Could not open %s\n",filename);
1231         }
1232         return (ismember);
1233 }
1234
1235 /*
1236  *      Cacheing is done two-way :
1237  *      - from uid, gid and perm to securid (CACHED_SECURID)
1238  *      - from a securid to uid, gid and perm (CACHED_PERMISSIONS)
1239  *
1240  *      CACHED_SECURID data is kept in a most-recent-first list
1241  *      which should not be too long to be efficient. Its optimal
1242  *      size is depends on usage and is hard to determine.
1243  *
1244  *      CACHED_PERMISSIONS data is kept in a two-level indexed array. It
1245  *      is optimal at the expense of storage. Use of a most-recent-first
1246  *      list would save memory and provide similar performances for
1247  *      standard usage, but not for file servers with too many file
1248  *      owners
1249  *
1250  *      CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS
1251  *      for legacy directories which were not allocated a security_id
1252  *      it is organized in a most-recent-first list.
1253  *
1254  *      In main caches, data is never invalidated, as the meaning of
1255  *      a security_id only changes when user mapping is changed, which
1256  *      current implies remounting. However returned entries may be
1257  *      overwritten at next update, so data has to be copied elsewhere
1258  *      before another cache update is made.
1259  *      In legacy cache, data has to be invalidated when protection is
1260  *      changed.
1261  *
1262  *      Though the same data may be found in both list, they
1263  *      must be kept separately : the interpretation of ACL
1264  *      in both direction are approximations which could be non
1265  *      reciprocal for some configuration of the user mapping data
1266  *
1267  *      During the process of recompiling ntfs-3g from a tgz archive,
1268  *      security processing added 7.6% to the cpu time used by ntfs-3g
1269  *      and 30% if the cache is disabled.
1270  */
1271
1272 static struct PERMISSIONS_CACHE *create_caches(struct SECURITY_CONTEXT *scx,
1273                         u32 securindex)
1274 {
1275         struct PERMISSIONS_CACHE *cache;
1276         unsigned int index1;
1277         unsigned int i;
1278
1279         cache = (struct PERMISSIONS_CACHE*)NULL;
1280                 /* create the first permissions blocks */
1281         index1 = securindex >> CACHE_PERMISSIONS_BITS;
1282         cache = (struct PERMISSIONS_CACHE*)
1283                 ntfs_malloc(sizeof(struct PERMISSIONS_CACHE)
1284                       + index1*sizeof(struct CACHED_PERMISSIONS*));
1285         if (cache) {
1286                 cache->head.last = index1;
1287                 cache->head.p_reads = 0;
1288                 cache->head.p_hits = 0;
1289                 cache->head.p_writes = 0;
1290                 *scx->pseccache = cache;
1291                 for (i=0; i<=index1; i++)
1292                         cache->cachetable[i]
1293                            = (struct CACHED_PERMISSIONS*)NULL;
1294         }
1295         return (cache);
1296 }
1297
1298 /*
1299  *              Free memory used by caches
1300  *      The only purpose is to facilitate the detection of memory leaks
1301  */
1302
1303 static void free_caches(struct SECURITY_CONTEXT *scx)
1304 {
1305         unsigned int index1;
1306         struct PERMISSIONS_CACHE *pseccache;
1307
1308         pseccache = *scx->pseccache;
1309         if (pseccache) {
1310                 for (index1=0; index1<=pseccache->head.last; index1++)
1311                         if (pseccache->cachetable[index1]) {
1312 #if POSIXACLS
1313                                 struct CACHED_PERMISSIONS *cacheentry;
1314                                 unsigned int index2;
1315
1316                                 for (index2=0; index2<(1<< CACHE_PERMISSIONS_BITS); index2++) {
1317                                         cacheentry = &pseccache->cachetable[index1][index2];
1318                                         if (cacheentry->valid
1319                                             && cacheentry->pxdesc)
1320                                                 free(cacheentry->pxdesc);
1321                                         }
1322 #endif
1323                                 free(pseccache->cachetable[index1]);
1324                         }
1325                 free(pseccache);
1326         }
1327 }
1328
1329 static int compare(const struct CACHED_SECURID *cached,
1330                         const struct CACHED_SECURID *item)
1331 {
1332 #if POSIXACLS
1333         size_t csize;
1334         size_t isize;
1335
1336                 /* only compare data and sizes */
1337         csize = (cached->variable ?
1338                 sizeof(struct POSIX_ACL)
1339                 + (((struct POSIX_SECURITY*)cached->variable)->acccnt
1340                    + ((struct POSIX_SECURITY*)cached->variable)->defcnt)
1341                         *sizeof(struct POSIX_ACE) :
1342                 0);
1343         isize = (item->variable ?
1344                 sizeof(struct POSIX_ACL)
1345                 + (((struct POSIX_SECURITY*)item->variable)->acccnt
1346                    + ((struct POSIX_SECURITY*)item->variable)->defcnt)
1347                         *sizeof(struct POSIX_ACE) :
1348                 0);
1349         return ((cached->uid != item->uid)
1350                  || (cached->gid != item->gid)
1351                  || (cached->dmode != item->dmode)
1352                  || (csize != isize)
1353                  || (csize
1354                     && isize
1355                     && memcmp(&((struct POSIX_SECURITY*)cached->variable)->acl,
1356                        &((struct POSIX_SECURITY*)item->variable)->acl, csize)));
1357 #else
1358         return ((cached->uid != item->uid)
1359                  || (cached->gid != item->gid)
1360                  || (cached->dmode != item->dmode));
1361 #endif
1362 }
1363
1364 static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached,
1365                         const struct CACHED_PERMISSIONS_LEGACY *item)
1366 {
1367         return (cached->mft_no != item->mft_no);
1368 }
1369
1370 /*
1371  *      Resize permission cache table
1372  *      do not call unless resizing is needed
1373  *      
1374  *      If allocation fails, the cache size is not updated
1375  *      Lack of memory is not considered as an error, the cache is left
1376  *      consistent and errno is not set.
1377  */
1378
1379 static void resize_cache(struct SECURITY_CONTEXT *scx,
1380                         u32 securindex)
1381 {
1382         struct PERMISSIONS_CACHE *oldcache;
1383         struct PERMISSIONS_CACHE *newcache;
1384         int newcnt;
1385         int oldcnt;
1386         unsigned int index1;
1387         unsigned int i;
1388
1389         oldcache = *scx->pseccache;
1390         index1 = securindex >> CACHE_PERMISSIONS_BITS;
1391         newcnt = index1 + 1;
1392         if (newcnt <= ((CACHE_PERMISSIONS_SIZE
1393                         + (1 << CACHE_PERMISSIONS_BITS)
1394                         - 1) >> CACHE_PERMISSIONS_BITS)) {
1395                 /* expand cache beyond current end, do not use realloc() */
1396                 /* to avoid losing data when there is no more memory */
1397                 oldcnt = oldcache->head.last + 1;
1398                 newcache = (struct PERMISSIONS_CACHE*)
1399                         ntfs_malloc(
1400                             sizeof(struct PERMISSIONS_CACHE)
1401                               + (newcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
1402                 if (newcache) {
1403                         memcpy(newcache,oldcache,
1404                             sizeof(struct PERMISSIONS_CACHE)
1405                               + (oldcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
1406                         free(oldcache);
1407                              /* mark new entries as not valid */
1408                         for (i=newcache->head.last+1; i<=index1; i++)
1409                                 newcache->cachetable[i]
1410                                          = (struct CACHED_PERMISSIONS*)NULL;
1411                         newcache->head.last = index1;
1412                         *scx->pseccache = newcache;
1413                 }
1414         }
1415 }
1416
1417 /*
1418  *      Enter uid, gid and mode into cache, if possible
1419  *
1420  *      returns the updated or created cache entry,
1421  *      or NULL if not possible (typically if there is no
1422  *              security id associated)
1423  */
1424
1425 #if POSIXACLS
1426 static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
1427                 ntfs_inode *ni, uid_t uid, gid_t gid,
1428                 struct POSIX_SECURITY *pxdesc)
1429 #else
1430 static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
1431                 ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode)
1432 #endif
1433 {
1434         struct CACHED_PERMISSIONS *cacheentry;
1435         struct CACHED_PERMISSIONS *cacheblock;
1436         struct PERMISSIONS_CACHE *pcache;
1437         u32 securindex;
1438 #if POSIXACLS
1439         int pxsize;
1440         struct POSIX_SECURITY *pxcached;
1441 #endif
1442         unsigned int index1;
1443         unsigned int index2;
1444         int i;
1445
1446         /* cacheing is only possible if a security_id has been defined */
1447         if (test_nino_flag(ni, v3_Extensions)
1448            && ni->security_id) {
1449                 /*
1450                  *  Immediately test the most frequent situation
1451                  *  where the entry exists
1452                  */
1453                 securindex = le32_to_cpu(ni->security_id);
1454                 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1455                 index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
1456                 pcache = *scx->pseccache;
1457                 if (pcache
1458                      && (pcache->head.last >= index1)
1459                      && pcache->cachetable[index1]) {
1460                         cacheentry = &pcache->cachetable[index1][index2];
1461                         cacheentry->uid = uid;
1462                         cacheentry->gid = gid;
1463 #if POSIXACLS
1464                         if (cacheentry->valid && cacheentry->pxdesc)
1465                                 free(cacheentry->pxdesc);
1466                         if (pxdesc) {
1467                                 pxsize = sizeof(struct POSIX_SECURITY)
1468                                         + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1469                                 pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
1470                                 if (pxcached) {
1471                                         memcpy(pxcached, pxdesc, pxsize);
1472                                         cacheentry->pxdesc = pxcached;
1473                                 } else {
1474                                         cacheentry->valid = 0;
1475                                         cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1476                                 }
1477                                 cacheentry->mode = pxdesc->mode & 07777;
1478                         } else
1479                                 cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
1480 #else
1481                         cacheentry->mode = mode & 07777;
1482 #endif
1483                         cacheentry->inh_fileid = const_cpu_to_le32(0);
1484                         cacheentry->inh_dirid = const_cpu_to_le32(0);
1485                         cacheentry->valid = 1;
1486                         pcache->head.p_writes++;
1487                 } else {
1488                         if (!pcache) {
1489                                 /* create the first cache block */
1490                                 pcache = create_caches(scx, securindex);
1491                         } else {
1492                                 if (index1 > pcache->head.last) {
1493                                         resize_cache(scx, securindex);
1494                                         pcache = *scx->pseccache;
1495                                 }
1496                         }
1497                         /* allocate block, if cache table was allocated */
1498                         if (pcache && (index1 <= pcache->head.last)) {
1499                                 cacheblock = (struct CACHED_PERMISSIONS*)
1500                                         malloc(sizeof(struct CACHED_PERMISSIONS)
1501                                                 << CACHE_PERMISSIONS_BITS);
1502                                 pcache->cachetable[index1] = cacheblock;
1503                                 for (i=0; i<(1 << CACHE_PERMISSIONS_BITS); i++)
1504                                         cacheblock[i].valid = 0;
1505                                 cacheentry = &cacheblock[index2];
1506                                 if (cacheentry) {
1507                                         cacheentry->uid = uid;
1508                                         cacheentry->gid = gid;
1509 #if POSIXACLS
1510                                         if (pxdesc) {
1511                                                 pxsize = sizeof(struct POSIX_SECURITY)
1512                                                         + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1513                                                 pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
1514                                                 if (pxcached) {
1515                                                         memcpy(pxcached, pxdesc, pxsize);
1516                                                         cacheentry->pxdesc = pxcached;
1517                                                 } else {
1518                                                         cacheentry->valid = 0;
1519                                                         cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1520                                                 }
1521                                                 cacheentry->mode = pxdesc->mode & 07777;
1522                                         } else
1523                                                 cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
1524 #else
1525                                         cacheentry->mode = mode & 07777;
1526 #endif
1527                                         cacheentry->inh_fileid = const_cpu_to_le32(0);
1528                                         cacheentry->inh_dirid = const_cpu_to_le32(0);
1529                                         cacheentry->valid = 1;
1530                                         pcache->head.p_writes++;
1531                                 }
1532                         } else
1533                                 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1534                 }
1535         } else {
1536                 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1537 #if CACHE_LEGACY_SIZE
1538                 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1539                         struct CACHED_PERMISSIONS_LEGACY wanted;
1540                         struct CACHED_PERMISSIONS_LEGACY *legacy;
1541
1542                         wanted.perm.uid = uid;
1543                         wanted.perm.gid = gid;
1544 #if POSIXACLS
1545                         wanted.perm.mode = pxdesc->mode & 07777;
1546                         wanted.perm.inh_fileid = const_cpu_to_le32(0);
1547                         wanted.perm.inh_dirid = const_cpu_to_le32(0);
1548                         wanted.mft_no = ni->mft_no;
1549                         wanted.variable = (void*)pxdesc;
1550                         wanted.varsize = sizeof(struct POSIX_SECURITY)
1551                                         + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
1552 #else
1553                         wanted.perm.mode = mode & 07777;
1554                         wanted.perm.inh_fileid = const_cpu_to_le32(0);
1555                         wanted.perm.inh_dirid = const_cpu_to_le32(0);
1556                         wanted.mft_no = ni->mft_no;
1557                         wanted.variable = (void*)NULL;
1558                         wanted.varsize = 0;
1559 #endif
1560                         legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_enter_cache(
1561                                 scx->vol->legacy_cache, GENERIC(&wanted),
1562                                 (cache_compare)leg_compare);
1563                         if (legacy) {
1564                                 cacheentry = &legacy->perm;
1565 #if POSIXACLS
1566                                 /*
1567                                  * give direct access to the cached pxdesc
1568                                  * in the permissions structure
1569                                  */
1570                                 cacheentry->pxdesc = legacy->variable;
1571 #endif
1572                         }
1573                 }
1574 #endif
1575         }
1576         return (cacheentry);
1577 }
1578
1579 /*
1580  *      Fetch owner, group and permission of a file, if cached
1581  *
1582  *      Beware : do not use the returned entry after a cache update :
1583  *      the cache may be relocated making the returned entry meaningless
1584  *
1585  *      returns the cache entry, or NULL if not available
1586  */
1587
1588 static struct CACHED_PERMISSIONS *fetch_cache(struct SECURITY_CONTEXT *scx,
1589                 ntfs_inode *ni)
1590 {
1591         struct CACHED_PERMISSIONS *cacheentry;
1592         struct PERMISSIONS_CACHE *pcache;
1593         u32 securindex;
1594         unsigned int index1;
1595         unsigned int index2;
1596
1597         /* cacheing is only possible if a security_id has been defined */
1598         cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1599         if (test_nino_flag(ni, v3_Extensions)
1600            && (ni->security_id)) {
1601                 securindex = le32_to_cpu(ni->security_id);
1602                 index1 = securindex >> CACHE_PERMISSIONS_BITS;
1603                 index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
1604                 pcache = *scx->pseccache;
1605                 if (pcache
1606                      && (pcache->head.last >= index1)
1607                      && pcache->cachetable[index1]) {
1608                         cacheentry = &pcache->cachetable[index1][index2];
1609                         /* reject if entry is not valid */
1610                         if (!cacheentry->valid)
1611                                 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1612                         else
1613                                 pcache->head.p_hits++;
1614                 if (pcache)
1615                         pcache->head.p_reads++;
1616                 }
1617         }
1618 #if CACHE_LEGACY_SIZE
1619         else {
1620                 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1621                 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
1622                         struct CACHED_PERMISSIONS_LEGACY wanted;
1623                         struct CACHED_PERMISSIONS_LEGACY *legacy;
1624
1625                         wanted.mft_no = ni->mft_no;
1626                         wanted.variable = (void*)NULL;
1627                         wanted.varsize = 0;
1628                         legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_fetch_cache(
1629                                 scx->vol->legacy_cache, GENERIC(&wanted),
1630                                 (cache_compare)leg_compare);
1631                         if (legacy) cacheentry = &legacy->perm;
1632                 }
1633         }
1634 #endif
1635 #if POSIXACLS
1636         if (cacheentry && !cacheentry->pxdesc) {
1637                 ntfs_log_error("No Posix descriptor in cache\n");
1638                 cacheentry = (struct CACHED_PERMISSIONS*)NULL;
1639         }
1640 #endif
1641         return (cacheentry);
1642 }
1643
1644 /*
1645  *      Retrieve a security attribute from $Secure
1646  */
1647
1648 static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id)
1649 {
1650         struct SII *psii;
1651         union {
1652                 struct {
1653                         le32 dataoffsl;
1654                         le32 dataoffsh;
1655                 } parts;
1656                 le64 all;
1657         } realign;
1658         int found;
1659         size_t size;
1660         size_t rdsize;
1661         s64 offs;
1662         ntfs_inode *ni;
1663         ntfs_index_context *xsii;
1664         char *securattr;
1665
1666         securattr = (char*)NULL;
1667         ni = vol->secure_ni;
1668         xsii = vol->secure_xsii;
1669         if (ni && xsii) {
1670                 ntfs_index_ctx_reinit(xsii);
1671                 found =
1672                     !ntfs_index_lookup((char*)&id,
1673                                        sizeof(SII_INDEX_KEY), xsii);
1674                 if (found) {
1675                         psii = (struct SII*)xsii->entry;
1676                         size =
1677                             (size_t) le32_to_cpu(psii->datasize)
1678                                  - sizeof(SECURITY_DESCRIPTOR_HEADER);
1679                         /* work around bad alignment problem */
1680                         realign.parts.dataoffsh = psii->dataoffsh;
1681                         realign.parts.dataoffsl = psii->dataoffsl;
1682                         offs = le64_to_cpu(realign.all)
1683                                 + sizeof(SECURITY_DESCRIPTOR_HEADER);
1684
1685                         securattr = (char*)ntfs_malloc(size);
1686                         if (securattr) {
1687                                 rdsize = ntfs_attr_data_read(
1688                                         ni, STREAM_SDS, 4,
1689                                         securattr, size, offs);
1690                                 if ((rdsize != size)
1691                                         || !ntfs_valid_descr(securattr,
1692                                                 rdsize)) {
1693                                         /* error to be logged by caller */
1694                                         free(securattr);
1695                                         securattr = (char*)NULL;
1696                                 }
1697                         }
1698                 } else
1699                         if (errno != ENOENT)
1700                                 ntfs_log_perror("Inconsistency in index $SII");
1701         }
1702         if (!securattr) {
1703                 ntfs_log_error("Failed to retrieve a security descriptor\n");
1704                 errno = EIO;
1705         }
1706         return (securattr);
1707 }
1708
1709 /*
1710  *              Get the security descriptor associated to a file
1711  *
1712  *      Either :
1713  *         - read the security descriptor attribute (v1.x format)
1714  *         - or find the descriptor in $Secure:$SDS (v3.x format)
1715  *
1716  *      in both case, sanity checks are done on the attribute and
1717  *      the descriptor can be assumed safe
1718  *
1719  *      The returned descriptor is dynamically allocated and has to be freed
1720  */
1721
1722 static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni)
1723 {
1724         SII_INDEX_KEY securid;
1725         char *securattr;
1726         s64 readallsz;
1727
1728                 /*
1729                  * Warning : in some situations, after fixing by chkdsk,
1730                  * v3_Extensions are marked present (long standard informations)
1731                  * with a default security descriptor inserted in an
1732                  * attribute
1733                  */
1734         if (test_nino_flag(ni, v3_Extensions)
1735                         && vol->secure_ni && ni->security_id) {
1736                         /* get v3.x descriptor in $Secure */
1737                 securid.security_id = ni->security_id;
1738                 securattr = retrievesecurityattr(vol,securid);
1739                 if (!securattr)
1740                         ntfs_log_error("Bad security descriptor for 0x%lx\n",
1741                                         (long)le32_to_cpu(ni->security_id));
1742         } else {
1743                         /* get v1.x security attribute */
1744                 readallsz = 0;
1745                 securattr = ntfs_attr_readall(ni, AT_SECURITY_DESCRIPTOR,
1746                                 AT_UNNAMED, 0, &readallsz);
1747                 if (securattr && !ntfs_valid_descr(securattr, readallsz)) {
1748                         ntfs_log_error("Bad security descriptor for inode %lld\n",
1749                                 (long long)ni->mft_no);
1750                         free(securattr);
1751                         securattr = (char*)NULL;
1752                 }
1753         }
1754         if (!securattr) {
1755                         /*
1756                          * in some situations, there is no security
1757                          * descriptor, and chkdsk does not detect or fix
1758                          * anything. This could be a normal situation.
1759                          * When this happens, simulate a descriptor with
1760                          * minimum rights, so that a real descriptor can
1761                          * be created by chown or chmod
1762                          */
1763                 ntfs_log_error("No security descriptor found for inode %lld\n",
1764                                 (long long)ni->mft_no);
1765                 securattr = ntfs_build_descr(0, 0, adminsid, adminsid);
1766         }
1767         return (securattr);
1768 }
1769
1770 #if POSIXACLS
1771
1772 /*
1773  *              Determine which access types to a file are allowed
1774  *      according to the relation of current process to the file
1775  *
1776  *      Do not call if default_permissions is set
1777  */
1778
1779 static int access_check_posix(struct SECURITY_CONTEXT *scx,
1780                         struct POSIX_SECURITY *pxdesc, mode_t request,
1781                         uid_t uid, gid_t gid)
1782 {
1783         struct POSIX_ACE *pxace;
1784         int userperms;
1785         int groupperms;
1786         int mask;
1787         BOOL somegroup;
1788         BOOL needgroups;
1789         mode_t perms;
1790         int i;
1791
1792         perms = pxdesc->mode;
1793                                         /* owner and root access */
1794         if (!scx->uid || (uid == scx->uid)) {
1795                 if (!scx->uid) {
1796                                         /* root access if owner or other execution */
1797                         if (perms & 0101)
1798                                 perms = 07777;
1799                         else {
1800                                         /* root access if some group execution */
1801                                 groupperms = 0;
1802                                 mask = 7;
1803                                 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1804                                         pxace = &pxdesc->acl.ace[i];
1805                                         switch (pxace->tag) {
1806                                         case POSIX_ACL_USER_OBJ :
1807                                         case POSIX_ACL_GROUP_OBJ :
1808                                         case POSIX_ACL_GROUP :
1809                                                 groupperms |= pxace->perms;
1810                                                 break;
1811                                         case POSIX_ACL_MASK :
1812                                                 mask = pxace->perms & 7;
1813                                                 break;
1814                                         default :
1815                                                 break;
1816                                         }
1817                                 }
1818                                 perms = (groupperms & mask & 1) | 6;
1819                         }
1820                 } else
1821                         perms &= 07700;
1822         } else {
1823                                 /*
1824                                  * analyze designated users, get mask
1825                                  * and identify whether we need to check
1826                                  * the group memberships. The groups are
1827                                  * not needed when all groups have the
1828                                  * same permissions as other for the
1829                                  * requested modes.
1830                                  */
1831                 userperms = -1;
1832                 groupperms = -1;
1833                 needgroups = FALSE;
1834                 mask = 7;
1835                 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1836                         pxace = &pxdesc->acl.ace[i];
1837                         switch (pxace->tag) {
1838                         case POSIX_ACL_USER :
1839                                 if ((uid_t)pxace->id == scx->uid)
1840                                         userperms = pxace->perms;
1841                                 break;
1842                         case POSIX_ACL_MASK :
1843                                 mask = pxace->perms & 7;
1844                                 break;
1845                         case POSIX_ACL_GROUP_OBJ :
1846                         case POSIX_ACL_GROUP :
1847                                 if (((pxace->perms & mask) ^ perms)
1848                                     & (request >> 6) & 7)
1849                                         needgroups = TRUE;
1850                                 break;
1851                         default :
1852                                 break;
1853                         }
1854                 }
1855                                         /* designated users */
1856                 if (userperms >= 0)
1857                         perms = (perms & 07000) + (userperms & mask);
1858                 else if (!needgroups)
1859                                 perms &= 07007;
1860                 else {
1861                                         /* owning group */
1862                         if (!(~(perms >> 3) & request & mask)
1863                             && ((gid == scx->gid)
1864                                 || groupmember(scx, scx->uid, gid)))
1865                                 perms &= 07070;
1866                         else {
1867                                         /* other groups */
1868                                 groupperms = -1;
1869                                 somegroup = FALSE;
1870                                 for (i=pxdesc->acccnt-1; i>=0 ; i--) {
1871                                         pxace = &pxdesc->acl.ace[i];
1872                                         if ((pxace->tag == POSIX_ACL_GROUP)
1873                                             && groupmember(scx, uid, pxace->id)) {
1874                                                 if (!(~pxace->perms & request & mask))
1875                                                         groupperms = pxace->perms;
1876                                                 somegroup = TRUE;
1877                                         }
1878                                 }
1879                                 if (groupperms >= 0)
1880                                         perms = (perms & 07000) + (groupperms & mask);
1881                                 else
1882                                         if (somegroup)
1883                                                 perms = 0;
1884                                         else
1885                                                 perms &= 07007;
1886                         }
1887                 }
1888         }
1889         return (perms);
1890 }
1891
1892 /*
1893  *              Get permissions to access a file
1894  *      Takes into account the relation of user to file (owner, group, ...)
1895  *      Do no use as mode of the file
1896  *      Do no call if default_permissions is set
1897  *
1898  *      returns -1 if there is a problem
1899  */
1900
1901 static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
1902                  ntfs_inode * ni, mode_t request)
1903 {
1904         const SECURITY_DESCRIPTOR_RELATIVE *phead;
1905         const struct CACHED_PERMISSIONS *cached;
1906         char *securattr;
1907         const SID *usid;        /* owner of file/directory */
1908         const SID *gsid;        /* group of file/directory */
1909         uid_t uid;
1910         gid_t gid;
1911         int perm;
1912         BOOL isdir;
1913         struct POSIX_SECURITY *pxdesc;
1914
1915         if (!scx->mapping[MAPUSERS])
1916                 perm = 07777;
1917         else {
1918                 /* check whether available in cache */
1919                 cached = fetch_cache(scx,ni);
1920                 if (cached) {
1921                         uid = cached->uid;
1922                         gid = cached->gid;
1923                         perm = access_check_posix(scx,cached->pxdesc,request,uid,gid);
1924                 } else {
1925                         perm = 0;       /* default to no permission */
1926                         isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
1927                                 != const_cpu_to_le16(0);
1928                         securattr = getsecurityattr(scx->vol, ni);
1929                         if (securattr) {
1930                                 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
1931                                         securattr;
1932                                 gsid = (const SID*)&
1933                                            securattr[le32_to_cpu(phead->group)];
1934                                 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
1935 #if OWNERFROMACL
1936                                 usid = ntfs_acl_owner(securattr);
1937                                 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
1938                                                  usid, gsid, isdir);
1939                                 if (pxdesc)
1940                                         perm = pxdesc->mode & 07777;
1941                                 else
1942                                         perm = -1;
1943                                 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
1944 #else
1945                                 usid = (const SID*)&
1946                                             securattr[le32_to_cpu(phead->owner)];
1947                                 pxdesc = ntfs_build_permissions_posix(scx,securattr,
1948                                                  usid, gsid, isdir);
1949                                 if (pxdesc)
1950                                         perm = pxdesc->mode & 07777;
1951                                 else
1952                                         perm = -1;
1953                                 if (!perm && ntfs_same_sid(usid, adminsid)) {
1954                                         uid = find_tenant(scx, securattr);
1955                                         if (uid)
1956                                                 perm = 0700;
1957                                 } else
1958                                         uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
1959 #endif
1960                                 /*
1961                                  *  Create a security id if there were none
1962                                  * and upgrade option is selected
1963                                  */
1964                                 if (!test_nino_flag(ni, v3_Extensions)
1965                                    && (perm >= 0)
1966                                    && (scx->vol->secure_flags
1967                                      & (1 << SECURITY_ADDSECURIDS))) {
1968                                         upgrade_secur_desc(scx->vol,
1969                                                 securattr, ni);
1970                                         /*
1971                                          * fetch owner and group for cacheing
1972                                          * if there is a securid
1973                                          */
1974                                 }
1975                                 if (test_nino_flag(ni, v3_Extensions)
1976                                     && (perm >= 0)) {
1977                                         enter_cache(scx, ni, uid,
1978                                                         gid, pxdesc);
1979                                 }
1980                                 if (pxdesc) {
1981                                         perm = access_check_posix(scx,pxdesc,request,uid,gid);
1982                                         free(pxdesc);
1983                                 }
1984                                 free(securattr);
1985                         } else {
1986                                 perm = -1;
1987                                 uid = gid = 0;
1988                         }
1989                 }
1990         }
1991         return (perm);
1992 }
1993
1994 /*
1995  *              Get a Posix ACL
1996  *
1997  *      returns size or -errno if there is a problem
1998  *      if size was too small, no copy is done and errno is not set,
1999  *      the caller is expected to issue a new call
2000  */
2001
2002 int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2003                         const char *name, char *value, size_t size) 
2004 {
2005         const SECURITY_DESCRIPTOR_RELATIVE *phead;
2006         struct POSIX_SECURITY *pxdesc;
2007         const struct CACHED_PERMISSIONS *cached;
2008         char *securattr;
2009         const SID *usid;        /* owner of file/directory */
2010         const SID *gsid;        /* group of file/directory */
2011         uid_t uid;
2012         gid_t gid;
2013         BOOL isdir;
2014         size_t outsize;
2015
2016         outsize = 0;    /* default to error */
2017         if (!scx->mapping[MAPUSERS])
2018                 errno = ENOTSUP;
2019         else {
2020                         /* check whether available in cache */
2021                 cached = fetch_cache(scx,ni);
2022                 if (cached)
2023                         pxdesc = cached->pxdesc;
2024                 else {
2025                         securattr = getsecurityattr(scx->vol, ni);
2026                         isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2027                                 != const_cpu_to_le16(0);
2028                         if (securattr) {
2029                                 phead =
2030                                     (const SECURITY_DESCRIPTOR_RELATIVE*)
2031                                                 securattr;
2032                                 gsid = (const SID*)&
2033                                           securattr[le32_to_cpu(phead->group)];
2034 #if OWNERFROMACL
2035                                 usid = ntfs_acl_owner(securattr);
2036 #else
2037                                 usid = (const SID*)&
2038                                           securattr[le32_to_cpu(phead->owner)];
2039 #endif
2040                                 pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2041                                           usid, gsid, isdir);
2042
2043                                         /*
2044                                          * fetch owner and group for cacheing
2045                                          */
2046                                 if (pxdesc) {
2047                                 /*
2048                                  *  Create a security id if there were none
2049                                  * and upgrade option is selected
2050                                  */
2051                                         if (!test_nino_flag(ni, v3_Extensions)
2052                                            && (scx->vol->secure_flags
2053                                              & (1 << SECURITY_ADDSECURIDS))) {
2054                                                 upgrade_secur_desc(scx->vol,
2055                                                          securattr, ni);
2056                                         }
2057 #if OWNERFROMACL
2058                                         uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2059 #else
2060                                         if (!(pxdesc->mode & 07777)
2061                                             && ntfs_same_sid(usid, adminsid)) {
2062                                                 uid = find_tenant(scx,
2063                                                                 securattr);
2064                                         } else
2065                                                 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2066 #endif
2067                                         gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2068                                         if (pxdesc->tagsset & POSIX_ACL_EXTENSIONS)
2069                                         enter_cache(scx, ni, uid,
2070                                                         gid, pxdesc);
2071                                 }
2072                                 free(securattr);
2073                         } else
2074                                 pxdesc = (struct POSIX_SECURITY*)NULL;
2075                 }
2076
2077                 if (pxdesc) {
2078                         if (ntfs_valid_posix(pxdesc)) {
2079                                 if (!strcmp(name,"system.posix_acl_default")) {
2080                                         if (ni->mrec->flags
2081                                                     & MFT_RECORD_IS_DIRECTORY)
2082                                                 outsize = sizeof(struct POSIX_ACL)
2083                                                         + pxdesc->defcnt*sizeof(struct POSIX_ACE);
2084                                         else {
2085                                         /*
2086                                          * getting default ACL from plain file :
2087                                          * return EACCES if size > 0 as
2088                                          * indicated in the man, but return ok
2089                                          * if size == 0, so that ls does not
2090                                          * display an error
2091                                          */
2092                                                 if (size > 0) {
2093                                                         outsize = 0;
2094                                                         errno = EACCES;
2095                                                 } else
2096                                                         outsize = sizeof(struct POSIX_ACL);
2097                                         }
2098                                         if (outsize && (outsize <= size)) {
2099                                                 memcpy(value,&pxdesc->acl,sizeof(struct POSIX_ACL));
2100                                                 memcpy(&value[sizeof(struct POSIX_ACL)],
2101                                                         &pxdesc->acl.ace[pxdesc->firstdef],
2102                                                         outsize-sizeof(struct POSIX_ACL));
2103                                         }
2104                                 } else {
2105                                         outsize = sizeof(struct POSIX_ACL)
2106                                                 + pxdesc->acccnt*sizeof(struct POSIX_ACE);
2107                                         if (outsize <= size)
2108                                                 memcpy(value,&pxdesc->acl,outsize);
2109                                 }
2110                         } else {
2111                                 outsize = 0;
2112                                 errno = EIO;
2113                                 ntfs_log_error("Invalid Posix ACL built\n");
2114                         }
2115                         if (!cached)
2116                                 free(pxdesc);
2117                 } else
2118                         outsize = 0;
2119         }
2120         return (outsize ? (int)outsize : -errno);
2121 }
2122
2123 #else /* POSIXACLS */
2124
2125
2126 /*
2127  *              Get permissions to access a file
2128  *      Takes into account the relation of user to file (owner, group, ...)
2129  *      Do no use as mode of the file
2130  *
2131  *      returns -1 if there is a problem
2132  */
2133
2134 static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
2135                 ntfs_inode *ni, mode_t request)
2136 {
2137         const SECURITY_DESCRIPTOR_RELATIVE *phead;
2138         const struct CACHED_PERMISSIONS *cached;
2139         char *securattr;
2140         const SID *usid;        /* owner of file/directory */
2141         const SID *gsid;        /* group of file/directory */
2142         BOOL isdir;
2143         uid_t uid;
2144         gid_t gid;
2145         int perm;
2146
2147         if (!scx->mapping[MAPUSERS] || (!scx->uid && !(request & S_IEXEC)))
2148                 perm = 07777;
2149         else {
2150                 /* check whether available in cache */
2151                 cached = fetch_cache(scx,ni);
2152                 if (cached) {
2153                         perm = cached->mode;
2154                         uid = cached->uid;
2155                         gid = cached->gid;
2156                 } else {
2157                         perm = 0;       /* default to no permission */
2158                         isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2159                                 != const_cpu_to_le16(0);
2160                         securattr = getsecurityattr(scx->vol, ni);
2161                         if (securattr) {
2162                                 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2163                                         securattr;
2164                                 gsid = (const SID*)&
2165                                            securattr[le32_to_cpu(phead->group)];
2166                                 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2167 #if OWNERFROMACL
2168                                 usid = ntfs_acl_owner(securattr);
2169                                 perm = ntfs_build_permissions(securattr,
2170                                                  usid, gsid, isdir);
2171                                 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2172 #else
2173                                 usid = (const SID*)&
2174                                             securattr[le32_to_cpu(phead->owner)];
2175                                 perm = ntfs_build_permissions(securattr,
2176                                                  usid, gsid, isdir);
2177                                 if (!perm && ntfs_same_sid(usid, adminsid)) {
2178                                         uid = find_tenant(scx, securattr);
2179                                         if (uid)
2180                                                 perm = 0700;
2181                                 } else
2182                                         uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2183 #endif
2184                                 /*
2185                                  *  Create a security id if there were none
2186                                  * and upgrade option is selected
2187                                  */
2188                                 if (!test_nino_flag(ni, v3_Extensions)
2189                                    && (perm >= 0)
2190                                    && (scx->vol->secure_flags
2191                                      & (1 << SECURITY_ADDSECURIDS))) {
2192                                         upgrade_secur_desc(scx->vol,
2193                                                 securattr, ni);
2194                                         /*
2195                                          * fetch owner and group for cacheing
2196                                          * if there is a securid
2197                                          */
2198                                 }
2199                                 if (test_nino_flag(ni, v3_Extensions)
2200                                     && (perm >= 0)) {
2201                                         enter_cache(scx, ni, uid,
2202                                                         gid, perm);
2203                                 }
2204                                 free(securattr);
2205                         } else {
2206                                 perm = -1;
2207                                 uid = gid = 0;
2208                         }
2209                 }
2210                 if (perm >= 0) {
2211                         if (!scx->uid) {
2212                                 /* root access and execution */
2213                                 if (perm & 0111)
2214                                         perm = 07777;
2215                                 else
2216                                         perm = 0;
2217                         } else
2218                                 if (uid == scx->uid)
2219                                         perm &= 07700;
2220                                 else
2221                                 /*
2222                                  * avoid checking group membership
2223                                  * when the requested perms for group
2224                                  * are the same as perms for other
2225                                  */
2226                                         if ((gid == scx->gid)
2227                                           || ((((perm >> 3) ^ perm)
2228                                                 & (request >> 6) & 7)
2229                                             && groupmember(scx, scx->uid, gid)))
2230                                                 perm &= 07070;
2231                                         else
2232                                                 perm &= 07007;
2233                 }
2234         }
2235         return (perm);
2236 }
2237
2238 #endif /* POSIXACLS */
2239
2240 /*
2241  *              Get an NTFS ACL
2242  *
2243  *      Returns size or -errno if there is a problem
2244  *      if size was too small, no copy is done and errno is not set,
2245  *      the caller is expected to issue a new call
2246  */
2247
2248 int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2249                         char *value, size_t size)
2250 {
2251         char *securattr;
2252         size_t outsize;
2253
2254         outsize = 0;    /* default to no data and no error */
2255         securattr = getsecurityattr(scx->vol, ni);
2256         if (securattr) {
2257                 outsize = ntfs_attr_size(securattr);
2258                 if (outsize <= size) {
2259                         memcpy(value,securattr,outsize);
2260                 }
2261                 free(securattr);
2262         }
2263         return (outsize ? (int)outsize : -errno);
2264 }
2265
2266 /*
2267  *              Get owner, group and permissions in an stat structure
2268  *      returns permissions, or -1 if there is a problem
2269  */
2270
2271 int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
2272                 ntfs_inode * ni, struct stat *stbuf)
2273 {
2274         const SECURITY_DESCRIPTOR_RELATIVE *phead;
2275         char *securattr;
2276         const SID *usid;        /* owner of file/directory */
2277         const SID *gsid;        /* group of file/directory */
2278         const struct CACHED_PERMISSIONS *cached;
2279         int perm;
2280         BOOL isdir;
2281 #if POSIXACLS
2282         struct POSIX_SECURITY *pxdesc;
2283 #endif
2284
2285         if (!scx->mapping[MAPUSERS])
2286                 perm = 07777;
2287         else {
2288                         /* check whether available in cache */
2289                 cached = fetch_cache(scx,ni);
2290                 if (cached) {
2291                         perm = cached->mode;
2292                         stbuf->st_uid = cached->uid;
2293                         stbuf->st_gid = cached->gid;
2294                         stbuf->st_mode = (stbuf->st_mode & ~07777) + perm;
2295                 } else {
2296                         perm = -1;      /* default to error */
2297                         isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
2298                                 != const_cpu_to_le16(0);
2299                         securattr = getsecurityattr(scx->vol, ni);
2300                         if (securattr) {
2301                                 phead =
2302                                     (const SECURITY_DESCRIPTOR_RELATIVE*)
2303                                                 securattr;
2304                                 gsid = (const SID*)&
2305                                           securattr[le32_to_cpu(phead->group)];
2306 #if OWNERFROMACL
2307                                 usid = ntfs_acl_owner(securattr);
2308 #else
2309                                 usid = (const SID*)&
2310                                           securattr[le32_to_cpu(phead->owner)];
2311 #endif
2312 #if POSIXACLS
2313                                 pxdesc = ntfs_build_permissions_posix(scx->mapping, securattr,
2314                                           usid, gsid, isdir);
2315                                 if (pxdesc)
2316                                         perm = pxdesc->mode & 07777;
2317                                 else
2318                                         perm = -1;
2319 #else
2320                                 perm = ntfs_build_permissions(securattr,
2321                                           usid, gsid, isdir);
2322 #endif
2323                                         /*
2324                                          * fetch owner and group for cacheing
2325                                          */
2326                                 if (perm >= 0) {
2327                                 /*
2328                                  *  Create a security id if there were none
2329                                  * and upgrade option is selected
2330                                  */
2331                                         if (!test_nino_flag(ni, v3_Extensions)
2332                                            && (scx->vol->secure_flags
2333                                              & (1 << SECURITY_ADDSECURIDS))) {
2334                                                 upgrade_secur_desc(scx->vol,
2335                                                          securattr, ni);
2336                                         }
2337 #if OWNERFROMACL
2338                                         stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2339 #else
2340                                         if (!perm && ntfs_same_sid(usid, adminsid)) {
2341                                                 stbuf->st_uid = 
2342                                                         find_tenant(scx,
2343                                                                 securattr);
2344                                                 if (stbuf->st_uid)
2345                                                         perm = 0700;
2346                                         } else
2347                                                 stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2348 #endif
2349                                         stbuf->st_gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2350                                         stbuf->st_mode =
2351                                             (stbuf->st_mode & ~07777) + perm;
2352 #if POSIXACLS
2353                                         enter_cache(scx, ni, stbuf->st_uid,
2354                                                 stbuf->st_gid, pxdesc);
2355                                         free(pxdesc);
2356 #else
2357                                         enter_cache(scx, ni, stbuf->st_uid,
2358                                                 stbuf->st_gid, perm);
2359 #endif
2360                                 }
2361                                 free(securattr);
2362                         }
2363                 }
2364         }
2365         return (perm);
2366 }
2367
2368 #if POSIXACLS
2369
2370 /*
2371  *              Get the base for a Posix inheritance and
2372  *      build an inherited Posix descriptor
2373  */
2374
2375 static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx,
2376                         ntfs_inode *dir_ni, mode_t mode, BOOL isdir)
2377 {
2378         const struct CACHED_PERMISSIONS *cached;
2379         const SECURITY_DESCRIPTOR_RELATIVE *phead;
2380         struct POSIX_SECURITY *pxdesc;
2381         struct POSIX_SECURITY *pydesc;
2382         char *securattr;
2383         const SID *usid;
2384         const SID *gsid;
2385         uid_t uid;
2386         gid_t gid;
2387
2388         pydesc = (struct POSIX_SECURITY*)NULL;
2389                 /* check whether parent directory is available in cache */
2390         cached = fetch_cache(scx,dir_ni);
2391         if (cached) {
2392                 uid = cached->uid;
2393                 gid = cached->gid;
2394                 pxdesc = cached->pxdesc;
2395                 if (pxdesc) {
2396                         pydesc = ntfs_build_inherited_posix(pxdesc,mode,
2397                                         scx->umask,isdir);
2398                 }
2399         } else {
2400                 securattr = getsecurityattr(scx->vol, dir_ni);
2401                 if (securattr) {
2402                         phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2403                                 securattr;
2404                         gsid = (const SID*)&
2405                                    securattr[le32_to_cpu(phead->group)];
2406                         gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2407 #if OWNERFROMACL
2408                         usid = ntfs_acl_owner(securattr);
2409                         pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2410                                                  usid, gsid, TRUE);
2411                         uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2412 #else
2413                         usid = (const SID*)&
2414                                     securattr[le32_to_cpu(phead->owner)];
2415                         pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
2416                                                  usid, gsid, TRUE);
2417                         if (pxdesc && ntfs_same_sid(usid, adminsid)) {
2418                                 uid = find_tenant(scx, securattr);
2419                         } else
2420                                 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2421 #endif
2422                         if (pxdesc) {
2423                                 /*
2424                                  *  Create a security id if there were none
2425                                  * and upgrade option is selected
2426                                  */
2427                                 if (!test_nino_flag(dir_ni, v3_Extensions)
2428                                    && (scx->vol->secure_flags
2429                                      & (1 << SECURITY_ADDSECURIDS))) {
2430                                         upgrade_secur_desc(scx->vol,
2431                                                 securattr, dir_ni);
2432                                         /*
2433                                          * fetch owner and group for cacheing
2434                                          * if there is a securid
2435                                          */
2436                                 }
2437                                 if (test_nino_flag(dir_ni, v3_Extensions)) {
2438                                         enter_cache(scx, dir_ni, uid,
2439                                                         gid, pxdesc);
2440                                 }
2441                                 pydesc = ntfs_build_inherited_posix(pxdesc,
2442                                         mode, scx->umask, isdir);
2443                                 free(pxdesc);
2444                         }
2445                         free(securattr);
2446                 }
2447         }
2448         return (pydesc);
2449 }
2450
2451 /*
2452  *              Allocate a security_id for a file being created
2453  *      
2454  *      Returns zero if not possible (NTFS v3.x required)
2455  */
2456
2457 le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
2458                 uid_t uid, gid_t gid, ntfs_inode *dir_ni,
2459                 mode_t mode, BOOL isdir)
2460 {
2461 #if !FORCE_FORMAT_v1x
2462         const struct CACHED_SECURID *cached;
2463         struct CACHED_SECURID wanted;
2464         struct POSIX_SECURITY *pxdesc;
2465         char *newattr;
2466         int newattrsz;
2467         const SID *usid;
2468         const SID *gsid;
2469         BIGSID defusid;
2470         BIGSID defgsid;
2471         le32 securid;
2472 #endif
2473
2474         securid = const_cpu_to_le32(0);
2475
2476 #if !FORCE_FORMAT_v1x
2477
2478         pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
2479         if (pxdesc) {
2480                 /* check whether target securid is known in cache */
2481
2482                 wanted.uid = uid;
2483                 wanted.gid = gid;
2484                 wanted.dmode = pxdesc->mode & mode & 07777;
2485                 if (isdir) wanted.dmode |= 0x10000;
2486                 wanted.variable = (void*)pxdesc;
2487                 wanted.varsize = sizeof(struct POSIX_SECURITY)
2488                                 + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2489                 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2490                                 scx->vol->securid_cache, GENERIC(&wanted),
2491                                 (cache_compare)compare);
2492                         /* quite simple, if we are lucky */
2493                 if (cached)
2494                         securid = cached->securid;
2495
2496                         /* not in cache : make sure we can create ids */
2497
2498                 if (!cached && (scx->vol->major_ver >= 3)) {
2499                         usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2500                         gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2501                         if (!usid || !gsid) {
2502                                 ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2503                                                 (int)uid, (int)gid);
2504                                 usid = gsid = adminsid;
2505                         }
2506                         newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2507                                         isdir, usid, gsid);
2508                         if (newattr) {
2509                                 newattrsz = ntfs_attr_size(newattr);
2510                                 securid = setsecurityattr(scx->vol,
2511                                         (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
2512                                         newattrsz);
2513                                 if (securid) {
2514                                         /* update cache, for subsequent use */
2515                                         wanted.securid = securid;
2516                                         ntfs_enter_cache(scx->vol->securid_cache,
2517                                                         GENERIC(&wanted),
2518                                                         (cache_compare)compare);
2519                                 }
2520                                 free(newattr);
2521                         } else {
2522                                 /*
2523                                  * could not build new security attribute
2524                                  * errno set by ntfs_build_descr()
2525                                  */
2526                         }
2527                 }
2528         free(pxdesc);
2529         }
2530 #endif
2531         return (securid);
2532 }
2533
2534 /*
2535  *              Apply Posix inheritance to a newly created file
2536  *      (for NTFS 1.x only : no securid)
2537  */
2538
2539 int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
2540                 ntfs_inode *ni, uid_t uid, gid_t gid,
2541                 ntfs_inode *dir_ni, mode_t mode)
2542 {
2543         struct POSIX_SECURITY *pxdesc;
2544         char *newattr;
2545         const SID *usid;
2546         const SID *gsid;
2547         BIGSID defusid;
2548         BIGSID defgsid;
2549         BOOL isdir;
2550         int res;
2551
2552         res = -1;
2553         isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2554         pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
2555         if (pxdesc) {
2556                 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2557                 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2558                 if (!usid || !gsid) {
2559                         ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2560                                         (int)uid, (int)gid);
2561                         usid = gsid = adminsid;
2562                 }
2563                 newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2564                                         isdir, usid, gsid);
2565                 if (newattr) {
2566                                 /* Adjust Windows read-only flag */
2567                         res = update_secur_descr(scx->vol, newattr, ni);
2568                         if (!res && !isdir) {
2569                                 if (mode & S_IWUSR)
2570                                         ni->flags &= ~FILE_ATTR_READONLY;
2571                                 else
2572                                         ni->flags |= FILE_ATTR_READONLY;
2573                         }
2574 #if CACHE_LEGACY_SIZE
2575                         /* also invalidate legacy cache */
2576                         if (isdir && !ni->security_id) {
2577                                 struct CACHED_PERMISSIONS_LEGACY legacy;
2578
2579                                 legacy.mft_no = ni->mft_no;
2580                                 legacy.variable = pxdesc;
2581                                 legacy.varsize = sizeof(struct POSIX_SECURITY)
2582                                         + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2583                                 ntfs_invalidate_cache(scx->vol->legacy_cache,
2584                                                 GENERIC(&legacy),
2585                                                 (cache_compare)leg_compare,0);
2586                         }
2587 #endif
2588                         free(newattr);
2589
2590                 } else {
2591                         /*
2592                          * could not build new security attribute
2593                          * errno set by ntfs_build_descr()
2594                          */
2595                 }
2596         }
2597         return (res);
2598 }
2599
2600 #else
2601
2602 le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
2603                 uid_t uid, gid_t gid, mode_t mode, BOOL isdir)
2604 {
2605 #if !FORCE_FORMAT_v1x
2606         const struct CACHED_SECURID *cached;
2607         struct CACHED_SECURID wanted;
2608         char *newattr;
2609         int newattrsz;
2610         const SID *usid;
2611         const SID *gsid;
2612         BIGSID defusid;
2613         BIGSID defgsid;
2614         le32 securid;
2615 #endif
2616
2617         securid = const_cpu_to_le32(0);
2618
2619 #if !FORCE_FORMAT_v1x
2620                 /* check whether target securid is known in cache */
2621
2622         wanted.uid = uid;
2623         wanted.gid = gid;
2624         wanted.dmode = mode & 07777;
2625         if (isdir) wanted.dmode |= 0x10000;
2626         wanted.variable = (void*)NULL;
2627         wanted.varsize = 0;
2628         cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2629                         scx->vol->securid_cache, GENERIC(&wanted),
2630                         (cache_compare)compare);
2631                 /* quite simple, if we are lucky */
2632         if (cached)
2633                 securid = cached->securid;
2634
2635                 /* not in cache : make sure we can create ids */
2636
2637         if (!cached && (scx->vol->major_ver >= 3)) {
2638                 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2639                 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2640                 if (!usid || !gsid) {
2641                         ntfs_log_error("File created by an unmapped user/group %d/%d\n",
2642                                         (int)uid, (int)gid);
2643                         usid = gsid = adminsid;
2644                 }
2645                 newattr = ntfs_build_descr(mode, isdir, usid, gsid);
2646                 if (newattr) {
2647                         newattrsz = ntfs_attr_size(newattr);
2648                         securid = setsecurityattr(scx->vol,
2649                                 (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
2650                                 newattrsz);
2651                         if (securid) {
2652                                 /* update cache, for subsequent use */
2653                                 wanted.securid = securid;
2654                                 ntfs_enter_cache(scx->vol->securid_cache,
2655                                                 GENERIC(&wanted),
2656                                                 (cache_compare)compare);
2657                         }
2658                         free(newattr);
2659                 } else {
2660                         /*
2661                          * could not build new security attribute
2662                          * errno set by ntfs_build_descr()
2663                          */
2664                 }
2665         }
2666 #endif
2667         return (securid);
2668 }
2669
2670 #endif
2671
2672 /*
2673  *              Update ownership and mode of a file, reusing an existing
2674  *      security descriptor when possible
2675  *      
2676  *      Returns zero if successful
2677  */
2678
2679 #if POSIXACLS
2680 int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2681                 uid_t uid, gid_t gid, mode_t mode,
2682                 struct POSIX_SECURITY *pxdesc)
2683 #else
2684 int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2685                 uid_t uid, gid_t gid, mode_t mode)
2686 #endif
2687 {
2688         int res;
2689         const struct CACHED_SECURID *cached;
2690         struct CACHED_SECURID wanted;
2691         char *newattr;
2692         const SID *usid;
2693         const SID *gsid;
2694         BIGSID defusid;
2695         BIGSID defgsid;
2696         BOOL isdir;
2697
2698         res = 0;
2699
2700                 /* check whether target securid is known in cache */
2701
2702         isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2703         wanted.uid = uid;
2704         wanted.gid = gid;
2705         wanted.dmode = mode & 07777;
2706         if (isdir) wanted.dmode |= 0x10000;
2707 #if POSIXACLS
2708         wanted.variable = (void*)pxdesc;
2709         if (pxdesc)
2710                 wanted.varsize = sizeof(struct POSIX_SECURITY)
2711                         + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
2712         else
2713                 wanted.varsize = 0;
2714 #else
2715         wanted.variable = (void*)NULL;
2716         wanted.varsize = 0;
2717 #endif
2718         if (test_nino_flag(ni, v3_Extensions)) {
2719                 cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
2720                                 scx->vol->securid_cache, GENERIC(&wanted),
2721                                 (cache_compare)compare);
2722                         /* quite simple, if we are lucky */
2723                 if (cached) {
2724                         ni->security_id = cached->securid;
2725                         NInoSetDirty(ni);
2726                 }
2727         } else cached = (struct CACHED_SECURID*)NULL;
2728
2729         if (!cached) {
2730                         /*
2731                          * Do not use usid and gsid from former attributes,
2732                          * but recompute them to get repeatable results
2733                          * which can be kept in cache.
2734                          */
2735                 usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
2736                 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
2737                 if (!usid || !gsid) {
2738                         ntfs_log_error("File made owned by an unmapped user/group %d/%d\n",
2739                                 uid, gid);
2740                         usid = gsid = adminsid;
2741                 }
2742 #if POSIXACLS
2743                 if (pxdesc)
2744                         newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
2745                                          isdir, usid, gsid);
2746                 else
2747                         newattr = ntfs_build_descr(mode,
2748                                          isdir, usid, gsid);
2749 #else
2750                 newattr = ntfs_build_descr(mode,
2751                                          isdir, usid, gsid);
2752 #endif
2753                 if (newattr) {
2754                         res = update_secur_descr(scx->vol, newattr, ni);
2755                         if (!res) {
2756                                 /* adjust Windows read-only flag */
2757                                 if (!isdir) {
2758                                         if (mode & S_IWUSR)
2759                                                 ni->flags &= ~FILE_ATTR_READONLY;
2760                                         else
2761                                                 ni->flags |= FILE_ATTR_READONLY;
2762                                         NInoFileNameSetDirty(ni);
2763                                 }
2764                                 /* update cache, for subsequent use */
2765                                 if (test_nino_flag(ni, v3_Extensions)) {
2766                                         wanted.securid = ni->security_id;
2767                                         ntfs_enter_cache(scx->vol->securid_cache,
2768                                                         GENERIC(&wanted),
2769                                                         (cache_compare)compare);
2770                                 }
2771 #if CACHE_LEGACY_SIZE
2772                                 /* also invalidate legacy cache */
2773                                 if (isdir && !ni->security_id) {
2774                                         struct CACHED_PERMISSIONS_LEGACY legacy;
2775
2776                                         legacy.mft_no = ni->mft_no;
2777 #if POSIXACLS
2778                                         legacy.variable = wanted.variable;
2779                                         legacy.varsize = wanted.varsize;
2780 #else
2781                                         legacy.variable = (void*)NULL;
2782                                         legacy.varsize = 0;
2783 #endif
2784                                         ntfs_invalidate_cache(scx->vol->legacy_cache,
2785                                                 GENERIC(&legacy),
2786                                                 (cache_compare)leg_compare,0);
2787                                 }
2788 #endif
2789                         }
2790                         free(newattr);
2791                 } else {
2792                         /*
2793                          * could not build new security attribute
2794                          * errno set by ntfs_build_descr()
2795                          */
2796                         res = -1;
2797                 }
2798         }
2799         return (res);
2800 }
2801
2802 /*
2803  *              Check whether user has ownership rights on a file
2804  *
2805  *      Returns TRUE if allowed
2806  *              if not, errno tells why
2807  */
2808
2809 BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni)
2810 {
2811         const struct CACHED_PERMISSIONS *cached;
2812         char *oldattr;
2813         const SID *usid;
2814         uid_t processuid;
2815         uid_t uid;
2816         BOOL gotowner;
2817         int allowed;
2818
2819         processuid = scx->uid;
2820 /* TODO : use CAP_FOWNER process capability */
2821         /*
2822          * Always allow for root
2823          * Also always allow if no mapping has been defined
2824          */
2825         if (!scx->mapping[MAPUSERS] || !processuid)
2826                 allowed = TRUE;
2827         else {
2828                 gotowner = FALSE; /* default */
2829                 /* get the owner, either from cache or from old attribute  */
2830                 cached = fetch_cache(scx, ni);
2831                 if (cached) {
2832                         uid = cached->uid;
2833                         gotowner = TRUE;
2834                 } else {
2835                         oldattr = getsecurityattr(scx->vol, ni);
2836                         if (oldattr) {
2837 #if OWNERFROMACL
2838                                 usid = ntfs_acl_owner(oldattr);
2839 #else
2840                                 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2841
2842                                 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
2843                                                                 oldattr;
2844                                 usid = (const SID*)&oldattr
2845                                                 [le32_to_cpu(phead->owner)];
2846 #endif
2847                                 uid = ntfs_find_user(scx->mapping[MAPUSERS],
2848                                                 usid);
2849                                 gotowner = TRUE;
2850                                 free(oldattr);
2851                         }
2852                 }
2853                 allowed = FALSE;
2854                 if (gotowner) {
2855 /* TODO : use CAP_FOWNER process capability */
2856                         if (!processuid || (processuid == uid))
2857                                 allowed = TRUE;
2858                         else
2859                                 errno = EPERM;
2860                 }
2861         }
2862         return (allowed);
2863 }
2864
2865 #ifdef HAVE_SETXATTR    /* extended attributes interface required */
2866
2867 #if POSIXACLS
2868
2869 /*
2870  *              Set a new access or default Posix ACL to a file
2871  *              (or remove ACL if no input data)
2872  *      Validity of input data is checked after merging
2873  *
2874  *      Returns 0, or -1 if there is a problem which errno describes
2875  */
2876
2877 int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2878                         const char *name, const char *value, size_t size,
2879                         int flags)
2880 {
2881         const SECURITY_DESCRIPTOR_RELATIVE *phead;
2882         const struct CACHED_PERMISSIONS *cached;
2883         char *oldattr;
2884         uid_t processuid;
2885         const SID *usid;
2886         const SID *gsid;
2887         uid_t uid;
2888         uid_t gid;
2889         int res;
2890         BOOL isdir;
2891         BOOL deflt;
2892         BOOL exist;
2893         int count;
2894         struct POSIX_SECURITY *oldpxdesc;
2895         struct POSIX_SECURITY *newpxdesc;
2896
2897         /* get the current pxsec, either from cache or from old attribute  */
2898         res = -1;
2899         deflt = !strcmp(name,"system.posix_acl_default");
2900         if (size)
2901                 count = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE);
2902         else
2903                 count = 0;
2904         isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
2905         newpxdesc = (struct POSIX_SECURITY*)NULL;
2906         if ((!value
2907                 || (((const struct POSIX_ACL*)value)->version == POSIX_VERSION))
2908             && (!deflt || isdir || (!size && !value))) {
2909                 cached = fetch_cache(scx, ni);
2910                 if (cached) {
2911                         uid = cached->uid;
2912                         gid = cached->gid;
2913                         oldpxdesc = cached->pxdesc;
2914                         if (oldpxdesc) {
2915                                 newpxdesc = ntfs_replace_acl(oldpxdesc,
2916                                                 (const struct POSIX_ACL*)value,count,deflt);
2917                                 }
2918                 } else {
2919                         oldattr = getsecurityattr(scx->vol, ni);
2920                         if (oldattr) {
2921                                 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
2922 #if OWNERFROMACL
2923                                 usid = ntfs_acl_owner(oldattr);
2924 #else
2925                                 usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
2926 #endif
2927                                 gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
2928                                 uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
2929                                 gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
2930                                 oldpxdesc = ntfs_build_permissions_posix(scx->mapping,
2931                                         oldattr, usid, gsid, isdir);
2932                                 if (oldpxdesc) {
2933                                         if (deflt)
2934                                                 exist = oldpxdesc->defcnt > 0;
2935                                         else
2936                                                 exist = oldpxdesc->acccnt > 3;
2937                                         if ((exist && (flags & XATTR_CREATE))
2938                                           || (!exist && (flags & XATTR_REPLACE))) {
2939                                                 errno = (exist ? EEXIST : ENODATA);
2940                                         } else {
2941                                                 newpxdesc = ntfs_replace_acl(oldpxdesc,
2942                                                         (const struct POSIX_ACL*)value,count,deflt);
2943                                         }
2944                                         free(oldpxdesc);
2945                                 }
2946                                 free(oldattr);
2947                         }
2948                 }
2949         } else
2950                 errno = EINVAL;
2951
2952         if (newpxdesc) {
2953                 processuid = scx->uid;
2954 /* TODO : use CAP_FOWNER process capability */
2955                 if (!processuid || (uid == processuid)) {
2956                                 /*
2957                                  * clear setgid if file group does
2958                                  * not match process group
2959                                  */
2960                         if (processuid && (gid != scx->gid)
2961                             && !groupmember(scx, scx->uid, gid)) {
2962                                 newpxdesc->mode &= ~S_ISGID;
2963                         }
2964                         res = ntfs_set_owner_mode(scx, ni, uid, gid,
2965                                 newpxdesc->mode, newpxdesc);
2966                 } else
2967                         errno = EPERM;
2968                 free(newpxdesc);
2969         }
2970         return (res ? -1 : 0);
2971 }
2972
2973 /*
2974  *              Remove a default Posix ACL from a file
2975  *
2976  *      Returns 0, or -1 if there is a problem which errno describes
2977  */
2978
2979 int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2980                         const char *name)
2981 {
2982         return (ntfs_set_posix_acl(scx, ni, name,
2983                         (const char*)NULL, 0, 0));
2984 }
2985
2986 #endif
2987
2988 /*
2989  *              Set a new NTFS ACL to a file
2990  *
2991  *      Returns 0, or -1 if there is a problem
2992  */
2993
2994 int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
2995                         const char *value, size_t size, int flags)
2996 {