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