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