]> wimlib.net Git - wimlib/blob - src/ntfs-3g_security.c
new NTFS 3g patches
[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) {
3450                                 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3451                                 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3452                         } else
3453                                 res = -1;
3454 #endif
3455                         free(oldattr);
3456                 } else
3457                         res = -1;
3458         }
3459         if (!res) {
3460                 /* check requested by root */
3461                 /* or chgrp requested by owner to an owned group */
3462                 if (!scx->uid
3463                    || ((((int)uid < 0) || (uid == fileuid))
3464                       && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
3465                       && (fileuid == scx->uid))) {
3466                         /* replace by the new usid and gsid */
3467                         /* or reuse old gid and sid for cacheing */
3468                         if ((int)uid < 0)
3469                                 uid = fileuid;
3470                         if ((int)gid < 0)
3471                                 gid = filegid;
3472                         /* clear setuid and setgid if owner has changed */
3473                         /* unless request originated by root */
3474                         if (uid && (fileuid != uid))
3475                                 mode &= 01777;
3476 #if POSIXACLS
3477                         res = ntfs_set_owner_mode(scx, ni, uid, gid, 
3478                                 mode, pxdesc);
3479 #else
3480                         res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3481 #endif
3482                 } else {
3483                         res = -1;       /* neither owner nor root */
3484                         errno = EPERM;
3485                 }
3486 #if POSIXACLS
3487                 if (pxdescbuilt)
3488                         free(pxdesc);
3489 #endif
3490         } else {
3491                 /*
3492                  * Should not happen : a default descriptor is generated
3493                  * by getsecurityattr() when there are none
3494                  */
3495                 ntfs_log_error("File has no security descriptor\n");
3496                 res = -1;
3497                 errno = EIO;
3498         }
3499         return (res ? -1 : 0);
3500 }
3501
3502 /*
3503  *              Define new owner/group and mode to a file
3504  *
3505  *      returns zero if successful
3506  */
3507
3508 int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
3509                         uid_t uid, gid_t gid, const mode_t mode)
3510 {
3511         const struct CACHED_PERMISSIONS *cached;
3512         char *oldattr;
3513         uid_t fileuid;
3514         uid_t filegid;
3515         int res;
3516 #if POSIXACLS
3517         const SECURITY_DESCRIPTOR_RELATIVE *phead;
3518         const SID *usid;
3519         const SID *gsid;
3520         BOOL isdir;
3521         const struct POSIX_SECURITY *oldpxdesc;
3522         struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
3523         int pxsize;
3524 #endif
3525
3526         res = 0;
3527         /* get the current owner and mode from cache or security attributes */
3528         oldattr = (char*)NULL;
3529         cached = fetch_cache(scx,ni);
3530         if (cached) {
3531                 fileuid = cached->uid;
3532                 filegid = cached->gid;
3533 #if POSIXACLS
3534                 oldpxdesc = cached->pxdesc;
3535                 if (oldpxdesc) {
3536                                 /* must copy before merging */
3537                         pxsize = sizeof(struct POSIX_SECURITY)
3538                                 + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
3539                         newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
3540                         if (newpxdesc) {
3541                                 memcpy(newpxdesc, oldpxdesc, pxsize);
3542                                 if (ntfs_merge_mode_posix(newpxdesc, mode))
3543                                         res = -1;
3544                         } else
3545                                 res = -1;
3546                 }
3547 #endif
3548         } else {
3549                 fileuid = 0;
3550                 filegid = 0;
3551                 oldattr = getsecurityattr(scx->vol, ni);
3552                 if (oldattr) {
3553 #if POSIXACLS
3554                         isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
3555                                 != const_cpu_to_le16(0);
3556                         phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
3557                                 oldattr;
3558                         gsid = (const SID*)
3559                                 &oldattr[le32_to_cpu(phead->group)];
3560 #if OWNERFROMACL
3561                         usid = ntfs_acl_owner(oldattr);
3562 #else
3563                         usid = (const SID*)
3564                                 &oldattr[le32_to_cpu(phead->owner)];
3565 #endif
3566                         newpxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
3567                                         usid, gsid, isdir);
3568                         if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
3569                                 res = -1;
3570                         else {
3571                                 fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
3572                                 filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
3573                         }
3574 #endif
3575                         free(oldattr);
3576                 } else
3577                         res = -1;
3578         }
3579         if (!res) {
3580                 /* check requested by root */
3581                 /* or chgrp requested by owner to an owned group */
3582                 if (!scx->uid
3583                    || ((((int)uid < 0) || (uid == fileuid))
3584                       && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
3585                       && (fileuid == scx->uid))) {
3586                         /* replace by the new usid and gsid */
3587                         /* or reuse old gid and sid for cacheing */
3588                         if ((int)uid < 0)
3589                                 uid = fileuid;
3590                         if ((int)gid < 0)
3591                                 gid = filegid;
3592 #if POSIXACLS
3593                         res = ntfs_set_owner_mode(scx, ni, uid, gid, 
3594                                 mode, newpxdesc);
3595 #else
3596                         res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
3597 #endif
3598                 } else {
3599                         res = -1;       /* neither owner nor root */
3600                         errno = EPERM;
3601                 }
3602         } else {
3603                 /*
3604                  * Should not happen : a default descriptor is generated
3605                  * by getsecurityattr() when there are none
3606                  */
3607                 ntfs_log_error("File has no security descriptor\n");
3608                 res = -1;
3609                 errno = EIO;
3610         }
3611 #if POSIXACLS
3612         free(newpxdesc);
3613 #endif
3614         return (res ? -1 : 0);
3615 }
3616
3617 /*
3618  *              Build a security id for a descriptor inherited from
3619  *      parent directory the Windows way
3620  */
3621
3622 static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
3623                         const char *parentattr, BOOL fordir)
3624 {
3625         const SECURITY_DESCRIPTOR_RELATIVE *pphead;
3626         const ACL *ppacl;
3627         const SID *usid;
3628         const SID *gsid;
3629         BIGSID defusid;
3630         BIGSID defgsid;
3631         int offpacl;
3632         int offowner;
3633         int offgroup;
3634         SECURITY_DESCRIPTOR_RELATIVE *pnhead;
3635         ACL *pnacl;
3636         int parentattrsz;
3637         char *newattr;
3638         int newattrsz;
3639         int aclsz;
3640         int usidsz;
3641         int gsidsz;
3642         int pos;
3643         le32 securid;
3644
3645         parentattrsz = ntfs_attr_size(parentattr);
3646         pphead = (const SECURITY_DESCRIPTOR_RELATIVE*)parentattr;
3647         if (scx->mapping[MAPUSERS]) {
3648                 usid = ntfs_find_usid(scx->mapping[MAPUSERS], scx->uid, (SID*)&defusid);
3649                 gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS], scx->gid, (SID*)&defgsid);
3650                 if (!usid)
3651                         usid = adminsid;
3652                 if (!gsid)
3653                         gsid = adminsid;
3654         } else {
3655                 /*
3656                  * If there is no user mapping, we have to copy owner
3657                  * and group from parent directory.
3658                  * Windows never has to do that, because it can always
3659                  * rely on a user mapping
3660                  */
3661                 offowner = le32_to_cpu(pphead->owner);
3662                 usid = (const SID*)&parentattr[offowner];
3663                 offgroup = le32_to_cpu(pphead->group);
3664                 gsid = (const SID*)&parentattr[offgroup];
3665         }
3666                 /*
3667                  * new attribute is smaller than parent's
3668                  * except for differences in SIDs which appear in
3669                  * owner, group and possible grants and denials in
3670                  * generic creator-owner and creator-group ACEs.
3671                  * For directories, an ACE may be duplicated for
3672                  * access and inheritance, so we double the count.
3673                  */
3674         usidsz = ntfs_sid_size(usid);
3675         gsidsz = ntfs_sid_size(gsid);
3676         newattrsz = parentattrsz + 3*usidsz + 3*gsidsz;
3677         if (fordir)
3678                 newattrsz *= 2;
3679         newattr = (char*)ntfs_malloc(newattrsz);
3680         if (newattr) {
3681                 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr;
3682                 pnhead->revision = SECURITY_DESCRIPTOR_REVISION;
3683                 pnhead->alignment = 0;
3684                 pnhead->control = SE_SELF_RELATIVE;
3685                 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
3686                         /*
3687                          * locate and inherit DACL
3688                          * do not test SE_DACL_PRESENT (wrong for "DR Watson")
3689                          */
3690                 pnhead->dacl = const_cpu_to_le32(0);
3691                 if (pphead->dacl) {
3692                         offpacl = le32_to_cpu(pphead->dacl);
3693                         ppacl = (const ACL*)&parentattr[offpacl];
3694                         pnacl = (ACL*)&newattr[pos];
3695                         aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
3696                         if (aclsz) {
3697                                 pnhead->dacl = cpu_to_le32(pos);
3698                                 pos += aclsz;
3699                                 pnhead->control |= SE_DACL_PRESENT;
3700                         }
3701                 }
3702                         /*
3703                          * locate and inherit SACL
3704                          */
3705                 pnhead->sacl = const_cpu_to_le32(0);
3706                 if (pphead->sacl) {
3707                         offpacl = le32_to_cpu(pphead->sacl);
3708                         ppacl = (const ACL*)&parentattr[offpacl];
3709                         pnacl = (ACL*)&newattr[pos];
3710                         aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
3711                         if (aclsz) {
3712                                 pnhead->sacl = cpu_to_le32(pos);
3713                                 pos += aclsz;
3714                                 pnhead->control |= SE_SACL_PRESENT;
3715                         }
3716                 }
3717                         /*
3718                          * inherit or redefine owner
3719                          */
3720                 memcpy(&newattr[pos],usid,usidsz);
3721                 pnhead->owner = cpu_to_le32(pos);
3722                 pos += usidsz;
3723                         /*
3724                          * inherit or redefine group
3725                          */
3726                 memcpy(&newattr[pos],gsid,gsidsz);
3727                 pnhead->group = cpu_to_le32(pos);
3728                 pos += usidsz;
3729                 securid = setsecurityattr(scx->vol,
3730                         (SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos);
3731                 free(newattr);
3732         } else
3733                 securid = const_cpu_to_le32(0);
3734         return (securid);
3735 }
3736
3737 /*
3738  *              Get an inherited security id
3739  *
3740  *      For Windows compatibility, the normal initial permission setting
3741  *      may be inherited from the parent directory instead of being
3742  *      defined by the creation arguments.
3743  *
3744  *      The following creates an inherited id for that purpose.
3745  *
3746  *      Note : the owner and group of parent directory are also
3747  *      inherited (which is not the case on Windows) if no user mapping
3748  *      is defined.
3749  *
3750  *      Returns the inherited id, or zero if not possible (eg on NTFS 1.x)
3751  */
3752
3753 le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
3754                         ntfs_inode *dir_ni, BOOL fordir)
3755 {
3756         struct CACHED_PERMISSIONS *cached;
3757         char *parentattr;
3758         le32 securid;
3759
3760         securid = const_cpu_to_le32(0);
3761         cached = (struct CACHED_PERMISSIONS*)NULL;
3762                 /*
3763                  * Try to get inherited id from cache
3764                  */
3765         if (test_nino_flag(dir_ni, v3_Extensions)
3766                         && dir_ni->security_id) {
3767                 cached = fetch_cache(scx, dir_ni);
3768                 if (cached)
3769                         securid = (fordir ? cached->inh_dirid
3770                                         : cached->inh_fileid);
3771         }
3772                 /*
3773                  * Not cached or not available in cache, compute it all
3774                  * Note : if parent directory has no id, it is not cacheable
3775                  */
3776         if (!securid) {
3777                 parentattr = getsecurityattr(scx->vol, dir_ni);
3778                 if (parentattr) {
3779                         securid = build_inherited_id(scx,
3780                                                 parentattr, fordir);
3781                         free(parentattr);
3782                         /*
3783                          * Store the result into cache for further use
3784                          */
3785                         if (securid) {
3786                                 cached = fetch_cache(scx, dir_ni);
3787                                 if (cached) {
3788                                         if (fordir)
3789                                                 cached->inh_dirid = securid;
3790                                         else
3791                                                 cached->inh_fileid = securid;
3792                                 }
3793                         }
3794                 }
3795         }
3796         return (securid);
3797 }
3798
3799 /*
3800  *              Link a group to a member of group
3801  *
3802  *      Returns 0 if OK, -1 (and errno set) if error
3803  */
3804
3805 static int link_single_group(struct MAPPING *usermapping, struct passwd *user,
3806                         gid_t gid)
3807 {
3808         struct group *group;
3809         char **grmem;
3810         int grcnt;
3811         gid_t *groups;
3812         int res;
3813
3814         res = 0;
3815         group = getgrgid(gid);
3816         if (group && group->gr_mem) {
3817                 grcnt = usermapping->grcnt;
3818                 groups = usermapping->groups;
3819                 grmem = group->gr_mem;
3820                 while (*grmem && strcmp(user->pw_name, *grmem))
3821                         grmem++;
3822                 if (*grmem) {
3823                         if (!grcnt)
3824                                 groups = (gid_t*)malloc(sizeof(gid_t));
3825                         else
3826                                 groups = (gid_t*)realloc(groups,
3827                                         (grcnt+1)*sizeof(gid_t));
3828                         if (groups)
3829                                 groups[grcnt++] = gid;
3830                         else {
3831                                 res = -1;
3832                                 errno = ENOMEM;
3833                         }
3834                 }
3835                 usermapping->grcnt = grcnt;
3836                 usermapping->groups = groups;
3837         }
3838         return (res);
3839 }
3840
3841
3842 /*
3843  *              Statically link group to users
3844  *      This is based on groups defined in /etc/group and does not take
3845  *      the groups dynamically set by setgroups() nor any changes in
3846  *      /etc/group into account
3847  *
3848  *      Only mapped groups and root group are linked to mapped users
3849  *
3850  *      Returns 0 if OK, -1 (and errno set) if error
3851  *
3852  */
3853
3854 static int link_group_members(struct SECURITY_CONTEXT *scx)
3855 {
3856         struct MAPPING *usermapping;
3857         struct MAPPING *groupmapping;
3858         struct passwd *user;
3859         int res;
3860
3861         res = 0;
3862         for (usermapping=scx->mapping[MAPUSERS]; usermapping && !res;
3863                         usermapping=usermapping->next) {
3864                 usermapping->grcnt = 0;
3865                 usermapping->groups = (gid_t*)NULL;
3866                 user = getpwuid(usermapping->xid);
3867                 if (user && user->pw_name) {
3868                         for (groupmapping=scx->mapping[MAPGROUPS];
3869                                         groupmapping && !res;
3870                                         groupmapping=groupmapping->next) {
3871                                 if (link_single_group(usermapping, user,
3872                                     groupmapping->xid))
3873                                         res = -1;
3874                                 }
3875                         if (!res && link_single_group(usermapping,
3876                                          user, (gid_t)0))
3877                                 res = -1;
3878                 }
3879         }
3880         return (res);
3881 }
3882
3883 /*
3884  *              Apply default single user mapping
3885  *      returns zero if successful
3886  */
3887
3888 static int ntfs_do_default_mapping(struct SECURITY_CONTEXT *scx,
3889                          uid_t uid, gid_t gid, const SID *usid)
3890 {
3891         struct MAPPING *usermapping;
3892         struct MAPPING *groupmapping;
3893         SID *sid;
3894         int sidsz;
3895         int res;
3896
3897         res = -1;
3898         sidsz = ntfs_sid_size(usid);
3899         sid = (SID*)ntfs_malloc(sidsz);
3900         if (sid) {
3901                 memcpy(sid,usid,sidsz);
3902                 usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
3903                 if (usermapping) {
3904                         groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
3905                         if (groupmapping) {
3906                                 usermapping->sid = sid;
3907                                 usermapping->xid = uid;
3908                                 usermapping->next = (struct MAPPING*)NULL;
3909                                 groupmapping->sid = sid;
3910                                 groupmapping->xid = gid;
3911                                 groupmapping->next = (struct MAPPING*)NULL;
3912                                 scx->mapping[MAPUSERS] = usermapping;
3913                                 scx->mapping[MAPGROUPS] = groupmapping;
3914                                 res = 0;
3915                         }
3916                 }
3917         }
3918         return (res);
3919 }
3920
3921 /*
3922  *              Make sure there are no ambiguous mapping
3923  *      Ambiguous mapping may lead to undesired configurations and
3924  *      we had rather be safe until the consequences are understood
3925  */
3926
3927 #if 0 /* not activated for now */
3928
3929 static BOOL check_mapping(const struct MAPPING *usermapping,
3930                 const struct MAPPING *groupmapping)
3931 {
3932         const struct MAPPING *mapping1;
3933         const struct MAPPING *mapping2;
3934         BOOL ambiguous;
3935
3936         ambiguous = FALSE;
3937         for (mapping1=usermapping; mapping1; mapping1=mapping1->next)
3938                 for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
3939                         if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
3940                                 if (mapping1->xid != mapping2->xid)
3941                                         ambiguous = TRUE;
3942                         } else {
3943                                 if (mapping1->xid == mapping2->xid)
3944                                         ambiguous = TRUE;
3945                         }
3946         for (mapping1=groupmapping; mapping1; mapping1=mapping1->next)
3947                 for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
3948                         if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
3949                                 if (mapping1->xid != mapping2->xid)
3950                                         ambiguous = TRUE;
3951                         } else {
3952                                 if (mapping1->xid == mapping2->xid)
3953                                         ambiguous = TRUE;
3954                         }
3955         return (ambiguous);
3956 }
3957
3958 #endif
3959
3960 #if 0 /* not used any more */
3961
3962 /*
3963  *              Try and apply default single user mapping
3964  *      returns zero if successful
3965  */
3966
3967 static int ntfs_default_mapping(struct SECURITY_CONTEXT *scx)
3968 {
3969         const SECURITY_DESCRIPTOR_RELATIVE *phead;
3970         ntfs_inode *ni;
3971         char *securattr;
3972         const SID *usid;
3973         int res;
3974
3975         res = -1;
3976         ni = ntfs_pathname_to_inode(scx->vol, NULL, "/.");
3977         if (ni) {
3978                 securattr = getsecurityattr(scx->vol, ni);
3979                 if (securattr) {
3980                         phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr;
3981                         usid = (SID*)&securattr[le32_to_cpu(phead->owner)];
3982                         if (ntfs_is_user_sid(usid))
3983                                 res = ntfs_do_default_mapping(scx,
3984                                                 scx->uid, scx->gid, usid);
3985                         free(securattr);
3986                 }
3987                 ntfs_inode_close(ni);
3988         }
3989         return (res);
3990 }
3991
3992 #endif
3993
3994 /*
3995  *              Basic read from a user mapping file on another volume
3996  */
3997
3998 static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused)))
3999 {
4000         return (read(*(int*)fileid, buf, size));
4001 }
4002
4003
4004 /*
4005  *              Read from a user mapping file on current NTFS partition
4006  */
4007
4008 static int localread(void *fileid, char *buf, size_t size, off_t offs)
4009 {
4010         return (ntfs_attr_data_read((ntfs_inode*)fileid,
4011                         AT_UNNAMED, 0, buf, size, offs));
4012 }
4013
4014 /*
4015  *              Build the user mapping
4016  *      - according to a mapping file if defined (or default present),
4017  *      - or try default single user mapping if possible
4018  *
4019  *      The mapping is specific to a mounted device
4020  *      No locking done, mounting assumed non multithreaded
4021  *
4022  *      returns zero if mapping is successful
4023  *      (failure should not be interpreted as an error)
4024  */
4025
4026 int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
4027                         BOOL allowdef)
4028 {
4029         struct MAPLIST *item;
4030         struct MAPLIST *firstitem;
4031         struct MAPPING *usermapping;
4032         struct MAPPING *groupmapping;
4033         ntfs_inode *ni;
4034         int fd;
4035         static struct {
4036                 u8 revision;
4037                 u8 levels;
4038                 be16 highbase;
4039                 be32 lowbase;
4040                 le32 level1;
4041                 le32 level2;
4042                 le32 level3;
4043                 le32 level4;
4044                 le32 level5;
4045         } defmap = {
4046                 1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5),
4047                 const_cpu_to_le32(21),
4048                 const_cpu_to_le32(DEFSECAUTH1), const_cpu_to_le32(DEFSECAUTH2),
4049                 const_cpu_to_le32(DEFSECAUTH3), const_cpu_to_le32(DEFSECBASE)
4050         } ;
4051
4052         /* be sure not to map anything until done */
4053         scx->mapping[MAPUSERS] = (struct MAPPING*)NULL;
4054         scx->mapping[MAPGROUPS] = (struct MAPPING*)NULL;
4055
4056         if (!usermap_path) usermap_path = MAPPINGFILE;
4057         if (usermap_path[0] == '/') {
4058                 fd = open(usermap_path,O_RDONLY);
4059                 if (fd > 0) {
4060                         firstitem = ntfs_read_mapping(basicread, (void*)&fd);
4061                         close(fd);
4062                 } else
4063                         firstitem = (struct MAPLIST*)NULL;
4064         } else {
4065                 ni = ntfs_pathname_to_inode(scx->vol, NULL, usermap_path);
4066                 if (ni) {
4067                         firstitem = ntfs_read_mapping(localread, ni);
4068                         ntfs_inode_close(ni);
4069                 } else
4070                         firstitem = (struct MAPLIST*)NULL;
4071         }
4072
4073
4074         if (firstitem) {
4075                 usermapping = ntfs_do_user_mapping(firstitem);
4076                 groupmapping = ntfs_do_group_mapping(firstitem);
4077                 if (usermapping && groupmapping) {
4078                         scx->mapping[MAPUSERS] = usermapping;
4079                         scx->mapping[MAPGROUPS] = groupmapping;
4080                 } else
4081                         ntfs_log_error("There were no valid user or no valid group\n");
4082                 /* now we can free the memory copy of input text */
4083                 /* and rely on internal representation */
4084                 while (firstitem) {
4085                         item = firstitem->next;
4086                         free(firstitem);
4087                         firstitem = item;
4088                 }
4089         } else {
4090                         /* no mapping file, try a default mapping */
4091                 if (allowdef) {
4092                         if (!ntfs_do_default_mapping(scx,
4093                                         0, 0, (const SID*)&defmap))
4094                                 ntfs_log_info("Using default user mapping\n");
4095                 }
4096         }
4097         return (!scx->mapping[MAPUSERS] || link_group_members(scx));
4098 }
4099
4100 #ifdef HAVE_SETXATTR    /* extended attributes interface required */
4101
4102 /*
4103  *              Get the ntfs attribute into an extended attribute
4104  *      The attribute is returned according to cpu endianness
4105  */
4106
4107 int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size)
4108 {
4109         u32 attrib;
4110         size_t outsize;
4111
4112         outsize = 0;    /* default to no data and no error */
4113         if (ni) {
4114                 attrib = le32_to_cpu(ni->flags);
4115                 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
4116                         attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4117                 else
4118                         attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4119                 if (!attrib)
4120                         attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
4121                 outsize = sizeof(FILE_ATTR_FLAGS);
4122                 if (size >= outsize) {
4123                         if (value)
4124                                 memcpy(value,&attrib,outsize);
4125                         else
4126                                 errno = EINVAL;
4127                 }
4128         }
4129         return (outsize ? (int)outsize : -errno);
4130 }
4131
4132 /*
4133  *              Get the ntfs attributes from an inode
4134  *      The attributes are returned according to cpu endianness
4135  *
4136  *      Returns the attributes if successful (cannot be zero)
4137  *              0 if failed (errno to tell why)
4138  */
4139
4140 u32 ntfs_get_inode_attributes(ntfs_inode *ni)
4141 {
4142         u32 attrib = -1;
4143
4144         if (ni) {
4145                 attrib = le32_to_cpu(ni->flags);
4146                 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
4147                         attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4148                 else
4149                         attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
4150                 if (!attrib)
4151                         attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
4152         } else
4153                 errno = EINVAL;
4154         return (attrib);
4155 }
4156
4157 /*
4158  *              Set the ntfs attributes on an inode
4159  *      The attribute is expected according to cpu endianness
4160  *
4161  *      Returns 0 if successful
4162  *              -1 if failed (errno to tell why)
4163  */
4164
4165 int ntfs_set_inode_attributes(ntfs_inode *ni, u32 attrib)
4166 {
4167         le32 settable;
4168         ATTR_FLAGS dirflags;
4169         int res;
4170
4171         res = -1;
4172         if (ni) {
4173                 settable = FILE_ATTR_SETTABLE;
4174                 res = 0;
4175                 if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4176                         /*
4177                          * Accept changing compression for a directory
4178                          * and set index root accordingly
4179                          */
4180                         settable |= FILE_ATTR_COMPRESSED;
4181                         if ((ni->flags ^ cpu_to_le32(attrib))
4182                                      & FILE_ATTR_COMPRESSED) {
4183                                 if (ni->flags & FILE_ATTR_COMPRESSED)
4184                                         dirflags = const_cpu_to_le16(0);
4185                                 else
4186                                         dirflags = ATTR_IS_COMPRESSED;
4187                                 res = ntfs_attr_set_flags(ni, AT_INDEX_ROOT,
4188                                         NTFS_INDEX_I30, 4, dirflags,
4189                                         ATTR_COMPRESSION_MASK);
4190                         }
4191                 }
4192                 if (!res) {
4193                         ni->flags = (ni->flags & ~settable)
4194                                  | (cpu_to_le32(attrib) & settable);
4195                         NInoFileNameSetDirty(ni);
4196                         NInoSetDirty(ni);
4197                 }
4198         } else
4199                 errno = EINVAL;
4200         return (res);
4201 }
4202
4203 /*
4204  *              Return the ntfs attribute into an extended attribute
4205  *      The attribute is expected according to cpu endianness
4206  *
4207  *      Returns 0, or -1 if there is a problem
4208  */
4209
4210 int ntfs_set_ntfs_attrib(ntfs_inode *ni,
4211                         const char *value, size_t size, int flags)
4212 {
4213         u32 attrib;
4214         int res;
4215
4216         res = -1;
4217         if (ni && value && (size >= sizeof(FILE_ATTR_FLAGS))) {
4218                 if (!(flags & XATTR_CREATE)) {
4219                         /* copy to avoid alignment problems */
4220                         memcpy(&attrib,value,sizeof(FILE_ATTR_FLAGS));
4221                         res = ntfs_set_inode_attributes(ni, attrib);
4222                 } else
4223                         errno = EEXIST;
4224         } else
4225                 errno = EINVAL;
4226         return (res ? -1 : 0);
4227 }
4228
4229 #endif /* HAVE_SETXATTR */
4230
4231 /*
4232  *      Open $Secure once for all
4233  *      returns zero if it succeeds
4234  *              non-zero if it fails. This is not an error (on NTFS v1.x)
4235  */
4236
4237
4238 int ntfs_open_secure(ntfs_volume *vol)
4239 {
4240         ntfs_inode *ni;
4241         int res;
4242
4243         res = -1;
4244         vol->secure_ni = (ntfs_inode*)NULL;
4245         vol->secure_xsii = (ntfs_index_context*)NULL;
4246         vol->secure_xsdh = (ntfs_index_context*)NULL;
4247         if (vol->major_ver >= 3) {
4248                         /* make sure this is a genuine $Secure inode 9 */
4249                 ni = ntfs_pathname_to_inode(vol, NULL, "$Secure");
4250                 if (ni && (ni->mft_no == 9)) {
4251                         vol->secure_reentry = 0;
4252                         vol->secure_xsii = ntfs_index_ctx_get(ni,
4253                                                 sii_stream, 4);
4254                         vol->secure_xsdh = ntfs_index_ctx_get(ni,
4255                                                 sdh_stream, 4);
4256                         if (ni && vol->secure_xsii && vol->secure_xsdh) {
4257                                 vol->secure_ni = ni;
4258                                 res = 0;
4259                         }
4260                 }
4261         }
4262         return (res);
4263 }
4264
4265 /*
4266  *              Final cleaning
4267  *      Allocated memory is freed to facilitate the detection of memory leaks
4268  */
4269
4270 void ntfs_close_secure(struct SECURITY_CONTEXT *scx)
4271 {
4272         ntfs_volume *vol;
4273
4274         vol = scx->vol;
4275         if (vol->secure_ni) {
4276                 ntfs_index_ctx_put(vol->secure_xsii);
4277                 ntfs_index_ctx_put(vol->secure_xsdh);
4278                 ntfs_inode_close(vol->secure_ni);
4279                 
4280         }
4281         ntfs_free_mapping(scx->mapping);
4282         free_caches(scx);
4283 }
4284
4285 /*
4286  *              API for direct access to security descriptors
4287  *      based on Win32 API
4288  */
4289
4290
4291 /*
4292  *              Selective feeding of a security descriptor into user buffer
4293  *
4294  *      Returns TRUE if successful
4295  */
4296
4297 static BOOL feedsecurityattr(const char *attr, u32 selection,
4298                 char *buf, u32 buflen, u32 *psize)
4299 {
4300         const SECURITY_DESCRIPTOR_RELATIVE *phead;
4301         SECURITY_DESCRIPTOR_RELATIVE *pnhead;
4302         const ACL *pdacl;
4303         const ACL *psacl;
4304         const SID *pusid;
4305         const SID *pgsid;
4306         unsigned int offdacl;
4307         unsigned int offsacl;
4308         unsigned int offowner;
4309         unsigned int offgroup;
4310         unsigned int daclsz;
4311         unsigned int saclsz;
4312         unsigned int usidsz;
4313         unsigned int gsidsz;
4314         unsigned int size; /* size of requested attributes */
4315         BOOL ok;
4316         unsigned int pos;
4317         unsigned int avail;
4318         le16 control;
4319
4320         avail = 0;
4321         control = SE_SELF_RELATIVE;
4322         phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4323         size = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4324
4325                 /* locate DACL if requested and available */
4326         if (phead->dacl && (selection & DACL_SECURITY_INFORMATION)) {
4327                 offdacl = le32_to_cpu(phead->dacl);
4328                 pdacl = (const ACL*)&attr[offdacl];
4329                 daclsz = le16_to_cpu(pdacl->size);
4330                 size += daclsz;
4331                 avail |= DACL_SECURITY_INFORMATION;
4332         } else
4333                 offdacl = daclsz = 0;
4334
4335                 /* locate owner if requested and available */
4336         offowner = le32_to_cpu(phead->owner);
4337         if (offowner && (selection & OWNER_SECURITY_INFORMATION)) {
4338                         /* find end of USID */
4339                 pusid = (const SID*)&attr[offowner];
4340                 usidsz = ntfs_sid_size(pusid);
4341                 size += usidsz;
4342                 avail |= OWNER_SECURITY_INFORMATION;
4343         } else
4344                 offowner = usidsz = 0;
4345
4346                 /* locate group if requested and available */
4347         offgroup = le32_to_cpu(phead->group);
4348         if (offgroup && (selection & GROUP_SECURITY_INFORMATION)) {
4349                         /* find end of GSID */
4350                 pgsid = (const SID*)&attr[offgroup];
4351                 gsidsz = ntfs_sid_size(pgsid);
4352                 size += gsidsz;
4353                 avail |= GROUP_SECURITY_INFORMATION;
4354         } else
4355                 offgroup = gsidsz = 0;
4356
4357                 /* locate SACL if requested and available */
4358         if (phead->sacl && (selection & SACL_SECURITY_INFORMATION)) {
4359                         /* find end of SACL */
4360                 offsacl = le32_to_cpu(phead->sacl);
4361                 psacl = (const ACL*)&attr[offsacl];
4362                 saclsz = le16_to_cpu(psacl->size);
4363                 size += saclsz;
4364                 avail |= SACL_SECURITY_INFORMATION;
4365         } else
4366                 offsacl = saclsz = 0;
4367
4368                 /*
4369                  * Check having enough size in destination buffer
4370                  * (required size is returned nevertheless so that
4371                  * the request can be reissued with adequate size)
4372                  */
4373         if (size > buflen) {
4374                 *psize = size;
4375                 errno = EINVAL;
4376                 ok = FALSE;
4377         } else {
4378                 if (selection & OWNER_SECURITY_INFORMATION)
4379                         control |= phead->control & SE_OWNER_DEFAULTED;
4380                 if (selection & GROUP_SECURITY_INFORMATION)
4381                         control |= phead->control & SE_GROUP_DEFAULTED;
4382                 if (selection & DACL_SECURITY_INFORMATION)
4383                         control |= phead->control
4384                                         & (SE_DACL_PRESENT
4385                                            | SE_DACL_DEFAULTED
4386                                            | SE_DACL_AUTO_INHERITED
4387                                            | SE_DACL_PROTECTED);
4388                 if (selection & SACL_SECURITY_INFORMATION)
4389                         control |= phead->control
4390                                         & (SE_SACL_PRESENT
4391                                            | SE_SACL_DEFAULTED
4392                                            | SE_SACL_AUTO_INHERITED
4393                                            | SE_SACL_PROTECTED);
4394                 /*
4395                  * copy header and feed new flags, even if no detailed data
4396                  */
4397                 memcpy(buf,attr,sizeof(SECURITY_DESCRIPTOR_RELATIVE));
4398                 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)buf;
4399                 pnhead->control = control;
4400                 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4401
4402                 /* copy DACL if requested and available */
4403                 if (selection & avail & DACL_SECURITY_INFORMATION) {
4404                         pnhead->dacl = cpu_to_le32(pos);
4405                         memcpy(&buf[pos],&attr[offdacl],daclsz);
4406                         pos += daclsz;
4407                 } else
4408                         pnhead->dacl = const_cpu_to_le32(0);
4409
4410                 /* copy SACL if requested and available */
4411                 if (selection & avail & SACL_SECURITY_INFORMATION) {
4412                         pnhead->sacl = cpu_to_le32(pos);
4413                         memcpy(&buf[pos],&attr[offsacl],saclsz);
4414                         pos += saclsz;
4415                 } else
4416                         pnhead->sacl = const_cpu_to_le32(0);
4417
4418                 /* copy owner if requested and available */
4419                 if (selection & avail & OWNER_SECURITY_INFORMATION) {
4420                         pnhead->owner = cpu_to_le32(pos);
4421                         memcpy(&buf[pos],&attr[offowner],usidsz);
4422                         pos += usidsz;
4423                 } else
4424                         pnhead->owner = const_cpu_to_le32(0);
4425
4426                 /* copy group if requested and available */
4427                 if (selection & avail & GROUP_SECURITY_INFORMATION) {
4428                         pnhead->group = cpu_to_le32(pos);
4429                         memcpy(&buf[pos],&attr[offgroup],gsidsz);
4430                         pos += gsidsz;
4431                 } else
4432                         pnhead->group = const_cpu_to_le32(0);
4433                 if (pos != size)
4434                         ntfs_log_error("Error in security descriptor size\n");
4435                 *psize = size;
4436                 ok = TRUE;
4437         }
4438
4439         return (ok);
4440 }
4441
4442 /*
4443  *              Merge a new security descriptor into the old one
4444  *      and assign to designated file
4445  *
4446  *      Returns TRUE if successful
4447  */
4448
4449 static BOOL mergesecurityattr(ntfs_volume *vol, const char *oldattr,
4450                 const char *newattr, u32 selection, ntfs_inode *ni)
4451 {
4452         const SECURITY_DESCRIPTOR_RELATIVE *oldhead;
4453         const SECURITY_DESCRIPTOR_RELATIVE *newhead;
4454         SECURITY_DESCRIPTOR_RELATIVE *targhead;
4455         const ACL *pdacl;
4456         const ACL *psacl;
4457         const SID *powner;
4458         const SID *pgroup;
4459         int offdacl;
4460         int offsacl;
4461         int offowner;
4462         int offgroup;
4463         unsigned int size;
4464         le16 control;
4465         char *target;
4466         int pos;
4467         int oldattrsz;
4468         int newattrsz;
4469         BOOL ok;
4470
4471         ok = FALSE; /* default return */
4472         oldhead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
4473         newhead = (const SECURITY_DESCRIPTOR_RELATIVE*)newattr;
4474         oldattrsz = ntfs_attr_size(oldattr);
4475         newattrsz = ntfs_attr_size(newattr);
4476         target = (char*)ntfs_malloc(oldattrsz + newattrsz);
4477         if (target) {
4478                 targhead = (SECURITY_DESCRIPTOR_RELATIVE*)target;
4479                 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
4480                 control = SE_SELF_RELATIVE;
4481                         /*
4482                          * copy new DACL if selected
4483                          * or keep old DACL if any
4484                          */
4485                 if ((selection & DACL_SECURITY_INFORMATION) ?
4486                                 newhead->dacl : oldhead->dacl) {
4487                         if (selection & DACL_SECURITY_INFORMATION) {
4488                                 offdacl = le32_to_cpu(newhead->dacl);
4489                                 pdacl = (const ACL*)&newattr[offdacl];
4490                         } else {
4491                                 offdacl = le32_to_cpu(oldhead->dacl);
4492                                 pdacl = (const ACL*)&oldattr[offdacl];
4493                         }
4494                         size = le16_to_cpu(pdacl->size);
4495                         memcpy(&target[pos], pdacl, size);
4496                         targhead->dacl = cpu_to_le32(pos);
4497                         pos += size;
4498                 } else
4499                         targhead->dacl = const_cpu_to_le32(0);
4500                 if (selection & DACL_SECURITY_INFORMATION) {
4501                         control |= newhead->control
4502                                         & (SE_DACL_PRESENT
4503                                            | SE_DACL_DEFAULTED
4504                                            | SE_DACL_PROTECTED);
4505                         if (newhead->control & SE_DACL_AUTO_INHERIT_REQ)
4506                                 control |= SE_DACL_AUTO_INHERITED;
4507                 } else
4508                         control |= oldhead->control
4509                                         & (SE_DACL_PRESENT
4510                                            | SE_DACL_DEFAULTED
4511                                            | SE_DACL_AUTO_INHERITED
4512                                            | SE_DACL_PROTECTED);
4513                         /*
4514                          * copy new SACL if selected
4515                          * or keep old SACL if any
4516                          */
4517                 if ((selection & SACL_SECURITY_INFORMATION) ?
4518                                 newhead->sacl : oldhead->sacl) {
4519                         if (selection & SACL_SECURITY_INFORMATION) {
4520                                 offsacl = le32_to_cpu(newhead->sacl);
4521                                 psacl = (const ACL*)&newattr[offsacl];
4522                         } else {
4523                                 offsacl = le32_to_cpu(oldhead->sacl);
4524                                 psacl = (const ACL*)&oldattr[offsacl];
4525                         }
4526                         size = le16_to_cpu(psacl->size);
4527                         memcpy(&target[pos], psacl, size);
4528                         targhead->sacl = cpu_to_le32(pos);
4529                         pos += size;
4530                 } else
4531                         targhead->sacl = const_cpu_to_le32(0);
4532                 if (selection & SACL_SECURITY_INFORMATION) {
4533                         control |= newhead->control
4534                                         & (SE_SACL_PRESENT
4535                                            | SE_SACL_DEFAULTED
4536                                            | SE_SACL_PROTECTED);
4537                         if (newhead->control & SE_SACL_AUTO_INHERIT_REQ)
4538                                 control |= SE_SACL_AUTO_INHERITED;
4539                 } else
4540                         control |= oldhead->control
4541                                         & (SE_SACL_PRESENT
4542                                            | SE_SACL_DEFAULTED
4543                                            | SE_SACL_AUTO_INHERITED
4544                                            | SE_SACL_PROTECTED);
4545                         /*
4546                          * copy new OWNER if selected
4547                          * or keep old OWNER if any
4548                          */
4549                 if ((selection & OWNER_SECURITY_INFORMATION) ?
4550                                 newhead->owner : oldhead->owner) {
4551                         if (selection & OWNER_SECURITY_INFORMATION) {
4552                                 offowner = le32_to_cpu(newhead->owner);
4553                                 powner = (const SID*)&newattr[offowner];
4554                         } else {
4555                                 offowner = le32_to_cpu(oldhead->owner);
4556                                 powner = (const SID*)&oldattr[offowner];
4557                         }
4558                         size = ntfs_sid_size(powner);
4559                         memcpy(&target[pos], powner, size);
4560                         targhead->owner = cpu_to_le32(pos);
4561                         pos += size;
4562                 } else
4563                         targhead->owner = const_cpu_to_le32(0);
4564                 if (selection & OWNER_SECURITY_INFORMATION)
4565                         control |= newhead->control & SE_OWNER_DEFAULTED;
4566                 else
4567                         control |= oldhead->control & SE_OWNER_DEFAULTED;
4568                         /*
4569                          * copy new GROUP if selected
4570                          * or keep old GROUP if any
4571                          */
4572                 if ((selection & GROUP_SECURITY_INFORMATION) ?
4573                                 newhead->group : oldhead->group) {
4574                         if (selection & GROUP_SECURITY_INFORMATION) {
4575                                 offgroup = le32_to_cpu(newhead->group);
4576                                 pgroup = (const SID*)&newattr[offgroup];
4577                                 control |= newhead->control
4578                                                  & SE_GROUP_DEFAULTED;
4579                         } else {
4580                                 offgroup = le32_to_cpu(oldhead->group);
4581                                 pgroup = (const SID*)&oldattr[offgroup];
4582                                 control |= oldhead->control
4583                                                  & SE_GROUP_DEFAULTED;
4584                         }
4585                         size = ntfs_sid_size(pgroup);
4586                         memcpy(&target[pos], pgroup, size);
4587                         targhead->group = cpu_to_le32(pos);
4588                         pos += size;
4589                 } else
4590                         targhead->group = const_cpu_to_le32(0);
4591                 if (selection & GROUP_SECURITY_INFORMATION)
4592                         control |= newhead->control & SE_GROUP_DEFAULTED;
4593                 else
4594                         control |= oldhead->control & SE_GROUP_DEFAULTED;
4595                 targhead->revision = SECURITY_DESCRIPTOR_REVISION;
4596                 targhead->alignment = 0;
4597                 targhead->control = control;
4598                 ok = !update_secur_descr(vol, target, ni);
4599                 free(target);
4600         }
4601         return (ok);
4602 }
4603
4604 int ntfs_get_inode_security(ntfs_inode *ni, u32 selection,
4605                             char *buf, u32 buflen, u32 *psize)
4606 {
4607         int res;
4608         char *attr;
4609
4610         res = 0;
4611         if (ni) {
4612                 attr = getsecurityattr(ni->vol, ni);
4613                 if (attr) {
4614                         if (feedsecurityattr(attr, selection,
4615                                         buf, buflen, psize)) {
4616                                 if (test_nino_flag(ni, v3_Extensions)
4617                                     && ni->security_id)
4618                                         res = le32_to_cpu(
4619                                                 ni->security_id);
4620                                 else
4621                                         res = -1;
4622                         }
4623                         free(attr);
4624                 }
4625         } else
4626                 errno = EINVAL;
4627         return (res);
4628 }
4629
4630 int ntfs_set_inode_security(ntfs_inode *ni, u32 selection, const char *attr)
4631 {
4632         const SECURITY_DESCRIPTOR_RELATIVE *phead;
4633         int attrsz;
4634         BOOL missing;
4635         char *oldattr;
4636         int res;
4637
4638         res = -1; /* default return */
4639         if (ni) {
4640                 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4641                 attrsz = ntfs_attr_size(attr);
4642                 /* if selected, owner and group must be present or defaulted */
4643                 missing = ((selection & OWNER_SECURITY_INFORMATION)
4644                                 && !phead->owner
4645                                 && !(phead->control & SE_OWNER_DEFAULTED))
4646                         || ((selection & GROUP_SECURITY_INFORMATION)
4647                                 && !phead->group
4648                                 && !(phead->control & SE_GROUP_DEFAULTED));
4649                 if (!missing
4650                     && (phead->control & SE_SELF_RELATIVE)
4651                     && ntfs_valid_descr(attr, attrsz)) {
4652                         oldattr = getsecurityattr(ni->vol, ni);
4653                         if (oldattr) {
4654                                 if (mergesecurityattr(ni->vol, oldattr, attr,
4655                                                         selection, ni)) {
4656                                         res = 0;
4657                                 }
4658                                 free(oldattr);
4659                         }
4660                 } else
4661                         errno = EINVAL;
4662         } else
4663                 errno = EINVAL;
4664         return (res);
4665 }
4666
4667 /*
4668  *              Return the security descriptor of a file
4669  *      This is intended to be similar to GetFileSecurity() from Win32
4670  *      in order to facilitate the development of portable tools
4671  *
4672  *      returns zero if unsuccessful (following Win32 conventions)
4673  *              -1 if no securid
4674  *              the securid if any
4675  *
4676  *  The Win32 API is :
4677  *
4678  *  BOOL WINAPI GetFileSecurity(
4679  *    __in          LPCTSTR lpFileName,
4680  *    __in          SECURITY_INFORMATION RequestedInformation,
4681  *    __out_opt     PSECURITY_DESCRIPTOR pSecurityDescriptor,
4682  *    __in          DWORD nLength,
4683  *    __out         LPDWORD lpnLengthNeeded
4684  *  );
4685  *
4686  */
4687
4688 int ntfs_get_file_security(struct SECURITY_API *scapi,
4689                 const char *path, u32 selection,
4690                 char *buf, u32 buflen, u32 *psize)
4691 {
4692         ntfs_inode *ni;
4693         char *attr;
4694         int res;
4695
4696         res = 0; /* default return */
4697         if (scapi && (scapi->magic == MAGIC_API)) {
4698                 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4699                 if (ni) {
4700                         attr = getsecurityattr(scapi->security.vol, ni);
4701                         if (attr) {
4702                                 if (feedsecurityattr(attr,selection,
4703                                                 buf,buflen,psize)) {
4704                                         if (test_nino_flag(ni, v3_Extensions)
4705                                             && ni->security_id)
4706                                                 res = le32_to_cpu(
4707                                                         ni->security_id);
4708                                         else
4709                                                 res = -1;
4710                                 }
4711                                 free(attr);
4712                         }
4713                         ntfs_inode_close(ni);
4714                 } else
4715                         errno = ENOENT;
4716                 if (!res) *psize = 0;
4717         } else
4718                 errno = EINVAL; /* do not clear *psize */
4719         return (res);
4720 }
4721
4722
4723 /*
4724  *              Set the security descriptor of a file or directory
4725  *      This is intended to be similar to SetFileSecurity() from Win32
4726  *      in order to facilitate the development of portable tools
4727  *
4728  *      returns zero if unsuccessful (following Win32 conventions)
4729  *              -1 if no securid
4730  *              the securid if any
4731  *
4732  *  The Win32 API is :
4733  *
4734  *  BOOL WINAPI SetFileSecurity(
4735  *    __in          LPCTSTR lpFileName,
4736  *    __in          SECURITY_INFORMATION SecurityInformation,
4737  *    __in          PSECURITY_DESCRIPTOR pSecurityDescriptor
4738  *  );
4739  */
4740
4741 int ntfs_set_file_security(struct SECURITY_API *scapi,
4742                 const char *path, u32 selection, const char *attr)
4743 {
4744         const SECURITY_DESCRIPTOR_RELATIVE *phead;
4745         ntfs_inode *ni;
4746         int attrsz;
4747         BOOL missing;
4748         char *oldattr;
4749         int res;
4750
4751         res = 0; /* default return */
4752         if (scapi && (scapi->magic == MAGIC_API) && attr) {
4753                 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4754                 attrsz = ntfs_attr_size(attr);
4755                 /* if selected, owner and group must be present or defaulted */
4756                 missing = ((selection & OWNER_SECURITY_INFORMATION)
4757                                 && !phead->owner
4758                                 && !(phead->control & SE_OWNER_DEFAULTED))
4759                         || ((selection & GROUP_SECURITY_INFORMATION)
4760                                 && !phead->group
4761                                 && !(phead->control & SE_GROUP_DEFAULTED));
4762                 if (!missing
4763                     && (phead->control & SE_SELF_RELATIVE)
4764                     && ntfs_valid_descr(attr, attrsz)) {
4765                         ni = ntfs_pathname_to_inode(scapi->security.vol,
4766                                 NULL, path);
4767                         if (ni) {
4768                                 oldattr = getsecurityattr(scapi->security.vol,
4769                                                 ni);
4770                                 if (oldattr) {
4771                                         if (mergesecurityattr(
4772                                                 scapi->security.vol,
4773                                                 oldattr, attr,
4774                                                 selection, ni)) {
4775                                                 if (test_nino_flag(ni,
4776                                                             v3_Extensions))
4777                                                         res = le32_to_cpu(
4778                                                             ni->security_id);
4779                                                 else
4780                                                         res = -1;
4781                                         }
4782                                         free(oldattr);
4783                                 }
4784                                 ntfs_inode_close(ni);
4785                         }
4786                 } else
4787                         errno = EINVAL;
4788         } else
4789                 errno = EINVAL;
4790         return (res);
4791 }
4792
4793
4794 /*
4795  *              Return the attributes of a file
4796  *      This is intended to be similar to GetFileAttributes() from Win32
4797  *      in order to facilitate the development of portable tools
4798  *
4799  *      returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES)
4800  *
4801  *  The Win32 API is :
4802  *
4803  *  DWORD WINAPI GetFileAttributes(
4804  *   __in  LPCTSTR lpFileName
4805  *  );
4806  */
4807
4808 int ntfs_get_file_attributes(struct SECURITY_API *scapi, const char *path)
4809 {
4810         ntfs_inode *ni;
4811         s32 attrib;
4812
4813         attrib = -1; /* default return */
4814         if (scapi && (scapi->magic == MAGIC_API) && path) {
4815                 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4816                 if (ni) {
4817                         attrib = ntfs_get_inode_attributes(ni);
4818                         ntfs_inode_close(ni);
4819                 } else
4820                         errno = ENOENT;
4821         } else
4822                 errno = EINVAL; /* do not clear *psize */
4823         return (attrib);
4824 }
4825
4826
4827 /*
4828  *              Set attributes to a file or directory
4829  *      This is intended to be similar to SetFileAttributes() from Win32
4830  *      in order to facilitate the development of portable tools
4831  *
4832  *      Only a few flags can be set (same list as Win32)
4833  *
4834  *      returns zero if unsuccessful (following Win32 conventions)
4835  *              nonzero if successful
4836  *
4837  *  The Win32 API is :
4838  *
4839  *  BOOL WINAPI SetFileAttributes(
4840  *    __in  LPCTSTR lpFileName,
4841  *    __in  DWORD dwFileAttributes
4842  *  );
4843  */
4844
4845 BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi,
4846                 const char *path, s32 attrib)
4847 {
4848         ntfs_inode *ni;
4849         int res;
4850
4851         res = 0; /* default return */
4852         if (scapi && (scapi->magic == MAGIC_API) && path) {
4853                 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4854                 if (ni) {
4855                         /* Win32 convention here : -1 means successful */
4856                         if (!ntfs_set_inode_attributes(ni, attrib))
4857                                 res = -1;
4858                         if (ntfs_inode_close(ni))
4859                                 res = 0;
4860                 } else
4861                         errno = ENOENT;
4862         }
4863         return (res);
4864 }
4865
4866
4867 BOOL ntfs_read_directory(struct SECURITY_API *scapi,
4868                 const char *path, ntfs_filldir_t callback, void *context)
4869 {
4870         ntfs_inode *ni;
4871         BOOL ok;
4872         s64 pos;
4873
4874         ok = FALSE; /* default return */
4875         if (scapi && (scapi->magic == MAGIC_API) && callback) {
4876                 ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
4877                 if (ni) {
4878                         if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
4879                                 pos = 0;
4880                                 ntfs_readdir(ni,&pos,context,callback);
4881                                 ok = !ntfs_inode_close(ni);
4882                         } else {
4883                                 ntfs_inode_close(ni);
4884                                 errno = ENOTDIR;
4885                         }
4886                 } else
4887                         errno = ENOENT;
4888         } else
4889                 errno = EINVAL; /* do not clear *psize */
4890         return (ok);
4891 }
4892
4893 /*
4894  *              read $SDS (for auditing security data)
4895  *
4896  *      Returns the number or read bytes, or -1 if there is an error
4897  */
4898
4899 int ntfs_read_sds(struct SECURITY_API *scapi,
4900                 char *buf, u32 size, u32 offset)
4901 {
4902         int got;
4903
4904         got = -1; /* default return */
4905         if (scapi && (scapi->magic == MAGIC_API)) {
4906                 if (scapi->security.vol->secure_ni)
4907                         got = ntfs_attr_data_read(scapi->security.vol->secure_ni,
4908                                 STREAM_SDS, 4, buf, size, offset);
4909                 else
4910                         errno = EOPNOTSUPP;
4911         } else
4912                 errno = EINVAL;
4913         return (got);
4914 }
4915
4916 /*
4917  *              read $SII (for auditing security data)
4918  *
4919  *      Returns next entry, or NULL if there is an error
4920  */
4921
4922 INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
4923                 INDEX_ENTRY *entry)
4924 {
4925         SII_INDEX_KEY key;
4926         INDEX_ENTRY *ret;
4927         BOOL found;
4928         ntfs_index_context *xsii;
4929
4930         ret = (INDEX_ENTRY*)NULL; /* default return */
4931         if (scapi && (scapi->magic == MAGIC_API)) {
4932                 xsii = scapi->security.vol->secure_xsii;
4933                 if (xsii) {
4934                         if (!entry) {
4935                                 key.security_id = const_cpu_to_le32(0);
4936                                 found = !ntfs_index_lookup((char*)&key,
4937                                                 sizeof(SII_INDEX_KEY), xsii);
4938                                 /* not supposed to find */
4939                                 if (!found && (errno == ENOENT))
4940                                         ret = xsii->entry;
4941                         } else
4942                                 ret = ntfs_index_next(entry,xsii);
4943                         if (!ret)
4944                                 errno = ENODATA;
4945                 } else
4946                         errno = EOPNOTSUPP;
4947         } else
4948                 errno = EINVAL;
4949         return (ret);
4950 }
4951
4952 /*
4953  *              read $SDH (for auditing security data)
4954  *
4955  *      Returns next entry, or NULL if there is an error
4956  */
4957
4958 INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
4959                 INDEX_ENTRY *entry)
4960 {
4961         SDH_INDEX_KEY key;
4962         INDEX_ENTRY *ret;
4963         BOOL found;
4964         ntfs_index_context *xsdh;
4965
4966         ret = (INDEX_ENTRY*)NULL; /* default return */
4967         if (scapi && (scapi->magic == MAGIC_API)) {
4968                 xsdh = scapi->security.vol->secure_xsdh;
4969                 if (xsdh) {
4970                         if (!entry) {
4971                                 key.hash = const_cpu_to_le32(0);
4972                                 key.security_id = const_cpu_to_le32(0);
4973                                 found = !ntfs_index_lookup((char*)&key,
4974                                                 sizeof(SDH_INDEX_KEY), xsdh);
4975                                 /* not supposed to find */
4976                                 if (!found && (errno == ENOENT))
4977                                         ret = xsdh->entry;
4978                         } else
4979                                 ret = ntfs_index_next(entry,xsdh);
4980                         if (!ret)
4981                                 errno = ENODATA;
4982                 } else errno = ENOTSUP;
4983         } else
4984                 errno = EINVAL;
4985         return (ret);
4986 }
4987
4988 /*
4989  *              Get the mapped user SID
4990  *      A buffer of 40 bytes has to be supplied
4991  *
4992  *      returns the size of the SID, or zero and errno set if not found
4993  */
4994
4995 int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf)
4996 {
4997         const SID *usid;
4998         BIGSID defusid;
4999         int size;
5000
5001         size = 0;
5002         if (scapi && (scapi->magic == MAGIC_API)) {
5003                 usid = ntfs_find_usid(scapi->security.mapping[MAPUSERS], uid, (SID*)&defusid);
5004                 if (usid) {
5005                         size = ntfs_sid_size(usid);
5006                         memcpy(buf,usid,size);
5007                 } else
5008                         errno = ENODATA;
5009         } else
5010                 errno = EINVAL;
5011         return (size);
5012 }
5013
5014 /*
5015  *              Get the mapped group SID
5016  *      A buffer of 40 bytes has to be supplied
5017  *
5018  *      returns the size of the SID, or zero and errno set if not found
5019  */
5020
5021 int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf)
5022 {
5023         const SID *gsid;
5024         BIGSID defgsid;
5025         int size;
5026
5027         size = 0;
5028         if (scapi && (scapi->magic == MAGIC_API)) {
5029                 gsid = ntfs_find_gsid(scapi->security.mapping[MAPGROUPS], gid, (SID*)&defgsid);
5030                 if (gsid) {
5031                         size = ntfs_sid_size(gsid);
5032                         memcpy(buf,gsid,size);
5033                 } else
5034                         errno = ENODATA;
5035         } else
5036                 errno = EINVAL;
5037         return (size);
5038 }
5039
5040 /*
5041  *              Get the user mapped to a SID
5042  *
5043  *      returns the uid, or -1 if not found
5044  */
5045
5046 int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid)
5047 {
5048         int uid;
5049
5050         uid = -1;
5051         if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(usid)) {
5052                 if (ntfs_same_sid(usid,adminsid))
5053                         uid = 0;
5054                 else {
5055                         uid = ntfs_find_user(scapi->security.mapping[MAPUSERS], usid);
5056                         if (!uid) {
5057                                 uid = -1;
5058                                 errno = ENODATA;
5059                         }
5060                 }
5061         } else
5062                 errno = EINVAL;
5063         return (uid);
5064 }
5065
5066 /*
5067  *              Get the group mapped to a SID
5068  *
5069  *      returns the uid, or -1 if not found
5070  */
5071
5072 int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid)
5073 {
5074         int gid;
5075
5076         gid = -1;
5077         if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(gsid)) {
5078                 if (ntfs_same_sid(gsid,adminsid))
5079                         gid = 0;
5080                 else {
5081                         gid = ntfs_find_group(scapi->security.mapping[MAPGROUPS], gsid);
5082                         if (!gid) {
5083                                 gid = -1;
5084                                 errno = ENODATA;
5085                         }
5086                 }
5087         } else
5088                 errno = EINVAL;
5089         return (gid);
5090 }
5091
5092 /*
5093  *              Initializations before calling ntfs_get_file_security()
5094  *      ntfs_set_file_security() and ntfs_read_directory()
5095  *
5096  *      Only allowed for root
5097  *
5098  *      Returns an (obscured) struct SECURITY_API* needed for further calls
5099  *              NULL if not root (EPERM) or device is mounted (EBUSY)
5100  */
5101
5102 struct SECURITY_API *ntfs_initialize_file_security(const char *device,
5103                                 unsigned long flags)
5104 {
5105         ntfs_volume *vol;
5106         unsigned long mntflag;
5107         int mnt;
5108         struct SECURITY_API *scapi;
5109         struct SECURITY_CONTEXT *scx;
5110
5111         scapi = (struct SECURITY_API*)NULL;
5112         mnt = ntfs_check_if_mounted(device, &mntflag);
5113         if (!mnt && !(mntflag & NTFS_MF_MOUNTED) && !getuid()) {
5114                 vol = ntfs_mount(device, flags);
5115                 if (vol) {
5116                         scapi = (struct SECURITY_API*)
5117                                 ntfs_malloc(sizeof(struct SECURITY_API));
5118                         if (!ntfs_volume_get_free_space(vol)
5119                             && scapi) {
5120                                 scapi->magic = MAGIC_API;
5121                                 scapi->seccache = (struct PERMISSIONS_CACHE*)NULL;
5122                                 scx = &scapi->security;
5123                                 scx->vol = vol;
5124                                 scx->uid = getuid();
5125                                 scx->gid = getgid();
5126                                 scx->pseccache = &scapi->seccache;
5127                                 scx->vol->secure_flags = 0;
5128                                         /* accept no mapping and no $Secure */
5129                                 ntfs_build_mapping(scx,(const char*)NULL,TRUE);
5130                                 ntfs_open_secure(vol);
5131                         } else {
5132                                 if (scapi)
5133                                         free(scapi);
5134                                 else
5135                                         errno = ENOMEM;
5136                                 mnt = ntfs_umount(vol,FALSE);
5137                                 scapi = (struct SECURITY_API*)NULL;
5138                         }
5139                 }
5140         } else
5141                 if (getuid())
5142                         errno = EPERM;
5143                 else
5144                         errno = EBUSY;
5145         return (scapi);
5146 }
5147
5148 /*
5149  *              Leaving after ntfs_initialize_file_security()
5150  *
5151  *      Returns FALSE if FAILED
5152  */
5153
5154 BOOL ntfs_leave_file_security(struct SECURITY_API *scapi)
5155 {
5156         int ok;
5157         ntfs_volume *vol;
5158
5159         ok = FALSE;
5160         if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) {
5161                 vol = scapi->security.vol;
5162                 ntfs_close_secure(&scapi->security);
5163                 free(scapi);
5164                 if (!ntfs_umount(vol, 0))
5165                         ok = TRUE;
5166         }
5167         return (ok);
5168 }
5169