blob: 29236c6d5aaf7f331bb32fb3195a08d30690d9e1 [file] [log] [blame]
Steve Kondik2111ad72013-07-07 12:07:44 -07001/*
2 * Display and audit security attributes in an NTFS volume
3 *
Steve Kondike68cb602016-08-28 00:45:36 -07004 * Copyright (c) 2007-2015 Jean-Pierre Andre
Steve Kondik2111ad72013-07-07 12:07:44 -07005 *
6 * Options :
7 * -a auditing security data
8 * -b backing up NTFS ACLs
9 * -e set extra backed-up parameters (in conjunction with -s)
10 * -h displaying hexadecimal security descriptors within a file
11 * -r recursing in a directory
12 * -s setting backed-up NTFS ACLs
13 * -u getting a user mapping proposal
14 * -v verbose (very verbose if set twice)
15 * also, if compile-time option is set
16 * -t run internal tests (with no access to storage)
17 *
18 * On Linux (being root, with volume not mounted) :
19 * secaudit -h [file]
20 * display the security descriptors found in file
21 * secaudit -a[rv] volume
22 * audit the volume
23 * secaudit [-v] volume file
24 * display the security parameters of file
25 * secaudit -r[v] volume directory
26 * display the security parameters of files in directory
27 * secaudit -b[v] volume [directory]
28 * backup the security parameters of files in directory
29 * secaudit -s[ve] volume [backupfile]
30 * set the security parameters as indicated in backup
31 * with -e set extra parameters (Windows attrib)
32 * secaudit volume perms file
33 * set the security parameters of file to perms (mode or acl)
34 * secaudit -r[v] volume perms directory
35 * set the security parameters of files in directory to perms
36 * special case, does not require being root :
37 * secaudit [-v] mounted-file
38 * display the security parameters of mounted file
39 *
40 *
41 * On Windows (the volume being part of file name)
42 * secaudit -h [file]
43 * display the security descriptors found in file
44 * secaudit [-v] file
45 * display the security parameters of file
46 * secaudit -r[v] directory
47 * display the security parameters of files in directory
48 * secaudit -b[v] directory
49 * backup the security parameters of files in directory
50 * secaudit -s[v] [backupfile]
51 * set the security parameters as indicated in backup
52 * with -e set extra parameters (Windows attrib)
53 * secaudit perms file
54 * set the security parameters of file to perms (mode or acl)
55 * secaudit -r[v] perms directory
56 * set the security parameters of files in directory to perms
57 */
58
59/* History
60 *
61 * Nov 2007
62 * - first version, by concatenating miscellaneous utilities
63 *
64 * Jan 2008, version 1.0.1
65 * - fixed mode displaying
66 * - added a global severe errors count
67 *
68 * Feb 2008, version 1.0.2
69 * - implemented conversions for big-endian machines
70 *
71 * Mar 2008, version 1.0.3
72 * - avoided consistency checks on $Secure when there is no such file
73 *
74 * Mar 2008, version 1.0.4
75 * - changed ordering of ACE's
76 * - changed representation for special flags
77 * - defaulted to stdin for option -h
78 * - added self tests (compile time option)
79 * - fixed errors specific to big-endian computers
80 *
81 * Apr 2008, version 1.1.0
82 * - developped Posix ACLs to NTFS ACLs conversions
83 * - developped NTFS ACLs backup and restore
84 *
85 * Apr 2008, version 1.1.1
86 * - fixed an error specific to big-endian computers
87 * - checked hash value and fixed error report in restore
88 * - improved display in showhex() and restore()
89 *
90 * Apr 2008, version 1.1.2
91 * - improved and fixed Posix ACLs to NTFS ACLs conversions
92 *
93 * Apr 2008, version 1.1.3
94 * - reenabled recursion for setting a new mode or ACL
95 * - processed Unicode file names and displayed them as UTF-8
96 * - allocated dynamically memory for file names when recursing
97 *
98 * May 2008, version 1.1.4
99 * - all Unicode/UTF-8 strings checked and processed
100 *
101 * Jul 2008, version 1.1.5
102 * - made Windows owner consistent with Linux owner when changing mode
103 * - allowed owner change on Windows when it does not match Linux owner
104 * - skipped currently unused code
105 *
106 * Aug 2008, version 1.2.0
107 * - processed \.NTFS-3G\UserMapping on Windows
108 * - made use of user mappings through the security API or direct access
109 * - fixed a bug in restore
110 * - fixed UTF-8 conversions
111 *
112 * Sep 2008, version 1.3.0
113 * - split the code to have part of it shared with ntfs-3g library
114 * - fixed testing for end of SDS block
115 * - added samples checking in selftest for easier debugging
116 *
117 * Oct 2008, version 1.3.1
118 * - fixed outputting long long data when testing on a Palm organizer
119 *
120 * Dec 2008, version 1.3.2
121 * - fixed restoring ACLs
122 * - added optional logging of ACL hashes to facilitate restore checks
123 * - fixed collecting SACLs
124 * - fixed setting special control flags
125 * - fixed clearing existing SACLs (Linux only) and DACLs
126 * - changed the sequencing of items when quering a security descriptor
127 * - avoided recursing on junctions and symlinks on Windows
128 *
129 * Jan 2009, version 1.3.3
130 * - save/restore Windows attributes (code from Faisal)
131 *
132 * Mar 2009, version 1.3.4
133 * - enabled displaying attributes of a mounted file over Linux
134 *
135 * Apr 2009, version 1.3.5
136 * - fixed initialisation of stand-alone user mapping
137 * - fixed POSIXACL redefinition when included in the ntfs-3g package
138 * - fixed displaying of options
139 * - fixed a dependency on the shared library version used
140 *
141 * May 2009, version 1.3.6
142 * - added new samples for self testing
143 *
144 * Jun 2009, version 1.3.7
145 * - fixed displaying owner and group of a mounted file over Linux
146 *
147 * Jul 2009, version 1.3.8
148 * - fixed again displaying owner and group of a mounted file over Linux
149 * - cleaned some code to avoid warnings
150 *
151 * Nov 2009, version 1.3.9
152 * - allowed security descriptors up to 64K
153 *
154 * Nov 2009, version 1.3.10
155 * - applied patches for MacOSX from Erik Larsson
156 *
157 * Nov 2009, version 1.3.11
158 * - replace <attr/xattr.h> by <sys/xattr.h> (provided by glibc)
159 *
160 * Dec 2009, version 1.3.12
161 * - worked around "const" possibly redefined in config.h
162 *
163 * Dec 2009, version 1.3.13
164 * - fixed the return code of dorestore()
165 *
166 * Dec 2009, version 1.3.14
167 * - adapted to opensolaris
168 *
169 * Jan 2010, version 1.3.15
170 * - more adaptations to opensolaris
171 * - removed the fix for return code of dorestore()
172 *
173 * Jan 2010, version 1.3.16
174 * - repeated the fix for return code of dorestore()
175 *
176 * Mar 2010, version 1.3.17
177 * - adapted to new default user mapping
178 * - fixed #ifdef'd code for selftest
179 *
180 * May 2010, version 1.3.18
181 * - redefined early error logging
182 *
183 * Mar 2011, version 1.3.19
184 * - fixed interface to ntfs_initialize_file_security()
185 *
186 * Apr 2011, version 1.3.20
187 * - fixed false memory leak detection
188 *
189 * Jun 2011, version 1.3.21
190 * - cleaned a few unneeded variables
191 *
192 * Nov 2011, version 1.3.22
193 * - added a distinctive prefix to owner and group SID
194 * - fixed a false memory leak detection
195 *
196 * Jun 2012, version 1.3.23
197 * - added support for SACL (nickgarvey)
198 *
199 * Jul 2012, version 1.3.24
200 * - added self-tests for authenticated users
201 * - added display of ace-inherited flag
202 * - made runnable on OpenIndiana
203 *
204 * Aug 2012, version 1.4.0
205 * - added an option for user mapping proposal
Steve Kondik79165c32015-11-09 19:43:00 -0800206 *
207 * Sep 2013, version 1.4.1
208 * - silenced an aliasing warning by gcc >= 4.8
209 *
210 * May 2014, version 1.4.2
211 * - decoded GENERIC_ALL permissions
212 * - decoded more "well-known" and generic SIDs
213 * - showed Windows ownership in verbose situations
214 * - fixed apparent const violations
Steve Kondike68cb602016-08-28 00:45:36 -0700215 *
216 * Dec 2014, version 1.4.3
217 * - fixed displaying "UserMapping" as a file name
218 *
219 * Mar 2015, version 1.4.5
220 * - adapted to new NTFS ACLs when owner is same as group
221 *
222 * May 2015, version 1.4.6
223 * - made to load shared library based on generic name
Steve Kondik2111ad72013-07-07 12:07:44 -0700224 */
225
226/*
227 * This program is free software; you can redistribute it and/or modify
228 * it under the terms of the GNU General Public License as published by
229 * the Free Software Foundation; either version 2 of the License, or
230 * (at your option) any later version.
231 *
232 * This program is distributed in the hope that it will be useful,
233 * but WITHOUT ANY WARRANTY; without even the implied warranty of
234 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
235 * GNU General Public License for more details.
236 *
237 * You should have received a copy of the GNU General Public License
238 * along with this program (in the main directory of the NTFS-3G
239 * distribution in the file COPYING); if not, write to the Free Software
240 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
241 */
242
243/*
244 * General parameters which may have to be adapted to needs
245 */
246
Steve Kondike68cb602016-08-28 00:45:36 -0700247#define AUDT_VERSION "1.4.6"
Steve Kondik2111ad72013-07-07 12:07:44 -0700248
249#define GET_FILE_SECURITY "ntfs_get_file_security"
250#define SET_FILE_SECURITY "ntfs_set_file_security"
251#define GET_FILE_ATTRIBUTES "ntfs_get_file_attributes"
252#define SET_FILE_ATTRIBUTES "ntfs_set_file_attributes"
253#define READ_DIRECTORY "ntfs_read_directory"
254#define READ_SDS "ntfs_read_sds"
255#define READ_SII "ntfs_read_sii"
256#define READ_SDH "ntfs_read_sdh"
257#define GET_USER "ntfs_get_user"
258#define GET_GROUP "ntfs_get_group"
259#define GET_USID "ntfs_get_usid"
260#define GET_GSID "ntfs_get_gsid"
261#define INIT_FILE_SECURITY "ntfs_initialize_file_security"
262#define LEAVE_FILE_SECURITY "ntfs_leave_file_security"
263
264/*
265 * External declarations
266 */
267
268#include <stdio.h>
269#include <time.h>
270#include <string.h>
271#include <stdlib.h>
272#include <sys/types.h>
273#include <fcntl.h>
274#include <errno.h>
275#include <stdarg.h>
276
277 /*
278 * integration into secaudit, check whether Win32,
279 * may have to be adapted to compiler or something else
280 */
281
282#ifndef WIN32
283#if defined(__WIN32) | defined(__WIN32__) | defined(WNSC)
284#define WIN32 1
285#endif
286#endif
287
288 /*
289 * integration into secaudit/Win32
290 */
291#ifdef WIN32
292#include <windows.h>
293#define __LITTLE_ENDIAN 1234
294#define __BYTE_ORDER __LITTLE_ENDIAN
295#else
296 /*
297 * integration into secaudit/STSC
298 */
299#ifdef STSC
300#include <stat.h>
301#undef __BYTE_ORDER
302#define __BYTE_ORDER __BIG_ENDIAN
303#else
304 /*
305 * integration into secaudit/Linux
306 */
307
308#include <sys/stat.h>
309#ifdef HAVE_ENDIAN_H
310#include <endian.h>
311#endif
312#ifdef HAVE_MACHINE_ENDIAN_H
313#include <machine/endian.h>
314#endif
315#include <unistd.h>
316#include <dlfcn.h>
317#endif /* STSC */
318#endif /* WIN32 */
319#include "secaudit.h"
320
321#ifndef WIN32
322
323#ifndef STSC
324
325#if !defined(HAVE_CONFIG_H) && POSIXACLS && !defined(__SVR4)
326 /* require <sys/xattr.h> if not integrated into ntfs-3g package */
327#define HAVE_SETXATTR 1
328#endif
329
330#ifdef HAVE_CONFIG_H
331#ifdef _FILE_OFFSET_BITS
332#undef _FILE_OFFSET_BITS /* work around "_FILE_OFFSET_BITS" possibly already defined */
333#endif
334 /* <sys/xattr.h> according to config.h if integrated into ntfs-3g package */
335#include "config.h"
336#ifdef const /* work around "const" possibly redefined in config.h */
337#undef const
338#endif
339#ifndef POSIXACLS
340#define POSIXACLS 0
341#endif
342#endif /* HAVE_CONFIG_H */
343
344#ifdef HAVE_SETXATTR
345#include <sys/xattr.h>
346#else
347#warning "The extended attribute package is not available"
348#endif /* HAVE_SETXATTR */
349
350#endif /* STSC */
351
352#define NTFS_MNT_NONE 0 /* no flag for mounting the device */
353#define NTFS_MNT_RDONLY 1 /* flag for mounting the device read-only */
354
355struct CALLBACK;
356
357typedef int (*dircallback)(struct CALLBACK *context, char *ntfsname,
358 int length, int type, long long pos, u64 mft_ref,
359 unsigned int dt_type);
360
361#ifndef HAVE_SYSLOG_H
362void ntfs_log_early_error(const char *format, ...)
363 __attribute__((format(printf, 1, 2)));
364#endif
365
366#if USESTUBS | defined(STSC)
367
368int ntfs_get_file_security(void *scapi,
369 const char *path, DWORD selection,
370 char *buf, DWORD buflen, LPDWORD psize);
371BOOL ntfs_set_file_security(void *scapi,
372 const char *path, DWORD selection, const char *attr);
373int ntfs_get_file_attributes(void *scapi,
374 const char *path);
375BOOL ntfs_set_file_attributes(void *scapi,
376 const char *path, DWORD attrib);
377BOOL ntfs_read_directory(void *scapi,
378 const char *path, dircallback callback, void *context);
379int ntfs_read_sds(void *scapi,
380 char *buf, DWORD buflen, DWORD offset);
381void *ntfs_read_sii(void *scapi, void *entry);
382void *ntfs_read_sdh(void *scapi, void *entry);
383
384int ntfs_get_usid(void *scapi, uid_t uid, char *buf);
385int ntfs_get_gsid(void *scapi, gid_t gid, char *buf);
386int ntfs_get_user(void *scapi, const char *usid);
387int ntfs_get_group(void *scapi, const char *gsid);
388
389void *ntfs_initialize_file_security(const char *device, unsigned long flags);
390BOOL ntfs_leave_file_security(void *scapi);
391
392#else
393
394typedef int (*type_get_file_security)(void *scapi,
395 const char *path, DWORD selection,
396 char *buf, DWORD buflen, LPDWORD psize);
397typedef BOOL (*type_set_file_security)(void *scapi,
398 const char *path, DWORD selection, const char *attr);
399typedef int (*type_get_file_attributes)(void *scapi,
400 const char *path);
401typedef BOOL (*type_set_file_attributes)(void *scapi,
402 const char *path, DWORD attrib);
403typedef BOOL (*type_read_directory)(void *scapi,
404 const char *path, dircallback callback, void *context);
405typedef int (*type_read_sds)(void *scapi,
406 char *buf, DWORD buflen, DWORD offset);
407typedef void *(*type_read_sii)(void *scapi, void *entry);
408typedef void *(*type_read_sdh)(void *scapi, void *entry);
409
410typedef int (*type_get_usid)(void *scapi, uid_t uid, char *buf);
411typedef int (*type_get_gsid)(void *scapi, gid_t gid, char *buf);
412typedef int (*type_get_user)(void *scapi, const char *usid);
413typedef int (*type_get_group)(void *scapi, const char *gsid);
414
415typedef void *(*type_initialize_file_security)(const char *device,
416 unsigned long flags);
417typedef BOOL (*type_leave_file_security)(void *scapi);
418
419type_get_file_security ntfs_get_file_security;
420type_set_file_security ntfs_set_file_security;
421type_get_file_attributes ntfs_get_file_attributes;
422type_set_file_attributes ntfs_set_file_attributes;
423type_read_directory ntfs_read_directory;
424type_read_sds ntfs_read_sds;
425type_read_sii ntfs_read_sii;
426type_read_sdh ntfs_read_sdh;
427
428type_get_usid ntfs_get_usid;
429type_get_gsid ntfs_get_gsid;
430type_get_user ntfs_get_user;
431type_get_group ntfs_get_group;
432
433type_initialize_file_security ntfs_initialize_file_security;
434type_leave_file_security ntfs_leave_file_security;
435
436
437#endif /* USESTUBS | defined(STSC) */
438#endif /* WIN32 */
439
Steve Kondik79165c32015-11-09 19:43:00 -0800440#define ACCOUNTSIZE 256 /* maximum size of an account name */
441
Steve Kondik2111ad72013-07-07 12:07:44 -0700442/*
443 * Prototypes for local functions
444 */
445
446BOOL open_security_api(void);
447BOOL close_security_api(void);
448#ifndef WIN32
449BOOL open_volume(const char*, unsigned long flags);
450BOOL close_volume(const char*);
451#endif
452unsigned int get2l(const char*, int);
453unsigned long get4l(const char*, int);
454u64 get6l(const char*, int);
455u64 get6h(const char*, int);
456u64 get8l(const char*, int);
457void set2l(char*, unsigned int);
458void set4l(char*, unsigned long);
459void hexdump(const char*, int, int);
460u32 hash(const le32*, int);
461unsigned int utf8size(const char*, int);
462unsigned int makeutf8(char*, const char*, int);
463unsigned int utf16size(const char*);
464unsigned int makeutf16(char*, const char*);
465unsigned int utf16len(const char*);
466void printname(FILE*, const char*);
467void printerror(FILE*);
468BOOL guess_dir(const char*);
469void showsid(const char*, int, const char*, int);
470void showusid(const char*, int);
471void showgsid(const char*, int);
Steve Kondik79165c32015-11-09 19:43:00 -0800472void showownership(const char*);
Steve Kondik2111ad72013-07-07 12:07:44 -0700473void showheader(const char*, int);
474void showace(const char*, int, int, int);
475void showacl(const char*, int, int, int);
476void showdacl(const char*, int, int);
477void showsacl(const char*, int, int);
478void showall(const char*, int);
479void showposix(const struct POSIX_SECURITY*);
480int linux_permissions(const char*, BOOL);
481uid_t linux_owner(const char*);
482gid_t linux_group(const char*);
483int basicread(void*, char*, size_t, off_t);
484int dummyread(void*, char*, size_t, off_t);
485int local_build_mapping(struct MAPPING *[], const char*);
486void newblock(s32);
487void freeblocks(void);
488u32 getmsbhex(const char*);
489u32 getlsbhex(const char*);
490BOOL ishexdump(const char*, int, int);
491void showhex(FILE*);
492void showfull(const char*, BOOL);
493BOOL applyattr(const char*, const char*, BOOL, int, s32);
494BOOL restore(FILE*);
495BOOL dorestore(const char*, FILE*);
496u32 merge_rights(const struct POSIX_SECURITY*, BOOL);
497void tryposix(struct POSIX_SECURITY*);
498void check_samples(void);
499void basictest(int, BOOL, const SID*, const SID*);
500void posixtest(int, BOOL, const SID*, const SID*);
501void selftests(void);
502unsigned int getfull(char*, const char*);
503BOOL updatefull(const char *name, DWORD flags, char *attr);
504BOOL setfull(const char*, int, BOOL);
505BOOL singleshow(const char*);
506BOOL proposal(const char*, const char*);
507BOOL showmounted(const char*);
508BOOL processmounted(const char*);
509BOOL recurseshow(const char*);
510BOOL singleset(const char*, int);
511BOOL recurseset(const char*, int);
512#ifdef WIN32
513BOOL backup(const char*);
514BOOL listfiles(const char*);
515#if POSIXACLS
516BOOL iterate(RECURSE, const char*, const struct POSIX_SECURITY*);
517#else
518BOOL iterate(RECURSE, const char*, mode_t);
519#endif
520#else
521BOOL backup(const char*, const char*);
522BOOL listfiles(const char*, const char*);
523BOOL mapproposal(const char*, const char*);
524#endif
525#if POSIXACLS
526BOOL setfull_posix(const char *, const struct POSIX_SECURITY*, BOOL);
527struct POSIX_SECURITY *linux_permissions_posix(const char*, BOOL);
528BOOL recurseset_posix(const char*, const struct POSIX_SECURITY*);
529BOOL singleset_posix(const char*, const struct POSIX_SECURITY*);
530struct POSIX_SECURITY *encode_posix_acl(const char*);
531#endif
532static void *stdmalloc(size_t);
533static void stdfree(void*);
534
535BOOL valid_sds(const char*, unsigned int, unsigned int,
536 unsigned int, u32, BOOL);
537BOOL valid_sii(const char*, u32);
538BOOL valid_sdh(const char*, u32, u32);
539int consist_sds(const char*, unsigned int, unsigned int, BOOL);
540int consist_sii(const char*);
541int consist_sdh(const char*);
542int audit_sds(BOOL);
543int audit_sii(void);
544int audit_sdh(void);
545void audit_summary(void);
546BOOL audit(const char*);
547int getoptions(int, char*[]);
548
549#ifndef WIN32
550
551/*
552 * Structures for collecting directory contents (Linux only)
553 */
554
555struct LINK {
556 struct LINK *next;
557 char name[1];
558} ;
559
560struct CALLBACK {
561 struct LINK *head;
562 const char *dir;
563} ;
564
565int callback(struct CALLBACK *context, char *ntfsname,
566 int length, int type, long long pos, u64 mft_ref,
567 unsigned int dt_type);
568#endif
569
570/*
571 * Global constants
572 */
573
574#define BANNER "secaudit " AUDT_VERSION " : NTFS security data auditing"
575
576#if SELFTESTS & !USESTUBS
577
578/*
579 * Dummy mapping file (self tests only)
580 */
581
582#define DUMMYAUTH "S-1-5-21-3141592653-589793238-462843383-"
583char dummymapping[] = "500::" DUMMYAUTH "1000\n"
584 "501::" DUMMYAUTH "1001\n"
585 "502::" DUMMYAUTH "1002\n"
586 "503::" DUMMYAUTH "1003\n"
587 "516::" DUMMYAUTH "1016\n"
588 ":500:" DUMMYAUTH "513\r\n"
589 ":511:S-1-5-21-1607551490-981732888-1819828000-513\n"
590 ":516:" DUMMYAUTH "1012\r\n"
591 "::" DUMMYAUTH "10000\n";
592
593/*
594 * SID for world (S-1-1-0)
595 */
596
597static const char worldsidbytes[] = {
598 1, /* revision */
599 1, /* auth count */
600 0, 0, 0, 0, 0, 1, /* base */
601 0, 0, 0, 0 /* 1st level */
602} ;
603static const SID *worldsid = (const SID*)worldsidbytes;
604
605/*
606 * SID for authenticated user (S-1-5-11)
607 */
608
609static const char authsidbytes[] = {
610 1, /* revision */
611 1, /* auth count */
612 0, 0, 0, 0, 0, 5, /* base */
613 11, 0, 0, 0 /* 1st level */
614};
615
616static const SID *authsid = (const SID*)authsidbytes;
617
618/*
619 * SID for administrator (S-1-5-32-544)
620 */
621
622static const char adminsidbytes[] = {
623 1, /* revision */
624 2, /* auth count */
625 0, 0, 0, 0, 0, 5, /* base */
626 32, 0, 0, 0, /* 1st level */
627 32, 2, 0, 0 /* 2nd level */
628};
629
630static const SID *adminsid = (const SID*)adminsidbytes;
631
632/*
633 * SID for local users (S-1-5-32-545)
634 */
635
636static const char localsidbytes[] = {
637 1, /* revision */
638 2, /* auth count */
639 0, 0, 0, 0, 0, 5, /* base */
640 32, 0, 0, 0, /* 1st level */
641 33, 2, 0, 0 /* 2nd level */
642};
643
644static const SID *localsid = (const SID*)localsidbytes;
645
646/*
647 * SID for system (S-1-5-18)
648 */
649
650static const char systemsidbytes[] = {
651 1, /* revision */
652 1, /* auth count */
653 0, 0, 0, 0, 0, 5, /* base */
654 18, 0, 0, 0 /* 1st level */
655 };
656
657static const SID *systemsid = (const SID*)systemsidbytes;
658
659#endif
660
661/*
662 * Global variables
663 */
664
665BOOL opt_a; /* audit security data */
666BOOL opt_b; /* backup NTFS ACLs */
667BOOL opt_e; /* restore extra (currently windows attribs) */
668BOOL opt_h; /* display an hexadecimal descriptor in a file */
669BOOL opt_r; /* recursively apply to subdirectories */
670BOOL opt_s; /* restore NTFS ACLs */
671BOOL opt_u; /* user mapping proposal */
672#if SELFTESTS & !USESTUBS
673BOOL opt_t; /* run self-tests */
674#endif
675int opt_v; /* verbose or very verbose*/
676struct SECURITY_DATA *securdata[(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ)];
677#if FORCEMASK
678BOOL opt_m; /* force a mask - dangerous */
679u32 forcemsk /* mask to force */
680#endif
681unsigned int errors; /* number of severe errors */
682unsigned int warnings; /* number of non-severe errors */
683
684struct CHKALLOC *firstalloc;
685struct SECURITY_CONTEXT context;
686MAPTYPE mappingtype;
687
688#ifdef STSC
689#define static
690#endif
691
692#ifndef WIN32
693
694void *ntfs_handle;
695void *ntfs_context = (void*)NULL;
696
697/*
698 * Open and close the security API (platform dependent)
699 */
700
701BOOL open_security_api(void)
702{
703#if USESTUBS | defined(STSC)
704 return (TRUE);
705#else
706 char *error;
707 BOOL err;
708 const char *libfile;
709
710 err = TRUE;
711 libfile = getenv(ENVNTFS3G);
712 if (!libfile)
713 libfile = (sizeof(char*) == 8 ? LIBFILE64 : LIBFILE);
714#ifdef __SVR4
715 /* do not override library functions by caller ones */
716 ntfs_handle = dlopen(libfile,RTLD_LAZY | RTLD_GROUP);
717#else
718 ntfs_handle = dlopen(libfile,RTLD_LAZY);
719#endif
720 if (ntfs_handle) {
721 ntfs_initialize_file_security = (type_initialize_file_security)
722 dlsym(ntfs_handle,INIT_FILE_SECURITY);
723 error = dlerror();
724 if (error)
725 fprintf(stderr," %s\n",error);
726 else {
727 ntfs_leave_file_security = (type_leave_file_security)
728 dlsym(ntfs_handle,LEAVE_FILE_SECURITY);
729 ntfs_get_file_security = (type_get_file_security)
730 dlsym(ntfs_handle,GET_FILE_SECURITY);
731 ntfs_set_file_security = (type_set_file_security)
732 dlsym(ntfs_handle,SET_FILE_SECURITY);
733 ntfs_get_file_attributes = (type_get_file_attributes)
734 dlsym(ntfs_handle,GET_FILE_ATTRIBUTES);
735 ntfs_set_file_attributes = (type_set_file_attributes)
736 dlsym(ntfs_handle,SET_FILE_ATTRIBUTES);
737 ntfs_read_directory = (type_read_directory)
738 dlsym(ntfs_handle,READ_DIRECTORY);
739 ntfs_read_sds = (type_read_sds)
740 dlsym(ntfs_handle,READ_SDS);
741 ntfs_read_sii = (type_read_sii)
742 dlsym(ntfs_handle,READ_SII);
743 ntfs_read_sdh = (type_read_sdh)
744 dlsym(ntfs_handle,READ_SDH);
745 ntfs_get_user = (type_get_user)
746 dlsym(ntfs_handle,GET_USER);
747 ntfs_get_group = (type_get_group)
748 dlsym(ntfs_handle,GET_GROUP);
749 ntfs_get_usid = (type_get_usid)
750 dlsym(ntfs_handle,GET_USID);
751 ntfs_get_gsid = (type_get_gsid)
752 dlsym(ntfs_handle,GET_GSID);
753 err = !ntfs_initialize_file_security
754 || !ntfs_leave_file_security
755 || !ntfs_get_file_security
756 || !ntfs_set_file_security
757 || !ntfs_get_file_attributes
758 || !ntfs_set_file_attributes
759 || !ntfs_read_directory
760 || !ntfs_read_sds
761 || !ntfs_read_sii
762 || !ntfs_read_sdh
763 || !ntfs_get_user
764 || !ntfs_get_group
765 || !ntfs_get_usid
766 || !ntfs_get_gsid;
767
768 if (error)
769 fprintf(stderr,"ntfs-3g API not available\n");
770 }
771 } else {
772 fprintf(stderr,"Could not open ntfs-3g library\n");
773 fprintf(stderr,"\nPlease set environment variable \"" ENVNTFS3G "\"\n");
774 fprintf(stderr,"to appropriate path and retry\n");
775 }
776 return (!err);
777#endif /* USESTUBS | defined(STSC) */
778}
779
780BOOL close_security_api(void)
781{
782#if USESTUBS | defined(STSC)
783 return (0);
784#else
785 return (!dlclose(ntfs_handle));
786#endif /* USESTUBS | defined(STSC) */
787}
788
789/*
790 * Open and close a volume (platform dependent)
791 * Assumes a single volume is opened
792 */
793
794BOOL open_volume(const char *volume, unsigned long flags)
795{
796 BOOL ok;
797
798 ok = FALSE;
799 if (!ntfs_context) {
800 ntfs_context = ntfs_initialize_file_security(volume,flags);
801 if (ntfs_context) {
802 if (*(u32*)ntfs_context != MAGIC_API) {
803 fprintf(stderr,"Versions of ntfs-3g and secaudit"
804 " are not compatible\n");
805 } else {
806 fprintf(stderr,"\"%s\" opened\n",volume);
807 mappingtype = MAPEXTERN;
808 ok = TRUE;
809 }
810 } else {
811 fprintf(stderr,"Could not open \"%s\"\n",volume);
812 fprintf(stderr,"Make sure \"%s\" is not mounted\n",volume);
813 }
814 } else
815 fprintf(stderr,"A volume is already open\n");
816 return (ok);
817}
818
819BOOL close_volume(const char *volume)
820{
821 BOOL r;
822
823 r = ntfs_leave_file_security(ntfs_context);
824 if (r)
825 fprintf(stderr,"\"%s\" closed\n",volume);
826 else
827 fprintf(stderr,"Could not close \"%s\"\n",volume);
828 ntfs_context = (void*)NULL;
829 return (r);
830}
831
832#endif /* WIN32 */
833
834/*
835 * Extract small or big endian data from an array of bytes
836 */
837
838unsigned int get2l(const char *attr, int p)
839{
840 int i;
841 unsigned int v;
842
843 v = 0;
844 for (i=0; i<2; i++)
845 v += (attr[p+i] & 255) << (8*i);
846 return (v);
847}
848
849unsigned long get4l(const char *attr, int p)
850{
851 int i;
852 unsigned long v;
853
854 v = 0;
855 for (i=0; i<4; i++)
856 v += ((long)(attr[p+i] & 255)) << (8*i);
857 return (v);
858}
859
860u64 get6l(const char *attr, int p)
861{
862 int i;
863 u64 v;
864
865 v = 0;
866 for (i=0; i<6; i++)
867 v += ((long long)(attr[p+i] & 255)) << (8*i);
868 return (v);
869}
870
871u64 get6h(const char *attr, int p)
872{
873 int i;
874 u64 v;
875
876 v = 0;
877 for (i=0; i<6; i++)
878 v = (v << 8) + (attr[p+i] & 255);
879 return (v);
880}
881
882u64 get8l(const char *attr, int p)
883{
884 int i;
885 u64 v;
886
887 v = 0;
888 for (i=0; i<8; i++)
889 v += ((long long)(attr[p+i] & 255)) << (8*i);
890 return (v);
891}
892
893/*
894 * Set small or big endian data into an array of bytes
895 */
896
897void set2l(char *p, unsigned int v)
898{
899 int i;
900
901 for (i=0; i<2; i++)
902 p[i] = ((v >> 8*i) & 255);
903}
904
905void set4l(char *p, unsigned long v)
906{
907 int i;
908
909 for (i=0; i<4; i++)
910 p[i] = ((v >> 8*i) & 255);
911}
912
913
914/*
915 * hexadecimal dump of an array of bytes
916 */
917
918void hexdump(const char *attr, int size, int level)
919{
920 int i,j;
921
922 for (i=0; i<size; i+=16) {
923 if (level)
924 printf("%*c",level,' ');
925 printf("%06x ",i);
926 for (j=i; (j<(i+16)) && (j<size); j++)
927 printf((j & 3 ? "%02x" : " %02x"),attr[j] & 255);
928 printf("\n");
929 }
930}
931
932u32 hash(const le32 *buf, int size /* bytes */)
933{
934 u32 h;
935 int i;
936
937 h = 0;
938 for (i=0; 4*i<size; i++)
939 h = le32_to_cpu(buf[i]) + (h << 3) + ((h >> 29) & 7);
940 return (h);
941}
942
943/*
944 * Evaluate the size of UTS-8 conversion of a UTF-16LE text
945 * trailing '\0' not accounted for
946 * Returns 0 for invalid input
947 */
948
949unsigned int utf8size(const char *utf16, int length)
950{
951 int i;
952 unsigned int size;
953 enum { BASE, SURR, ERR } state;
954
955 size = 0;
956 state = BASE;
957 for (i=0; i<2*length; i+=2) {
958 switch (state) {
959 case BASE :
960 if (utf16[i+1] & 0xf8) {
961 if ((utf16[i+1] & 0xf8) == 0xd8)
962 state = (utf16[i+1] & 4 ? ERR : SURR);
963 else
964#if NOREVBOM
965 if (((utf16[i+1] & 0xff) == 0xff)
966 && ((utf16[i] & 0xfe) == 0xfe))
967 state = ERR;
968 else
969 size += 3;
970#else
971 size += 3;
972#endif
973 } else
974 if ((utf16[i] & 0x80) || utf16[i+1])
975 size += 2;
976 else
977 size++;
978 break;
979 case SURR :
980 if ((utf16[i+1] & 0xfc) == 0xdc) {
981 state = BASE;
982 size += 4;
983 } else
984 state = ERR;
985 break;
986 case ERR :
987 break;
988 }
989 }
990 if (state != BASE)
991 size = 0;
992 return (size);
993}
994
995/*
996 * Convert a UTF-16LE text to UTF-8
997 * Note : wcstombs() not used because on Linux it fails for characters
998 * not present in current locale
999 * Returns size or zero for invalid input
1000 */
1001
1002unsigned int makeutf8(char *utf8, const char *utf16, int length)
1003{
1004 int i;
1005 unsigned int size;
1006 unsigned int rem;
1007 enum { BASE, SURR, ERR } state;
1008
1009 size = 0;
1010 rem = 0;
1011 state = BASE;
1012 for (i=0; i<2*length; i+=2) {
1013 switch (state) {
1014 case BASE :
1015 if (utf16[i+1] & 0xf8) {
1016 if ((utf16[i+1] & 0xf8) == 0xd8) {
1017 if (utf16[i+1] & 4)
1018 state = ERR;
1019 else {
1020 utf8[size++] = 0xf0 + (utf16[i+1] & 7)
1021 + ((utf16[i] & 0xc0) == 0xc0);
1022 utf8[size++] = 0x80 + (((utf16[i] + 64) >> 2) & 63);
1023 rem = utf16[i] & 3;
1024 state = SURR;
1025 }
1026 } else {
1027#if NOREVBOM
1028 if (((utf16[i+1] & 0xff) == 0xff)
1029 && ((utf16[i] & 0xfe) == 0xfe))
1030 state = ERR;
1031 else {
1032 utf8[size++] = 0xe0 + ((utf16[i+1] >> 4) & 15);
1033 utf8[size++] = 0x80
1034 + ((utf16[i+1] & 15) << 2)
1035 + ((utf16[i] >> 6) & 3);
1036 utf8[size++] = 0x80 + (utf16[i] & 63);
1037 }
1038#else
1039 utf8[size++] = 0xe0 + ((utf16[i+1] >> 4) & 15);
1040 utf8[size++] = 0x80
1041 + ((utf16[i+1] & 15) << 2)
1042 + ((utf16[i] >> 6) & 3);
1043 utf8[size++] = 0x80 + (utf16[i] & 63);
1044#endif
1045 }
1046 } else
1047 if ((utf16[i] & 0x80) || utf16[i+1]) {
1048 utf8[size++] = 0xc0
1049 + ((utf16[i+1] & 15) << 2)
1050 + ((utf16[i] >> 6) & 3);
1051 utf8[size++] = 0x80 + (utf16[i] & 63);
1052 } else
1053 utf8[size++] = utf16[i];
1054 break;
1055 case SURR :
1056 if ((utf16[i+1] & 0xfc) == 0xdc) {
1057 utf8[size++] = 0x80 + (rem << 4)
1058 + ((utf16[i+1] & 3) << 2)
1059 + ((utf16[i] >> 6) & 3);
1060 utf8[size++] = 0x80 + (utf16[i] & 63);
1061 state = BASE;
1062 } else
1063 state = ERR;
1064 break;
1065 case ERR :
1066 break;
1067 }
1068 }
1069 utf8[size] = 0;
1070 if (state != BASE)
1071 state = ERR;
1072 return (state == ERR ? 0 : size);
1073}
1074
1075#ifdef WIN32
1076
1077/*
1078 * Evaluate the size of UTF-16LE conversion of a UTF-8 text
1079 * (basic conversions only)
1080 * trailing '\0' not accounted for
1081 */
1082
1083unsigned int utf16size(const char *utf8)
1084{
1085 unsigned int size;
1086 const char *p;
1087 int c;
1088 unsigned int code;
1089 enum { BASE, TWO, THREE, THREE2, THREE3, FOUR, ERR } state;
1090
1091 p = utf8;
1092 size = 0;
1093 state = BASE;
1094 while (*p) {
1095 c = *p++ & 255;
1096 switch (state) {
1097 case BASE :
1098 if (!(c & 0x80))
1099 size++;
1100 else
1101 if (c < 0xc2)
1102 state = ERR;
1103 else
1104 if (c < 0xe0)
1105 state = TWO;
1106 else
1107 if (c < 0xf0) {
1108 if (c == 0xe0)
1109 state = THREE2;
1110 else
1111 if (c == 0xed)
1112 state = THREE3;
1113 else
1114 state = THREE;
1115 } else
1116 if (c < 0xf8) {
1117 state = FOUR;
1118 code = c & 7;
1119 } else
1120 state = ERR;
1121 break;
1122 case TWO :
1123 if ((c & 0xc0) != 0x80)
1124 state = ERR;
1125 else {
1126 size++;
1127 state = BASE;
1128 }
1129 break;
1130 case THREE :
1131 if ((c & 0xc0) != 0x80)
1132 state = ERR;
1133 else
1134 state = TWO;
1135 break;
1136 case THREE2 :
1137 if ((c & 0xe0) != 0xa0)
1138 state = ERR;
1139 else
1140 state = TWO;
1141 break;
1142 case THREE3 :
1143 if ((c & 0xe0) != 0x80)
1144 state = ERR;
1145 else
1146 state = TWO;
1147 break;
1148 case FOUR :
1149 if ((((code << 6) + (c & 63)) > 0x10f)
1150 || (((code << 6) + (c & 63)) < 0x10))
1151 state = ERR;
1152 else {
1153 size++;
1154 state = THREE;
1155 }
1156 break;
1157 case ERR :
1158 break;
1159 }
1160 }
1161 if (state != BASE) size = 0;
1162 return (size);
1163}
1164
1165/*
1166 * Convert a UTF8 text to UTF-16LE
1167 * (basic conversions only)
1168 * Note : mbstowcs() not used because on Linux it fails for characters
1169 * not present in current locale
1170 */
1171
1172unsigned int makeutf16(char *target, const char *utf8)
1173{
1174 unsigned int size;
1175 unsigned int code;
1176 const char *p;
1177 int c;
1178 enum { BASE, TWO, THREE, THREE2, THREE3, FOUR, FOUR2, FOUR3, ERR } state;
1179
1180 p = utf8;
1181 size = 0;
1182 c = 0;
1183 state = BASE;
1184 while (*p) {
1185 c = *p++ & 255;
1186 switch (state) {
1187 case BASE :
1188 if (!(c & 0x80)) {
1189 target[2*size] = c;
1190 target[2*size + 1] = 0;
1191 size++;
1192 } else {
1193 if (c < 0xc2)
1194 state = ERR;
1195 else
1196 if (c < 0xe0) {
1197 code = c & 31;
1198 state = TWO;
1199 } else
1200 if (c < 0xf0) {
1201 code = c & 15;
1202 if (c == 0xe0)
1203 state = THREE2;
1204 else
1205 if (c == 0xed)
1206 state = THREE3;
1207 else
1208 state = THREE;
1209 } else
1210 if (c < 0xf8) {
1211 code = c & 7;
1212 state = FOUR;
1213 } else
1214 state = ERR;
1215 }
1216 break;
1217 case TWO :
1218#if NOREVBOM
1219 if (((c & 0xc0) != 0x80)
1220 || ((code == 0x3ff) && (c >= 0xbe)))
1221#else
1222 if ((c & 0xc0) != 0x80)
1223#endif
1224 state = ERR;
1225 else {
1226 target[2*size] = ((code & 3) << 6) + (c & 63);
1227 target[2*size + 1] = ((code >> 2) & 255);
1228 size++;
1229 state = BASE;
1230 }
1231 break;
1232 case THREE :
1233 if ((c & 0xc0) != 0x80)
1234 state = ERR;
1235 else {
1236 code = ((code & 15) << 6) + (c & 63);
1237 state = TWO;
1238 }
1239 break;
1240 case THREE2 :
1241 if ((c & 0xe0) != 0xa0)
1242 state = ERR;
1243 else {
1244 code = ((code & 15) << 6) + (c & 63);
1245 state = TWO;
1246 }
1247 break;
1248 case THREE3 :
1249 if ((c & 0xe0) != 0x80)
1250 state = ERR;
1251 else {
1252 code = ((code & 15) << 6) + (c & 63);
1253 state = TWO;
1254 }
1255 break;
1256 case FOUR :
1257 if ((c & 0xc0) != 0x80)
1258 state = ERR;
1259 else {
1260 code = (code << 6) + (c & 63);
1261 state = FOUR2;
1262 }
1263 break;
1264 case FOUR2 :
1265 if ((c & 0xc0) != 0x80)
1266 state = ERR;
1267 else {
1268 code = (code << 6) + (c & 63);
1269 state = FOUR3;
1270 }
1271 break;
1272 case FOUR3 :
1273 if ((code > 0x43ff)
1274 || (code < 0x400)
1275 || ((c & 0xc0) != 0x80))
1276 state = ERR;
1277 else {
1278 target[2*size] = ((code - 0x400) >> 4) & 255;
1279 target[2*size+1] = 0xd8 + (((code - 0x400) >> 12) & 3);
1280 target[2*size+2] = ((code & 3) << 6) + (c & 63);
1281 target[2*size+3] = 0xdc + ((code >> 2) & 3);
1282 size += 2;
1283 state = BASE;
1284 }
1285 break;
1286 case ERR :
1287 break;
1288 }
1289 }
1290 if (state != BASE)
1291 size = 0;
1292 target[2*size] = 0;
1293 target[2*size + 1] = 0;
1294 return (size);
1295}
1296
1297unsigned int utf16len(const char *str)
1298{
1299 unsigned int len;
1300
1301 len = 0;
1302 while (str[2*len] || str[2*len+1]) len++;
1303 return (len);
1304}
1305
1306#endif
1307
1308/*
1309 * Print a file name
1310 * on Windows it prints UTF-16LE names as UTF-8
1311 */
1312
1313void printname(FILE *file, const char *name)
1314{
1315#ifdef WIN32
1316 char utf8name[MAXFILENAME];
1317
1318 makeutf8(utf8name,name,utf16len(name));
1319 fprintf(file,"%s",utf8name);
1320#else
1321 fprintf(file,"%s",name);
1322#endif
1323}
1324
1325/*
1326 * Print the last error code
1327 */
1328
1329void printerror(FILE *file)
1330{
1331#ifdef WIN32
1332 int err;
1333 const char *txt;
1334
1335 err = GetLastError();
1336 switch (err) {
1337 case 5 :
1338 txt = "Access to security descriptor was denied";
1339 break;
1340 case 1307 :
1341 txt = "This SID may not be assigned as the owner of this object";
1342 break;
1343 case 1308 :
1344 txt = "This SID may not be assigned as the group of this object";
1345 break;
1346 case 1314 :
1347 txt = "You do not have the privilege to change this SID";
1348 break;
1349 default :
1350 txt = (const char*)NULL;
1351 break;
1352 }
1353 if (txt)
1354 fprintf(file,"Error %d : %s\n",err,txt);
1355 else
1356 fprintf(file,"Error %d\n",err);
1357#else
1358#ifdef STSC
1359 if (errno) fprintf(file,"Error code %d\n",errno);
1360#else
1361 if (errno) fprintf(file,"Error code %d : %s\n",errno,strerror(errno));
1362#endif
1363#endif
1364}
1365
1366#ifndef HAVE_SYSLOG_H
1367
1368/*
1369 * Redefine early error messages in stand-alone situations
1370 */
1371
1372void ntfs_log_early_error(const char *format, ...)
1373{
1374 va_list args;
1375
1376 va_start(args, format);
1377 vfprintf(stderr,format,args);
1378 va_end(args);
1379}
1380
1381#endif
1382
1383/*
1384 * Guess whether a security attribute is intended for a directory
1385 * based on the presence of inheritable ACE
1386 * (not 100% reliable)
1387 */
1388
1389BOOL guess_dir(const char *attr)
1390{
1391 int off;
1392 int isdir;
1393 int cnt;
1394 int i;
1395 int x;
1396
1397 isdir = 0;
1398 off = get4l(attr,16);
1399 if (off) {
1400 cnt = get2l(attr,off+4);
1401 x = 8;
1402 for (i=0; i<cnt; i++) {
1403 if (attr[off + x + 1] & 3)
1404 isdir = 1;
1405 x += get2l(attr,off + x + 2);
1406 }
1407 }
1408 return (isdir);
1409}
1410
1411/*
1412 * Display a SID
1413 * See http://msdn2.microsoft.com/en-us/library/aa379649.aspx
1414 */
1415
1416void showsid(const char *attr, int off, const char *prefix, int level)
1417{
1418 int cnt;
1419 int i;
1420 BOOL known;
1421 u64 auth;
1422 unsigned long first;
1423 unsigned long second;
1424 unsigned long last;
1425 char marker;
1426
1427 if (opt_b)
1428 marker = '#';
1429 else
1430 marker = ' ';
1431 cnt = attr[off+1] & 255;
1432 auth = get6h(attr,off+2);
1433 first = get4l(attr,off+8);
1434 known = FALSE;
1435 if ((attr[off] == 1) /* revision */
1436 && (auth < 100))
1437 switch (cnt) {
1438 case 0 : /* no level (error) */
1439 break;
1440 case 1 : /* single level */
1441 switch (auth) {
1442 case 0 :
1443 if (first == 0) {
1444 known = TRUE;
1445 printf("%*cNull SID\n",-level,marker);
1446 }
1447 break;
1448 case 1 :
1449 if (first == 0) {
1450 known = TRUE;
1451 printf("%*cWorld SID\n",-level,marker);
1452 }
1453 break;
1454 case 3 :
1455 switch (first) {
1456 case 0 :
1457 known = TRUE;
1458 printf("%*cCreator owner SID\n",-level,marker);
1459 break;
1460 case 1 :
1461 known = TRUE;
1462 printf("%*cCreator group SID\n",-level,marker);
1463 break;
1464 }
1465 break;
1466 case 5 :
1467 switch (first) {
Steve Kondik79165c32015-11-09 19:43:00 -08001468 case 1 :
1469 known = TRUE;
1470 printf("%*cDialup SID\n",-level,marker);
1471 break;
1472 case 2 :
1473 known = TRUE;
1474 printf("%*cNetwork SID\n",-level,marker);
1475 break;
1476 case 3 :
1477 known = TRUE;
1478 printf("%*cBatch SID\n",-level,marker);
1479 break;
1480 case 4 :
1481 known = TRUE;
1482 printf("%*cInteractive SID\n",-level,marker);
1483 break;
1484 case 6 :
1485 known = TRUE;
1486 printf("%*cService SID\n",-level,marker);
1487 break;
Steve Kondik2111ad72013-07-07 12:07:44 -07001488 case 7 :
1489 known = TRUE;
1490 printf("%*cAnonymous logon SID\n",-level,marker);
1491 break;
1492 case 11 :
1493 known = TRUE;
1494 printf("%*cAuthenticated user SID\n",-level,marker);
1495 break;
1496 case 13 :
1497 known = TRUE;
1498 printf("%*cLocal service SID\n",-level,marker);
1499 break;
1500 case 14 :
1501 known = TRUE;
1502 printf("%*cNetwork service SID\n",-level,marker);
1503 break;
1504 case 18 :
1505 known = TRUE;
1506 printf("%*cNT System SID\n",-level,marker);
1507 break;
1508 }
1509 break;
1510 }
1511 break;
1512 case 2 : /* double level */
1513 second = get4l(attr,off+12);
1514 switch (auth) {
1515 case 5 :
1516 if (first == 32) {
1517 known = TRUE;
1518 switch (second) {
1519 case 544 :
1520 printf("%*cLocal admins SID\n",-level,marker);
1521 break;
1522 case 545 :
1523 printf("%*cLocal users SID\n",-level,marker);
1524 break;
1525 case 546 :
1526 printf("%*cLocal guests SID\n",-level,marker);
1527 break;
1528 default :
1529 printf("%*cSome domain SID\n",-level,marker);
1530 break;
1531 }
1532 }
1533 break;
1534 }
1535 default : /* three levels or more */
1536 second = get4l(attr,off+12);
1537 last = get4l(attr,off+4+4*cnt);
1538 switch (auth) {
1539 case 5 :
1540 if (first == 21) {
1541 known = TRUE;
Steve Kondik79165c32015-11-09 19:43:00 -08001542 switch (last) {
1543 case 500 :
1544 printf("%*cSystem admin SID\n",-level,marker);
1545 break;
1546 case 501 :
1547 printf("%*cGuest SID\n",-level,marker);
1548 break;
Steve Kondik2111ad72013-07-07 12:07:44 -07001549 case 512 :
1550 printf("%*cLocal admins SID\n",-level,marker);
1551 break;
1552 case 513 :
1553 printf("%*cLocal users SID\n",-level,marker);
1554 break;
1555 case 514 :
1556 printf("%*cLocal guests SID\n",-level,marker);
1557 break;
1558 default :
1559 printf("%*cLocal user-%lu SID\n",-level,marker,last);
1560 break;
1561 }
1562 }
1563 break;
1564 }
1565 }
1566 if (!known)
1567 printf("%*cUnknown SID\n",-level,marker);
1568 printf("%*c%shex S-%d-",-level,marker,prefix,attr[off] & 255);
1569 printf("%llx",auth);
1570 for (i=0; i<cnt; i++)
1571 printf("-%lx",get4l(attr,off+8+4*i));
1572 printf("\n");
1573 printf("%*c%sdec S-%d-",-level,marker,prefix,attr[off] & 255);
1574 printf("%llu",auth);
1575 for (i=0; i<cnt; i++)
1576 printf("-%lu",get4l(attr,off+8+4*i));
1577 printf("\n");
1578}
1579
1580void showusid(const char *attr, int level)
1581{
1582 int off;
1583 char marker;
1584
1585 if (opt_b)
1586 marker = '#';
1587 else
1588 marker = ' ';
1589 if (level)
1590 printf("%*c",-level,marker);
1591 printf("Owner SID\n");
1592 off = get4l(attr,4);
1593 showsid(attr,off,"O:",level+4);
1594}
1595
1596void showgsid(const char *attr, int level)
1597{
1598 int off;
1599 char marker;
1600
1601 if (opt_b)
1602 marker = '#';
1603 else
1604 marker = ' ';
1605 if (level)
1606 printf("%*c",-level,marker);
1607 printf("Group SID\n");
1608 off = get4l(attr,8);
1609 showsid(attr,off,"G:",level+4);
1610}
1611
Steve Kondik79165c32015-11-09 19:43:00 -08001612void showownership(const char *attr)
1613{
1614#ifdef WIN32
1615 char account[ACCOUNTSIZE];
1616 BIGSID sidcopy;
1617 SID_NAME_USE use;
1618 unsigned long accountsz;
1619 unsigned long domainsz;
1620#endif
1621 enum { SHOWOWN, SHOWGRP, SHOWINT } shown;
1622 const char *sid;
1623 const char *prefix;
1624 u64 auth;
1625 int cnt;
1626 int off;
1627 int i;
1628
1629 for (shown=SHOWOWN; shown<=SHOWINT; shown++) {
1630 switch (shown) {
1631 case SHOWOWN :
1632 off = get4l(attr,4);
1633 sid = &attr[off];
1634 prefix = "Windows owner";
1635 break;
1636 case SHOWGRP :
1637 off = get4l(attr,8);
1638 sid = &attr[off];
1639 prefix = "Windows group";
1640 break;
1641#if OWNERFROMACL
1642 case SHOWINT :
1643 off = get4l(attr,4);
1644 prefix = "Interpreted owner";
1645 sid = (const char*)ntfs_acl_owner((const char*)attr);
1646 if (ntfs_same_sid((const SID*)sid,
1647 (const SID*)&attr[off]))
1648 sid = (const char*)NULL;
1649 break;
1650#endif
1651 default :
1652 sid = (const char*)NULL;
1653 prefix = (const char*)NULL;
1654 break;
1655 }
1656 if (sid) {
1657 cnt = sid[1] & 255;
1658 auth = get6h(sid,2);
1659 if (opt_b)
1660 printf("# %s S-%d-",prefix,sid[0] & 255);
1661 else
1662 printf("%s S-%d-",prefix,sid[0] & 255);
1663 printf("%llu",auth);
1664 for (i=0; i<cnt; i++)
1665 printf("-%lu",get4l(sid,8+4*i));
1666#ifdef WIN32
1667 memcpy(sidcopy,sid,ntfs_sid_size((const SID*)sid));
1668 accountsz = ACCOUNTSIZE;
1669 domainsz = ACCOUNTSIZE;
1670 if (LookupAccountSidA((const char*)NULL, sidcopy,
1671 account, &accountsz,
1672 (char*)NULL, &domainsz, &use))
1673 printf(" (%s)", account);
1674#endif
1675 printf("\n");
1676 }
1677 }
1678}
1679
Steve Kondik2111ad72013-07-07 12:07:44 -07001680void showheader(const char *attr, int level)
1681{
1682 int flags;
1683 char marker;
1684
1685 if (opt_b)
1686 marker = '#';
1687 else
1688 marker = ' ';
1689 if (level)
1690 printf("%*c",-level,marker);
1691 printf("Global header\n");
1692 printf("%*crevision %d\n",-level-4,marker,attr[0]);
1693 flags = get2l(attr,2);
1694 printf("%*cflags 0x%x\n",-level-4,marker,flags);
1695 if (flags & 1)
1696 printf("%*c owner is defaulted\n",-level-4,marker);
1697 if (flags & 2)
1698 printf("%*c group is defaulted\n",-level-4,marker);
1699 if (flags & 4)
1700 printf("%*c DACL present\n",-level-4,marker);
1701 if (flags & 8)
1702 printf("%*c DACL is defaulted\n",-level-4,marker);
1703 if (flags & 0x10)
1704 printf("%*c SACL present\n",-level-4,marker);
1705 if (flags & 0x20)
1706 printf("%*c SACL is defaulted\n",-level-4,marker);
1707 if (flags & 0x100)
1708 printf("%*c DACL inheritance is requested\n",-level-4,marker);
1709 if (flags & 0x200)
1710 printf("%*c SACL inheritance is requested\n",-level-4,marker);
1711 if (flags & 0x400)
1712 printf("%*c DACL was inherited automatically\n",-level-4,marker);
1713 if (flags & 0x800)
1714 printf("%*c SACL was inherited automatically\n",-level-4,marker);
1715 if (flags & 0x1000)
1716 printf("%*c DACL cannot be modified by inheritable ACEs\n",-level-4,marker);
1717 if (flags & 0x2000)
1718 printf("%*c SACL cannot be modified by inheritable ACEs\n",-level-4,marker);
1719 if (flags & 0x8000)
1720 printf("%*c self relative descriptor\n",-level-4,marker);
1721 if (flags & 0x43eb)
1722 printf("%*c unknown flags 0x%x present\n",-level-4,marker,
1723 flags & 0x43eb);
1724 printf("%*cOff USID 0x%x\n",-level-4,marker,(int)get4l(attr,4));
1725 printf("%*cOff GSID 0x%x\n",-level-4,marker,(int)get4l(attr,8));
1726 printf("%*cOff SACL 0x%x\n",-level-4,marker,(int)get4l(attr,12));
1727 printf("%*cOff DACL 0x%x\n",-level-4,marker,(int)get4l(attr,16));
1728}
1729
1730void showace(const char *attr, int off, int isdir, int level)
1731{
1732 int flags;
1733 u32 rights;
1734 char marker;
1735
1736 if (opt_b)
1737 marker = '#';
1738 else
1739 marker = ' ';
1740 printf("%*ctype %d\n",-level,marker,attr[off]);
1741 switch (attr[off]) {
1742 case 0 :
1743 printf("%*cAccess allowed\n",-level-4,marker);
1744 break;
1745 case 1 :
1746 printf("%*cAccess denied\n",-level-4,marker);
1747 break;
1748 case 2 :
1749 printf("%*cSystem audit\n",-level-4,marker);
1750 break;
1751 default :
1752 printf("%*cunknown\n",-level-4,marker);
1753 break;
1754 }
1755 flags = attr[off+1] & 255;
1756 printf("%*cflags 0x%x\n",-level,marker,flags);
1757 if (flags & 1)
1758 printf("%*cObject inherits ACE\n",-level-4,marker);
1759 if (flags & 2)
1760 printf("%*cContainer inherits ACE\n",-level-4,marker);
1761 if (flags & 4)
1762 printf("%*cDon\'t propagate inherits ACE\n",-level-4,marker);
1763 if (flags & 8)
1764 printf("%*cInherit only ACE\n",-level-4,marker);
1765 if (flags & 0x10)
1766 printf("%*cACE was inherited\n",-level-4,marker);
1767 if (flags & 0x40)
1768 printf("%*cAudit on success\n",-level-4,marker);
1769 if (flags & 0x80)
1770 printf("%*cAudit on failure\n",-level-4,marker);
1771
1772 printf("%*cSize 0x%x\n",-level,marker,get2l(attr,off+2));
1773
1774 rights = get4l(attr,off+4);
1775 printf("%*cAcc rgts 0x%lx\n",-level,marker,(long)rights);
1776 printf("%*cObj specific acc rgts 0x%lx\n",-level-4,marker,(long)rights & 65535);
1777 if (isdir) /* a directory */ {
1778 if (rights & 0x01)
1779 printf("%*cList directory\n",-level-8,marker);
1780 if (rights & 0x02)
1781 printf("%*cAdd file\n",-level-8,marker);
1782 if (rights & 0x04)
1783 printf("%*cAdd subdirectory\n",-level-8,marker);
1784 if (rights & 0x08)
1785 printf("%*cRead EA\n",-level-8,marker);
1786 if (rights & 0x10)
1787 printf("%*cWrite EA\n",-level-8,marker);
1788 if (rights & 0x20)
1789 printf("%*cTraverse\n",-level-8,marker);
1790 if (rights & 0x40)
1791 printf("%*cDelete child\n",-level-8,marker);
1792 if (rights & 0x80)
1793 printf("%*cRead attributes\n",-level-8,marker);
1794 if (rights & 0x100)
1795 printf("%*cWrite attributes\n",-level-8,marker);
1796 }
1797 else {
1798 /* see FILE_READ_DATA etc in winnt.h */
1799 if (rights & 0x01)
1800 printf("%*cRead data\n",-level-8,marker);
1801 if (rights & 0x02)
1802 printf("%*cWrite data\n",-level-8,marker);
1803 if (rights & 0x04)
1804 printf("%*cAppend data\n",-level-8,marker);
1805 if (rights & 0x08)
1806 printf("%*cRead EA\n",-level-8,marker);
1807 if (rights & 0x10)
1808 printf("%*cWrite EA\n",-level-8,marker);
1809 if (rights & 0x20)
1810 printf("%*cExecute\n",-level-8,marker);
1811 if (rights & 0x80)
1812 printf("%*cRead attributes\n",-level-8,marker);
1813 if (rights & 0x100)
1814 printf("%*cWrite attributes\n",-level-8,marker);
1815 }
1816 printf("%*cstandard acc rgts 0x%lx\n",-level-4,marker,(long)(rights >> 16) & 127);
1817 if (rights & 0x10000)
1818 printf("%*cDelete\n",-level-8,marker);
1819 if (rights & 0x20000)
1820 printf("%*cRead control\n",-level-8,marker);
1821 if (rights & 0x40000)
1822 printf("%*cWrite DAC\n",-level-8,marker);
1823 if (rights & 0x80000)
1824 printf("%*cWrite owner\n",-level-8,marker);
1825 if (rights & 0x100000)
1826 printf("%*cSynchronize\n",-level-8,marker);
1827 if (rights & 0x800000)
1828 printf("%*cCan access security ACL\n",-level-4,marker);
1829 if (rights & 0x10000000)
1830 printf("%*cGeneric all\n",-level-4,marker);
1831 if (rights & 0x20000000)
1832 printf("%*cGeneric execute\n",-level-4,marker);
1833 if (rights & 0x40000000)
1834 printf("%*cGeneric write\n",-level-4,marker);
1835 if (rights & 0x80000000)
1836 printf("%*cGeneric read\n",-level-4,marker);
1837
1838 printf("%*cSID at 0x%x\n",-level,marker,off+8);
1839 showsid(attr,off+8,"",level+4);
1840 printf("%*cSummary :",-level,marker);
1841 if (attr[off] == 0)
1842 printf(" grant");
1843 if (attr[off] == 1)
1844 printf(" deny");
1845 if (rights & le32_to_cpu(FILE_GREAD | FILE_GWRITE | FILE_GEXEC)) {
1846 printf(" ");
1847 if (rights & le32_to_cpu(FILE_GREAD))
1848 printf("r");
1849 if (rights & le32_to_cpu(FILE_GWRITE))
1850 printf("w");
1851 if (rights & le32_to_cpu(FILE_GEXEC))
1852 printf("x");
1853 } else
1854 printf(" none");
1855 if (flags & 11)
1856 printf(" inherited");
1857 if (!(flags & 8)) {
1858 int sz;
1859
1860 printf(" applied");
1861 sz = attr[off+9]*4 + 8;
1862 if (!memcmp(&attr[off+8],&attr[get4l(attr,4)],sz))
1863 printf(" to owner");
1864 if (!memcmp(&attr[off+8],&attr[get4l(attr,8)],sz))
1865 printf(" to group");
1866 }
1867 printf("\n");
1868
1869}
1870
1871void showacl(const char *attr, int off, int isdir, int level)
1872{
1873 int i;
1874 int cnt;
1875 int size;
1876 int x;
1877 char marker;
1878
1879 if (opt_b)
1880 marker = '#';
1881 else
1882 marker = ' ';
1883 size = get2l(attr,off+2);
1884 printf("%*crevision %d\n",-level,marker,attr[off]);
1885 printf("%*cACL size %d\n",-level,marker,size);
1886 cnt = get2l(attr,off+4);
1887 printf("%*cACE cnt %d\n",-level,marker,cnt);
1888 x = 8;
1889 for (i=0; (i<cnt) && (x < size); i++) {
1890 printf("%*cACE %d at 0x%x\n",-level,marker,i + 1,off+x);
1891 showace(attr,off + x,isdir,level+4);
1892 x += get2l(attr,off + x + 2);
1893 }
1894}
1895
1896void showdacl(const char *attr, int isdir, int level)
1897{
1898 int off;
1899 char marker;
1900
1901 if (opt_b)
1902 marker = '#';
1903 else
1904 marker = ' ';
1905 off = get4l(attr,16);
1906 if (off) {
1907 if (level)
1908 printf("%*c",-level,marker);
1909 printf("DACL\n");
1910 showacl(attr,off,isdir,level+4);
1911 } else {
1912 if (level)
1913 printf("%*c",-level,marker);
1914 printf("No DACL\n");
1915 }
1916}
1917
1918void showsacl(const char *attr, int isdir, int level)
1919{
1920 int off;
1921 char marker;
1922
1923 if (opt_b)
1924 marker = '#';
1925 else
1926 marker = ' ';
1927 off = get4l(attr,12);
1928 if (off) {
1929 if (level)
1930 printf("%*c",-level,marker);
1931 printf("SACL\n");
1932 showacl(attr,off,isdir,level+4);
1933 }
1934 else {
1935 if (level)
1936 printf("%*c",-level,marker);
1937 printf("No SACL\n");
1938 }
1939}
1940
1941void showall(const char *attr, int level)
1942{
1943 BOOL isdir;
1944
1945 isdir = guess_dir(attr);
1946 showheader(attr,level);
1947 showusid(attr,level);
1948 showgsid(attr,level);
1949 showdacl(attr,isdir,level);
1950 showsacl(attr,isdir,level);
1951}
1952
1953#if POSIXACLS
1954/*
1955 * Display a Posix descriptor
1956 */
1957
1958void showposix(const struct POSIX_SECURITY *pxdesc)
1959{
1960 char txperm[4];
1961 const char *txtag;
1962 const char *txtype;
1963 const struct POSIX_ACL *acl;
1964 const struct POSIX_ACE *pxace;
1965 int acccnt;
1966 int defcnt;
1967 int firstdef;
1968 int perms;
1969 u16 tag;
1970 s32 id;
1971 int k,l;
1972
1973 if (pxdesc) {
1974 acccnt = pxdesc->acccnt;
1975 defcnt = pxdesc->defcnt;
1976 firstdef = pxdesc->firstdef;
1977 acl = &pxdesc->acl;
1978 printf("Posix descriptor :\n");
1979 printf(" acccnt %d\n",acccnt);
1980 printf(" defcnt %d\n",defcnt);
1981 printf(" firstdef %d\n",firstdef);
1982 printf(" mode : 0%03o\n",(int)pxdesc->mode);
1983 printf(" tagsset : 0x%02x\n",(int)pxdesc->tagsset);
1984 printf("Posix ACL :\n");
1985 printf(" version %d\n",(int)acl->version);
1986 printf(" flags 0x%02x\n",(int)acl->flags);
1987 for (k=0; k<(acccnt + defcnt); k++) {
1988 if (k < acccnt)
1989 l = k;
1990 else
1991 l = firstdef + k - acccnt;
1992 pxace = &acl->ace[l];
1993 tag = pxace->tag;
1994 perms = pxace->perms;
1995 if (tag == POSIX_ACL_SPECIAL) {
1996 txperm[0] = (perms & S_ISVTX ? 's' : '-');
1997 txperm[1] = (perms & S_ISUID ? 'u' : '-');
1998 txperm[2] = (perms & S_ISGID ? 'g' : '-');
1999 } else {
2000 txperm[0] = (perms & 4 ? 'r' : '-');
2001 txperm[1] = (perms & 2 ? 'w' : '-');
2002 txperm[2] = (perms & 1 ? 'x' : '-');
2003 }
2004 txperm[3] = 0;
2005 if (k >= acccnt)
2006 txtype = "default";
2007 else
2008 txtype = "access ";
2009 switch (tag) {
2010 case POSIX_ACL_USER :
2011 txtag = "USER ";
2012 break;
2013 case POSIX_ACL_USER_OBJ :
2014 txtag = "USR-O";
2015 break;
2016 case POSIX_ACL_GROUP :
2017 txtag = "GROUP";
2018 break;
2019 case POSIX_ACL_GROUP_OBJ :
2020 txtag = "GRP-O";
2021 break;
2022 case POSIX_ACL_MASK :
2023 txtag = "MASK ";
2024 break;
2025 case POSIX_ACL_OTHER :
2026 txtag = "OTHER";
2027 break;
2028 case POSIX_ACL_SPECIAL :
2029 txtag = "SPECL";
2030 break;
2031 default :
2032 txtag = "UNKWN";
2033 break;
2034 }
2035 id = pxace->id;
2036 printf("ace %d : %s %s %4ld perms 0%03o %s\n",
2037 l,txtype,txtag,(long)id,
2038 perms,txperm);
2039 }
2040 } else
2041 printf("** NULL ACL\n");
2042}
2043
2044#endif /* POSIXACLS */
2045
2046#if defined(WIN32) | defined(STSC)
2047
2048#else
2049
2050/*
2051 * Relay to get usid as defined during mounting
2052 */
2053
2054const SID *relay_find_usid(const struct MAPPING *usermapping __attribute__((unused)),
2055 uid_t uid, SID *defusid)
2056{
2057 return (ntfs_get_usid(ntfs_context,uid,(char*)defusid) ?
2058 defusid : (SID*)NULL);
2059}
2060
2061/*
2062 * Relay to get gsid as defined during mounting
2063 */
2064
2065const SID *relay_find_gsid(const struct MAPPING *groupmapping __attribute__((unused)),
2066 uid_t gid, SID *defgsid)
2067{
2068 return (ntfs_get_usid(ntfs_context,gid,(char*)defgsid) ?
2069 defgsid : (SID*)NULL);
2070}
2071
2072/*
2073 * Relay to get uid as defined during mounting
2074 */
2075
2076uid_t relay_find_user(const struct MAPPING *mapping __attribute__((unused)),
2077 const SID *usid)
2078{
2079 int uid;
2080
2081 uid = ntfs_get_user(ntfs_context,(const char*)usid);
2082 return (uid < 0 ? 0 : uid);
2083}
2084
2085/*
2086 * Relay to get gid as defined during mounting
2087 */
2088
2089gid_t relay_find_group(const struct MAPPING *mapping __attribute__((unused)),
2090 const SID *gsid)
2091{
2092 int gid;
2093
2094 gid = ntfs_get_group(ntfs_context,(const char*)gsid);
2095 return (gid < 0 ? 0 : gid);
2096}
2097
2098#endif
2099
2100#if defined(WIN32) | defined(STSC)
2101
2102/*
2103 * Dummy get uid from user name, out of a Linux environment
2104 */
2105
2106struct passwd *getpwnam(const char *user)
2107{
2108 ntfs_log_error("Cannot interpret id \"%s\"", user);
2109 ntfs_log_error("please use numeric uids in UserMapping file\n");
2110 return ((struct passwd*)NULL);
2111}
2112
2113/*
2114 * Dummy get gid from group name, out of a Linux environment
2115 */
2116
2117struct group *getgrnam(const char *group)
2118{
2119 ntfs_log_error("Cannot interpret id \"%s\"", group);
2120 ntfs_log_error("please use numeric gids in UserMapping file\n");
2121 return ((struct group*)NULL);
2122}
2123
2124#endif /* defined(WIN32) | defined(STSC) */
2125
2126#if POSIXACLS
2127
2128struct POSIX_SECURITY *linux_permissions_posix(const char *attr, BOOL isdir)
2129{
2130 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2131#if OWNERFROMACL
2132 const SID *osid;
2133#endif
2134 const SID *usid;
2135 const SID *gsid;
2136 struct POSIX_SECURITY *posix_desc;
2137
2138 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
2139 gsid = (const SID*)&attr[le32_to_cpu(phead->group)];
2140#if OWNERFROMACL
2141 osid = (const SID*)&attr[le32_to_cpu(phead->owner)];
2142 usid = ntfs_acl_owner((const char*)attr);
2143#if SELFTESTS & !USESTUBS
2144 if (!opt_t && !ntfs_same_sid(usid,osid))
2145 printf("== Linux owner is different from Windows owner\n");
2146#else
2147 if (!ntfs_same_sid(usid,osid))
2148 printf("== Linux owner is different from Windows owner\n");
2149#endif
2150#else
2151 usid = (const SID*)&attr[le32_to_cpu(phead->owner)];
2152#endif
2153 posix_desc = ntfs_build_permissions_posix(context.mapping,
2154 (const char*)attr, usid, gsid, isdir);
2155 if (!posix_desc) {
2156 printf("** Failed to build a Posix descriptor\n");
2157 errors++;
2158 }
2159 return (posix_desc);
2160}
2161
2162#endif /* POSIXACLS */
2163
2164int linux_permissions(const char *attr, BOOL isdir)
2165{
2166 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2167#if OWNERFROMACL
2168 const SID *osid;
2169#endif
2170 const SID *usid;
2171 const SID *gsid;
2172 int perm;
2173
2174 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
2175 gsid = (const SID*)&attr[le32_to_cpu(phead->group)];
2176#if OWNERFROMACL
2177 osid = (const SID*)&attr[le32_to_cpu(phead->owner)];
2178 usid = ntfs_acl_owner((const char*)attr);
2179#if SELFTESTS & !USESTUBS
2180 if (!opt_t && !ntfs_same_sid(usid,osid))
2181 printf("== Linux owner is different from Windows owner\n");
2182#else
2183 if (!ntfs_same_sid(usid,osid))
2184 printf("== Linux owner is different from Windows owner\n");
2185#endif
2186#else
2187 usid = (const SID*)&attr[le32_to_cpu(phead->owner)];
2188#endif
2189 perm = ntfs_build_permissions((const char*)attr, usid, gsid, isdir);
2190 if (perm < 0) {
2191 printf("** Failed to build permissions\n");
2192 errors++;
2193 }
2194 return (perm);
2195}
2196
2197uid_t linux_owner(const char *attr)
2198{
2199 const SID *usid;
2200 uid_t uid;
2201
2202#if OWNERFROMACL
2203 usid = ntfs_acl_owner((const char*)attr);
2204#else
2205 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2206
2207 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
2208 usid = (const SID*)&attr[le32_to_cpu(phead->owner)];
2209#endif
2210#if defined(WIN32) | defined(STSC)
2211 uid = ntfs_find_user(context.mapping[MAPUSERS],usid);
2212#else
2213 if (mappingtype == MAPEXTERN)
2214 uid = relay_find_user(context.mapping[MAPUSERS],usid);
2215 else
2216 uid = ntfs_find_user(context.mapping[MAPUSERS],usid);
2217#endif
2218 return (uid);
2219}
2220
2221gid_t linux_group(const char *attr)
2222{
2223 const SECURITY_DESCRIPTOR_RELATIVE *phead;
2224 const SID *gsid;
2225 gid_t gid;
2226
2227 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
2228 gsid = (const SID*)&attr[le32_to_cpu(phead->group)];
2229#if defined(WIN32) | defined(STSC)
2230 gid = ntfs_find_group(context.mapping[MAPGROUPS],gsid);
2231#else
2232 if (mappingtype == MAPEXTERN)
2233 gid = relay_find_group(context.mapping[MAPGROUPS],gsid);
2234 else
2235 gid = ntfs_find_group(context.mapping[MAPGROUPS],gsid);
2236#endif
2237 return (gid);
2238}
2239
2240void newblock(s32 key)
2241{
2242 struct SECURITY_DATA *psecurdata;
2243 int i;
2244
2245 if ((key > 0) && (key < MAXSECURID) && !securdata[key >> SECBLKSZ]) {
2246 securdata[key >> SECBLKSZ] =
2247 (struct SECURITY_DATA*)malloc((1 << SECBLKSZ)*sizeof(struct SECURITY_DATA));
2248 if (securdata[key >> SECBLKSZ])
2249 for (i=0; i<(1 << SECBLKSZ); i++) {
2250 psecurdata = &securdata[key >> SECBLKSZ][i];
2251 psecurdata->filecount = 0;
2252 psecurdata->mode = 0;
2253 psecurdata->flags = 0;
2254 psecurdata->attr = (char*)NULL;
2255 }
2256 }
2257}
2258
2259void freeblocks(void)
2260{
2261 int i,j;
2262 struct SECURITY_DATA *psecurdata;
2263
2264 for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++)
2265 if (securdata[i]) {
2266 for (j=0; j<(1 << SECBLKSZ); j++) {
2267 psecurdata = &securdata[i][j];
2268 if (psecurdata->attr)
2269 free(psecurdata->attr);
2270 }
2271 free(securdata[i]);
2272 }
2273}
2274
2275/*
2276 * Basic read from a user mapping file (Win32)
2277 */
2278
2279int basicread(void *fileid, char *buf, size_t size,
2280 off_t pos __attribute__((unused)))
2281{
2282 return (read(*(int*)fileid, buf, size));
2283}
2284
2285#if SELFTESTS & !USESTUBS
2286
2287/*
2288 * Read a dummy mapping file for tests
2289 */
2290
2291int dummyread(void *fileid __attribute__((unused)),
2292 char *buf, size_t size, off_t pos)
2293{
2294 size_t sz;
2295
2296 if (pos >= (off_t)(sizeof(dummymapping) - 1))
2297 sz = 0;
2298 else
2299 if ((size + pos) >= (sizeof(dummymapping) - 1))
2300 sz = sizeof(dummymapping) - 1 - pos;
2301 else
2302 sz = size;
2303 if (sz > 0)
2304 memcpy(buf,&dummymapping[pos],sz);
2305 return (sz);
2306}
2307
2308#endif /* POSIXACLS & SELFTESTS & !USESTUBS */
2309
2310/*
2311 * Apply default single user mapping
2312 * returns zero if successful
2313 */
2314
2315static int do_default_mapping(struct MAPPING *mapping[],
2316 const SID *usid)
2317{
2318 struct MAPPING *usermapping;
2319 struct MAPPING *groupmapping;
2320 SID *sid;
2321 int sidsz;
2322 int res;
2323
2324 res = -1;
2325 sidsz = ntfs_sid_size(usid);
2326#if USESTUBS
2327 sid = (SID*)stdmalloc(sidsz); /* will be freed within the library */
2328#else
2329 sid = (SID*)ntfs_malloc(sidsz);
2330#endif
2331 if (sid) {
2332 memcpy(sid,usid,sidsz);
2333#if USESTUBS
2334 usermapping = (struct MAPPING*)stdmalloc(sizeof(struct MAPPING));
2335#else
2336 usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
2337#endif
2338 if (usermapping) {
2339#if USESTUBS
2340 groupmapping = (struct MAPPING*)stdmalloc(sizeof(struct MAPPING));
2341#else
2342 groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
2343#endif
2344 if (groupmapping) {
2345 usermapping->sid = sid;
2346 usermapping->xid = 0;
2347 usermapping->next = (struct MAPPING*)NULL;
2348 groupmapping->sid = sid;
2349 groupmapping->xid = 0;
2350 groupmapping->next = (struct MAPPING*)NULL;
2351 mapping[MAPUSERS] = usermapping;
2352 mapping[MAPGROUPS] = groupmapping;
2353 res = 0;
2354 }
2355 }
2356 }
2357 return (res);
2358}
2359
2360/*
2361 * Build the user mapping
2362 * - according to a mapping file if defined (or default present),
2363 * - or try default single user mapping if possible
2364 *
2365 * The mapping is specific to a mounted device
2366 * No locking done, mounting assumed non multithreaded
2367 *
2368 * returns zero if mapping is successful
2369 * (failure should not be interpreted as an error)
2370 */
2371
2372int local_build_mapping(struct MAPPING *mapping[], const char *usermap_path)
2373{
2374#ifdef WIN32
2375 char mapfile[sizeof(MAPDIR) + sizeof(MAPFILE) + 6];
2376 char currpath[261];
2377#else
2378 char *mapfile;
2379 char *p;
2380#endif
2381 int fd;
2382 struct MAPLIST *item;
2383 struct MAPLIST *firstitem = (struct MAPLIST*)NULL;
2384 struct MAPPING *usermapping;
2385 struct MAPPING *groupmapping;
2386 static struct {
2387 u8 revision;
2388 u8 levels;
2389 be16 highbase;
2390 be32 lowbase;
2391 le32 level1;
2392 le32 level2;
2393 le32 level3;
2394 le32 level4;
2395 le32 level5;
2396 } defmap = {
2397 1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5),
2398 const_cpu_to_le32(21),
2399 const_cpu_to_le32(DEFSECAUTH1), const_cpu_to_le32(DEFSECAUTH2),
2400 const_cpu_to_le32(DEFSECAUTH3), const_cpu_to_le32(DEFSECBASE)
2401 } ;
2402
2403 /* be sure not to map anything until done */
2404 mapping[MAPUSERS] = (struct MAPPING*)NULL;
2405 mapping[MAPGROUPS] = (struct MAPPING*)NULL;
2406
2407 if (usermap_path) {
2408#ifdef WIN32
2409/* TODO : check whether the device can store acls */
2410 strcpy(mapfile,"x:\\" MAPDIR "\\" MAPFILE);
Steve Kondik79165c32015-11-09 19:43:00 -08002411 if (((const le16*)usermap_path)[1] == ':')
Steve Kondik2111ad72013-07-07 12:07:44 -07002412 mapfile[0] = usermap_path[0];
2413 else {
2414 GetModuleFileName(NULL, currpath, 261);
2415 mapfile[0] = currpath[0];
2416 }
2417 fd = open(mapfile,O_RDONLY);
2418#else
2419 fd = 0;
2420 mapfile = (char*)malloc(MAXFILENAME);
2421 if (mapfile) {
2422 /* build a full path to locate the mapping file */
2423 if ((usermap_path[0] != '/')
2424 && getcwd(mapfile,MAXFILENAME)) {
2425 strcat(mapfile,"/");
2426 strcat(mapfile,usermap_path);
2427 } else
2428 strcpy(mapfile,usermap_path);
2429 p = strrchr(mapfile,'/');
2430 if (p)
2431 do {
2432 strcpy(p,"/" MAPDIR "/" MAPFILE);
2433 fd = open(mapfile,O_RDONLY);
2434 if (fd <= 0) {
2435 *p = 0;
2436 p = strrchr(mapfile,'/');
2437 if (p == mapfile)
2438 p = (char*)NULL;
2439 }
2440 } while ((fd <= 0) && p);
2441 free(mapfile);
2442 if (!p) {
2443 printf("** Could not find the user mapping file\n");
2444 if (usermap_path[0] != '/')
2445 printf(" Retry with full path of file\n");
2446 errors++;
2447 }
2448 }
2449#endif
2450 if (fd > 0) {
2451 firstitem = ntfs_read_mapping(basicread, (void*)&fd);
2452 close(fd);
2453 }
2454 } else {
2455#if SELFTESTS & !USESTUBS
2456 firstitem = ntfs_read_mapping(dummyread, (void*)NULL);
2457#endif
2458 }
2459
2460 if (firstitem) {
2461 usermapping = ntfs_do_user_mapping(firstitem);
2462 groupmapping = ntfs_do_group_mapping(firstitem);
2463 if (usermapping && groupmapping) {
2464 mapping[MAPUSERS] = usermapping;
2465 mapping[MAPGROUPS] = groupmapping;
2466 } else
2467 ntfs_log_error("There were no valid user or no valid group\n");
2468 /* now we can free the memory copy of input text */
2469 /* and rely on internal representation */
2470 while (firstitem) {
2471 item = firstitem->next;
2472#if USESTUBS
2473 stdfree(firstitem); /* allocated within library */
2474#else
2475 free(firstitem);
2476#endif
2477 firstitem = item;
2478 }
2479 } else {
2480 do_default_mapping(mapping,(const SID*)&defmap);
2481 }
2482 if (mapping[MAPUSERS])
2483 mappingtype = MAPLOCAL;
2484 return (!mapping[MAPUSERS]);
2485}
2486
2487/*
2488 * Get an hexadecimal number (source with MSB first)
2489 */
2490
2491u32 getmsbhex(const char *text)
2492{
2493 u32 v;
2494 int b;
2495 BOOL ok;
2496
2497 v = 0;
2498 ok = TRUE;
2499 do {
2500 b = *text++;
2501 if ((b >= '0') && (b <= '9'))
2502 v = (v << 4) + b - '0';
2503 else
2504 if ((b >= 'a') && (b <= 'f'))
2505 v = (v << 4) + b - 'a' + 10;
2506 else
2507 if ((b >= 'A') && (b <= 'F'))
2508 v = (v << 4) + b - 'A' + 10;
2509 else ok = FALSE;
2510 } while (ok);
2511 return (v);
2512}
2513
2514
2515/*
2516 * Get an hexadecimal number (source with LSB first)
2517 * An odd number of digits might yield a strange result
2518 */
2519
2520u32 getlsbhex(const char *text)
2521{
2522 u32 v;
2523 int b;
2524 BOOL ok;
2525 int pos;
2526
2527 v = 0;
2528 ok = TRUE;
2529 pos = 0;
2530 do {
2531 b = *text++;
2532 if ((b >= '0') && (b <= '9'))
2533 v |= (u32)(b - '0') << (pos ^ 4);
2534 else
2535 if ((b >= 'a') && (b <= 'f'))
2536 v |= (u32)(b - 'a' + 10) << (pos ^ 4);
2537 else
2538 if ((b >= 'A') && (b <= 'F'))
2539 v |= (u32)(b - 'A' + 10) << (pos ^ 4);
2540 else ok = FALSE;
2541 pos += 4;
2542 } while (ok);
2543 return (v);
2544}
2545
2546
2547/*
2548 * Check whether a line looks like an hex dump
2549 */
2550
2551BOOL ishexdump(const char *line, int first, int lth)
2552{
2553 BOOL ok;
2554 int i;
2555 int b;
2556
2557 ok = (first >= 0) && (lth >= (first + 16));
2558 for (i=0; ((first+i)<lth) && ok; i++) {
2559 b = line[first + i];
2560 if ((i == 6)
2561 || (i == 7)
2562 || (i == 16)
2563 || (i == 25)
2564 || (i == 34)
2565 || (i == 43))
2566 ok = (b == ' ') || (b == '\n');
2567 else
2568 ok = ((b >= '0') && (b <= '9'))
2569 || ((b >= 'a') && (b <= 'f'))
2570 || ((b >= 'A') && (b <= 'F'));
2571 }
2572 return (ok);
2573}
2574
2575
2576/*
2577 * Display security descriptors from a file
2578 * This is typically to convert a verbose output to a very verbose one
2579 */
2580
2581void showhex(FILE *fd)
2582{
2583 static char attr[MAXATTRSZ];
2584 char line[MAXLINE+1];
2585#if POSIXACLS
2586 struct POSIX_SECURITY *pxdesc;
2587#endif
2588 int lth;
2589 int first;
2590 unsigned int pos;
2591 u32 v;
2592 int c;
2593 int isdir;
2594 int mode;
2595 unsigned int off;
2596 int i;
Steve Kondik79165c32015-11-09 19:43:00 -08002597 le32 *pattr;
Steve Kondik2111ad72013-07-07 12:07:44 -07002598 BOOL isdump;
2599 BOOL done;
2600
2601 pos = 0;
2602 off = 0;
2603 done = FALSE;
2604 do {
2605 /* input a (partial) line without displaying */
2606 lth = 0;
2607 first = -1;
2608 do {
2609 c = getc(fd);
2610 if ((c != ' ') && (first < 0))
2611 first = lth;
2612 if (c == EOF)
2613 done = TRUE;
2614 else
2615 if (c != '\r')
2616 line[lth++] = c;
2617 } while (!done && (c != '\n') && (lth < MAXLINE));
2618 /* check whether this looks like an hexadecimal dump */
2619 isdump = ishexdump(line, first, lth);
2620 if (isdump) off = getmsbhex(&line[first]);
2621 /* line is not an hexadecimal dump */
2622 /* display what we have in store */
2623 if ((!isdump || !off) && pos && ntfs_valid_descr((char*)attr,pos)) {
2624 printf(" Computed hash : 0x%08lx\n",
2625 (unsigned long)hash((le32*)attr,
2626 ntfs_attr_size(attr)));
2627 isdir = guess_dir(attr);
2628 printf(" Estimated type : %s\n",(isdir ? "directory" : "file"));
2629 showheader(attr,4);
2630 showusid(attr,4);
2631 showgsid(attr,4);
2632 showdacl(attr,isdir,4);
2633 showsacl(attr,isdir,4);
Steve Kondik79165c32015-11-09 19:43:00 -08002634 showownership(attr);
Steve Kondik2111ad72013-07-07 12:07:44 -07002635 mode = linux_permissions(attr,isdir);
2636 printf("Interpreted Unix mode 0%03o\n",mode);
2637#if POSIXACLS
2638 /*
2639 * Posix display not possible when user
2640 * mapping is not available (option -h)
2641 */
2642 if (mappingtype != MAPNONE) {
2643 pxdesc = linux_permissions_posix(attr,isdir);
2644 if (pxdesc) {
2645 showposix(pxdesc);
2646 free(pxdesc);
2647 }
2648 }
2649#endif
2650 pos = 0;
2651 }
2652 if (isdump && !off)
2653 pos = off;
2654 /* line looks like an hexadecimal dump */
2655 /* decode it into attribute */
2656 if (isdump && (off == pos)) {
2657 for (i=first+8; i<lth; i+=9) {
Steve Kondik79165c32015-11-09 19:43:00 -08002658 pattr = (le32*)&attr[pos];
Steve Kondik2111ad72013-07-07 12:07:44 -07002659 v = getlsbhex(&line[i]);
Steve Kondik79165c32015-11-09 19:43:00 -08002660 *pattr = cpu_to_le32(v);
Steve Kondik2111ad72013-07-07 12:07:44 -07002661 pos += 4;
2662 }
2663 }
2664 /* display (full) current line */
2665 if (lth) printf("! ");
2666 for (i=0; i<lth; i++) {
2667 c = line[i];
2668 putchar(c);
2669 }
2670 while (!done && (c != '\n')) {
2671 c = getc(fd);
2672 if (c == EOF)
2673 done = TRUE;
2674 else
2675 putchar(c);
2676 }
2677 } while (!done);
2678}
2679
2680BOOL applyattr(const char *fullname, const char *attr,
2681 BOOL withattr, int attrib, s32 key)
2682{
2683 struct SECURITY_DATA *psecurdata;
2684 const char *curattr;
2685 char *newattr;
2686 int selection;
2687 BOOL bad;
2688 BOOL badattrib;
2689 BOOL err;
2690#ifdef WIN32
2691 HANDLE htoken;
2692 TOKEN_PRIVILEGES tkp;
2693#endif
2694
2695 err = FALSE;
2696 psecurdata = (struct SECURITY_DATA*)NULL;
2697 curattr = (const char*)NULL;
2698 newattr = (char*)NULL;
2699 if ((key > 0) && (key < MAXSECURID)) {
2700 if (!securdata[key >> SECBLKSZ])
2701 newblock(key);
2702 if (securdata[key >> SECBLKSZ]) {
2703 psecurdata = &securdata[key >> SECBLKSZ]
2704 [key & ((1 << SECBLKSZ) - 1)];
2705 }
2706 }
2707
2708 /* If we have a usable attrib value. Try applying */
2709 badattrib = FALSE;
2710 if (opt_e && (attrib != INVALID_FILE_ATTRIBUTES)) {
2711#ifdef WIN32
2712 badattrib = !SetFileAttributesW((LPCWSTR)fullname, attrib);
2713#else
2714 badattrib = !ntfs_set_file_attributes(ntfs_context, fullname, attrib);
2715#endif
2716 if (badattrib) {
2717 printf("** Could not set Windows attrib of ");
2718 printname(stdout,fullname);
2719 printf(" to 0x%x\n", attrib);
2720 printerror(stdout);
2721 warnings++;
2722 }
2723 }
2724
2725 if (withattr) {
2726 if (psecurdata) {
2727 newattr = (char*)malloc(ntfs_attr_size(attr));
2728 if (newattr) {
2729 memcpy(newattr,attr,ntfs_attr_size(attr));
2730 psecurdata->attr = newattr;
2731 }
2732 }
2733 curattr = attr;
2734 } else
2735 /*
2736 * No explicit attr in backup, use attr defined
2737 * previously for the same id
2738 */
2739 if (psecurdata)
2740 curattr = psecurdata->attr;
2741
2742
2743 if (curattr) {
2744#ifdef WIN32
2745 selection = OWNER_SECURITY_INFORMATION
2746 | GROUP_SECURITY_INFORMATION
2747 | DACL_SECURITY_INFORMATION;
2748 if (OpenProcessToken(GetCurrentProcess(),
2749 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &htoken)) {
2750 if (LookupPrivilegeValue(NULL, SE_SECURITY_NAME,
2751 &tkp.Privileges[0].Luid)) {
2752 tkp.PrivilegeCount = 1;
2753 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
2754 if (AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0)) {
2755 selection |= SACL_SECURITY_INFORMATION;
2756 }
2757 }
2758 }
Steve Kondik79165c32015-11-09 19:43:00 -08002759 /* const missing from stupid prototype */
Steve Kondik2111ad72013-07-07 12:07:44 -07002760 bad = !SetFileSecurityW((LPCWSTR)fullname,
Steve Kondik79165c32015-11-09 19:43:00 -08002761 selection, (PSECURITY_DESCRIPTOR)(LONG_PTR)curattr);
Steve Kondik2111ad72013-07-07 12:07:44 -07002762 if (bad)
2763 switch (GetLastError()) {
2764 case 1307 :
2765 case 1314 :
2766 printf("** Could not set owner or SACL of ");
2767 printname(stdout,fullname);
2768 printf(", retrying with no owner or SACL setting\n");
2769 warnings++;
Steve Kondik79165c32015-11-09 19:43:00 -08002770 /* const missing from stupid prototype */
Steve Kondik2111ad72013-07-07 12:07:44 -07002771 bad = !SetFileSecurityW((LPCWSTR)fullname,
2772 selection & ~OWNER_SECURITY_INFORMATION
Steve Kondik79165c32015-11-09 19:43:00 -08002773 & ~SACL_SECURITY_INFORMATION,
2774 (PSECURITY_DESCRIPTOR)
2775 (LONG_PTR)curattr);
Steve Kondik2111ad72013-07-07 12:07:44 -07002776 break;
2777 default :
2778 break;
2779 }
2780 /* Release privileges once we are done*/
2781 if (selection ^ SACL_SECURITY_INFORMATION) {
2782 tkp.Privileges[0].Attributes = 0;
2783 AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0);
2784 }
2785#else
2786 selection = OWNER_SECURITY_INFORMATION
2787 | GROUP_SECURITY_INFORMATION
2788 | DACL_SECURITY_INFORMATION
2789 | SACL_SECURITY_INFORMATION;
2790 bad = !ntfs_set_file_security(ntfs_context,fullname,
2791 selection, (const char*)curattr);
2792#endif
2793 if (bad) {
2794 printf("** Could not set the ACL of ");
2795 printname(stdout,fullname);
2796 printf("\n");
2797 printerror(stdout);
2798 err = TRUE;
2799 } else
2800 if (opt_v) {
2801 if (opt_e && !badattrib)
2802 printf("ACL and attrib have been applied to ");
2803 else
2804 printf("ACL has been applied to ");
2805 printname(stdout,fullname);
2806 printf("\n");
2807
2808 }
2809 } else {
2810 printf("** There was no valid ACL for ");
2811 printname(stdout,fullname);
2812 printf("\n");
2813 err = TRUE;
2814 }
2815 return (!err);
2816}
2817
2818/*
2819 * Restore security descriptors from a file
2820 */
2821
2822BOOL restore(FILE *fd)
2823{
2824 static char attr[MAXATTRSZ];
2825 char line[MAXFILENAME+25];
2826 char fullname[MAXFILENAME+25];
2827 SECURITY_DESCRIPTOR_RELATIVE *phead;
2828 int lth;
2829 int first;
2830 unsigned int pos;
2831 int c;
2832 int isdir;
2833 int mode;
2834 s32 key;
2835 BOOL isdump;
2836 unsigned int off;
2837 u32 v;
2838 u32 oldhash;
2839 int i;
2840 int count;
2841 int attrib;
Steve Kondik79165c32015-11-09 19:43:00 -08002842 le32 *pattr;
Steve Kondik2111ad72013-07-07 12:07:44 -07002843 BOOL withattr;
2844 BOOL done;
2845
2846 pos = 0;
2847 off = 0;
2848 done = FALSE;
2849 withattr = FALSE;
2850 oldhash = 0;
2851 key = 0;
2852 errors = 0;
2853 count = 0;
2854 fullname[0] = 0;
2855 attrib = INVALID_FILE_ATTRIBUTES;
2856 do {
2857 /* input a (partial) line without processing */
2858 lth = 0;
2859 first = -1;
2860 do {
2861 c = getc(fd);
2862 if ((c != ' ') && (first < 0))
2863 first = lth;
2864 if (c == EOF)
2865 done = TRUE;
2866 else
2867 if (c != '\r')
2868 line[lth++] = c;
2869 } while (!done && (c != '\n') && (lth < (MAXFILENAME + 24)));
2870 /* check whether this looks like an hexadecimal dump */
2871 isdump = ishexdump(line, first, lth);
2872 if (isdump) off = getmsbhex(&line[first]);
2873 /* line is not an hexadecimal dump */
2874 /* apply what we have in store */
2875 if ((!isdump || !off) && pos && ntfs_valid_descr((char*)attr,pos)) {
2876 withattr = TRUE;
2877 if (opt_v >= 2) {
2878 printf(" Computed hash : 0x%08lx\n",
2879 (unsigned long)hash((le32*)attr,
2880 ntfs_attr_size(attr)));
2881 isdir = guess_dir(attr);
2882 printf(" Estimated type : %s\n",(isdir ? "directory" : "file"));
2883 showheader(attr,4);
2884 showusid(attr,4);
2885 showgsid(attr,4);
2886 showdacl(attr,isdir,4);
2887 showsacl(attr,isdir,4);
2888 mode = linux_permissions(attr,isdir);
Steve Kondik79165c32015-11-09 19:43:00 -08002889 showownership(attr);
Steve Kondik2111ad72013-07-07 12:07:44 -07002890 printf("Interpreted Unix mode 0%03o\n",mode);
2891 }
2892 pos = 0;
2893 }
2894 if (isdump && !off)
2895 pos = off;
2896 /* line looks like an hexadecimal dump */
2897 /* decode it into attribute */
2898 if (isdump && (off == pos)) {
2899 for (i=first+8; i<lth; i+=9) {
Steve Kondik79165c32015-11-09 19:43:00 -08002900 pattr = (le32*)&attr[pos];
Steve Kondik2111ad72013-07-07 12:07:44 -07002901 v = getlsbhex(&line[i]);
Steve Kondik79165c32015-11-09 19:43:00 -08002902 *pattr = cpu_to_le32(v);
Steve Kondik2111ad72013-07-07 12:07:44 -07002903 pos += 4;
2904 }
2905 }
2906 /* display (full) current line unless dump or verbose */
2907 if (!isdump || opt_v) {
2908 if(lth) printf("! ");
2909 for (i=0; i<lth; i++) {
2910 c = line[i];
2911 putchar(c);
2912 }
2913 }
2914 while (!done && (c != '\n')) {
2915 c = getc(fd);
2916 if (c == EOF)
2917 done = TRUE;
2918 else
2919 if (!isdump || opt_v)
2920 putchar(c);
2921 }
2922
2923 line[lth] = 0;
2924 while ((lth > 0)
2925 && ((line[lth-1] == '\n') || (line[lth-1] == '\r')))
2926 line[--lth] = 0;
2927 if (!strncmp(line,"Computed hash : 0x",18))
2928 oldhash = getmsbhex(&line[18]);
2929 if (!strncmp(line,"Security key : 0x",17))
2930 key = getmsbhex(&line[17]);
2931 if (!strncmp(line,"Windows attrib : 0x",19))
2932 attrib = getmsbhex(&line[19]);
2933 if (done
2934 || !strncmp(line,"File ",5)
2935 || !strncmp(line,"Directory ",10)) {
2936 /*
2937 * New file or directory (or end of file) :
2938 * apply attribute just collected
2939 * or apply attribute defined from current key
2940 */
2941
2942 if (withattr
2943 && oldhash
2944 && (hash((const le32*)attr,ntfs_attr_size(attr)) != oldhash)) {
2945 printf("** ACL rejected, its hash is not as expected\n");
2946 errors++;
2947 } else
2948 if (fullname[0]) {
2949 phead = (SECURITY_DESCRIPTOR_RELATIVE*)attr;
2950 /* set the request for auto-inheritance */
2951 if (phead->control & SE_DACL_AUTO_INHERITED)
2952 phead->control |= SE_DACL_AUTO_INHERIT_REQ;
2953 if (!applyattr(fullname,attr,withattr,
2954 attrib,key))
2955 errors++;
2956 else
2957 count++;
2958 }
2959 /* save current file or directory name */
2960 withattr = FALSE;
2961 key = 0;
2962 oldhash = 0;
2963 attrib = INVALID_FILE_ATTRIBUTES;
2964 if (!done) {
2965#ifdef WIN32
2966 if (!strncmp(line,"File ",5))
2967 makeutf16(fullname,&line[5]);
2968 else
2969 makeutf16(fullname,&line[10]);
2970#else
2971 if (!strncmp(line,"File ",5))
2972 strcpy(fullname,&line[5]);
2973 else
2974 strcpy(fullname,&line[10]);
2975#endif
2976 }
2977 }
2978 } while (!done);
2979 printf("%d ACLs have been applied\n",count);
2980 return (FALSE);
2981}
2982
2983/*
2984 * Open the security API in rw mode for an ACL restoration
2985 */
2986
2987#ifdef WIN32
2988#else
2989BOOL dorestore(const char *volume, FILE *fd)
2990{
2991 BOOL err;
2992
2993 err = FALSE;
2994 if (!getuid()) {
2995 if (open_security_api()) {
2996 if (open_volume(volume,NTFS_MNT_NONE)) {
2997 if (restore(fd)) err = TRUE;
2998 close_volume(volume);
2999 } else {
3000 fprintf(stderr,"Could not open volume %s\n",volume);
3001 printerror(stderr);
3002 err = TRUE;
3003 }
3004 close_security_api();
3005 } else {
3006 fprintf(stderr,"Could not open security API\n");
3007 printerror(stderr);
3008 err = TRUE;
3009 }
3010 } else {
3011 fprintf(stderr,"Restore is only possible as root\n");
3012 err = TRUE;
3013 }
3014 return (err);
3015}
3016#endif /* WIN32 */
3017
3018#if POSIXACLS & SELFTESTS & !USESTUBS
3019
3020/*
3021 * Merge Posix ACL rights into an u32 (self test only)
3022 *
3023 * Result format : -----rwxrwxrwxrwxrwx---rwxrwxrwx
3024 * U1 U2 G1 G2 M o g w
3025 *
3026 * Only two users (U1, U2) and two groups (G1, G2) taken into account
3027 */
3028u32 merge_rights(const struct POSIX_SECURITY *pxdesc, BOOL def)
3029{
3030 const struct POSIX_ACE *pxace;
3031 int i;
3032 int users;
3033 int groups;
3034 int first;
3035 int last;
3036 u32 rights;
3037
3038 rights = 0;
3039 users = 0;
3040 groups = 0;
3041 if (def) {
3042 first = pxdesc->firstdef;
3043 last = pxdesc->firstdef + pxdesc->defcnt - 1;
3044 } else {
3045 first = 0;
3046 last = pxdesc->acccnt - 1;
3047 }
3048 pxace = pxdesc->acl.ace;
3049 for (i=first; i<=last; i++) {
3050 switch (pxace[i].tag) {
3051 case POSIX_ACL_USER_OBJ :
3052 rights |= (pxace[i].perms & 7) << 6;
3053 break;
3054 case POSIX_ACL_USER :
3055 if (users < 2)
3056 rights |= ((u32)pxace[i].perms & 7) << (24 - 3*users);
3057 users++;
3058 break;
3059 case POSIX_ACL_GROUP_OBJ :
3060 rights |= (pxace[i].perms & 7) << 3;
3061 break;
3062 case POSIX_ACL_GROUP :
3063 if (groups < 2)
3064 rights |= ((u32)pxace[i].perms & 7) << (18 - 3*groups);
3065 groups++;
3066 break;
3067 case POSIX_ACL_MASK :
3068 rights |= ((u32)pxace[i].perms & 7) << 12;
3069 break;
3070 case POSIX_ACL_OTHER :
3071 rights |= (pxace[i].perms & 7);
3072 break;
3073 default :
3074 break;
3075 }
3076 }
3077 return (rights);
3078}
3079
3080void tryposix(struct POSIX_SECURITY *pxdesc)
3081{
3082 le32 owner_sid[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */
3083 {
Steve Kondike68cb602016-08-28 00:45:36 -07003084 const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000),
3085 const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1),
3086 const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3),
3087 const_cpu_to_le32(1016)
Steve Kondik2111ad72013-07-07 12:07:44 -07003088 } ;
3089 le32 group_sid[] = /* S-1-5-21-3141592653-589793238-462843383-513 */
3090 {
Steve Kondike68cb602016-08-28 00:45:36 -07003091 const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000),
3092 const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1),
3093 const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3),
3094 const_cpu_to_le32(513)
Steve Kondik2111ad72013-07-07 12:07:44 -07003095 } ;
3096
3097 char *attr;
3098 BOOL isdir;
3099 mode_t mode;
3100 struct POSIX_SECURITY *newpxdesc;
3101 struct POSIX_SECURITY *oldpxdesc;
3102 static char *oldattr = (char*)NULL;
3103
3104 isdir = FALSE;
3105 if (oldattr) {
3106 oldpxdesc = linux_permissions_posix(oldattr, isdir);
3107 newpxdesc = ntfs_merge_descr_posix(pxdesc, oldpxdesc);
3108 if (!newpxdesc)
3109 newpxdesc = pxdesc;
3110 free(oldpxdesc);
3111 if (opt_v) {
3112 printf("merged descriptors :\n");
3113 showposix(newpxdesc);
3114 }
3115 } else
3116 newpxdesc = pxdesc;
3117 attr = ntfs_build_descr_posix(context.mapping,newpxdesc,
3118 isdir,(SID*)owner_sid,(SID*)group_sid);
3119 if (attr && ntfs_valid_descr(attr, ntfs_attr_size(attr))) {
3120 if (opt_v)
3121 hexdump(attr,ntfs_attr_size(attr),8);
3122 if (opt_v >= 2) {
3123 showheader(attr,4);
3124 showusid(attr,4);
3125 showgsid(attr,4);
3126 showdacl(attr,isdir,4);
3127 showsacl(attr,isdir,4);
3128 mode = linux_permissions(attr,isdir);
3129 printf("Interpreted Unix mode 0%03o\n",mode);
3130 printf("Interpreted back Posix descriptor :\n");
3131 newpxdesc = linux_permissions_posix(attr,isdir);
3132 showposix(newpxdesc);
3133 free(newpxdesc);
3134 }
3135 if (oldattr) free(oldattr);
3136 oldattr = attr;
3137 }
3138}
3139
3140static BOOL same_posix(struct POSIX_SECURITY *pxdesc1,
3141 struct POSIX_SECURITY *pxdesc2)
3142{
3143 BOOL same;
3144 int i;
3145
3146 same = pxdesc1
3147 && pxdesc2
3148 && (pxdesc1->mode == pxdesc2->mode)
3149 && (pxdesc1->acccnt == pxdesc2->acccnt)
3150 && (pxdesc1->defcnt == pxdesc2->defcnt)
3151 && (pxdesc1->firstdef == pxdesc2->firstdef)
3152 && (pxdesc1->tagsset == pxdesc2->tagsset)
3153 && (pxdesc1->acl.version == pxdesc2->acl.version)
3154 && (pxdesc1->acl.flags == pxdesc2->acl.flags);
3155 i = 0;
3156 while (same && (i < pxdesc1->acccnt)) {
3157 same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag)
3158 && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms)
3159 && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id);
3160 i++;
3161 }
3162 i = pxdesc1->firstdef;
3163 while (same && (i < pxdesc1->firstdef + pxdesc1->defcnt)) {
3164 same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag)
3165 && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms)
3166 && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id);
3167 i++;
3168 }
3169 return (same);
3170}
3171
3172#endif /* POSIXACLS & SELFTESTS & !USESTUBS */
3173
3174#if SELFTESTS & !USESTUBS
3175
3176/*
3177 * Build a dummy security descriptor
3178 * returns descriptor in allocated memory, must free() after use
3179 */
3180
3181static char *build_dummy_descr(BOOL isdir __attribute__((unused)),
3182 const SID *usid, const SID *gsid,
3183 int cnt,
3184 /* seq of int allow, SID *sid, int flags, u32 mask */
3185 ...)
3186{
3187 char *attr;
3188 int attrsz;
3189 SECURITY_DESCRIPTOR_RELATIVE *pnhead;
3190 ACL *pacl;
3191 ACCESS_ALLOWED_ACE *pace;
3192 va_list ap;
3193 const SID *sid;
3194 u32 umask;
3195 le32 mask;
3196 int flags;
3197 BOOL allow;
3198 int pos;
3199 int usidsz;
3200 int gsidsz;
3201 int sidsz;
3202 int aclsz;
3203 int i;
3204
3205 if (usid)
3206 usidsz = ntfs_sid_size(usid);
3207 else
3208 usidsz = 0;
3209 if (gsid)
3210 gsidsz = ntfs_sid_size(gsid);
3211 else
3212 gsidsz = 0;
3213
3214
3215 /* allocate enough space for the new security attribute */
3216 attrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE) /* header */
3217 + usidsz + gsidsz /* usid and gsid */
3218 + sizeof(ACL) /* acl header */
3219 + cnt*40;
3220
3221 attr = (char*)ntfs_malloc(attrsz);
3222 if (attr) {
3223 /* build the main header part */
3224 pnhead = (SECURITY_DESCRIPTOR_RELATIVE*) attr;
3225 pnhead->revision = SECURITY_DESCRIPTOR_REVISION;
3226 pnhead->alignment = 0;
3227 /*
3228 * The flag SE_DACL_PROTECTED prevents the ACL
3229 * to be changed in an inheritance after creation
3230 */
3231 pnhead->control = SE_DACL_PRESENT | SE_DACL_PROTECTED
3232 | SE_SELF_RELATIVE;
3233 /*
3234 * Windows prefers ACL first, do the same to
3235 * get the same hash value and avoid duplication
3236 */
3237 /* build the ACL header */
3238 pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
3239 pacl = (ACL*)&attr[pos];
3240 pacl->revision = ACL_REVISION;
3241 pacl->alignment1 = 0;
Steve Kondike68cb602016-08-28 00:45:36 -07003242 pacl->size = const_cpu_to_le16(0); /* fixed later */
Steve Kondik2111ad72013-07-07 12:07:44 -07003243 pacl->ace_count = cpu_to_le16(cnt);
Steve Kondike68cb602016-08-28 00:45:36 -07003244 pacl->alignment2 = const_cpu_to_le16(0);
Steve Kondik2111ad72013-07-07 12:07:44 -07003245
3246 /* enter the ACEs */
3247
3248 pos += sizeof(ACL);
3249 aclsz = sizeof(ACL);
3250 va_start(ap,cnt);
3251 for (i=0; i<cnt; i++) {
3252 pace = (ACCESS_ALLOWED_ACE*)&attr[pos];
3253 allow = va_arg(ap,int);
3254 sid = va_arg(ap,SID*);
3255 flags = va_arg(ap,int);
3256 umask = va_arg(ap,u32);
3257 mask = cpu_to_le32(umask);
3258 sidsz = ntfs_sid_size(sid);
3259 pace->type = (allow ? ACCESS_ALLOWED_ACE_TYPE : ACCESS_DENIED_ACE_TYPE);
3260 pace->flags = flags;
3261 pace->size = cpu_to_le16(sidsz + 8);
3262 pace->mask = mask;
3263 memcpy(&pace->sid,sid,sidsz);
3264 aclsz += sidsz + 8;
3265 pos += sidsz + 8;
3266 }
3267 va_end(ap);
3268
3269 /* append usid and gsid if defined */
3270 /* positions of ACL, USID and GSID into header */
Steve Kondike68cb602016-08-28 00:45:36 -07003271 pnhead->owner = const_cpu_to_le32(0);
3272 pnhead->group = const_cpu_to_le32(0);
Steve Kondik2111ad72013-07-07 12:07:44 -07003273 if (usid) {
3274 memcpy(&attr[pos], usid, usidsz);
3275 pnhead->owner = cpu_to_le32(pos);
3276 }
3277 if (gsid) {
3278 memcpy(&attr[pos + usidsz], gsid, gsidsz);
3279 pnhead->group = cpu_to_le32(pos + usidsz);
3280 }
3281 /* positions of DACL and SACL into header */
Steve Kondike68cb602016-08-28 00:45:36 -07003282 pnhead->sacl = const_cpu_to_le32(0);
Steve Kondik2111ad72013-07-07 12:07:44 -07003283 if (cnt) {
3284 pacl->size = cpu_to_le16(aclsz);
3285 pnhead->dacl =
Steve Kondike68cb602016-08-28 00:45:36 -07003286 const_cpu_to_le32(sizeof(
3287 SECURITY_DESCRIPTOR_RELATIVE));
Steve Kondik2111ad72013-07-07 12:07:44 -07003288 } else
Steve Kondike68cb602016-08-28 00:45:36 -07003289 pnhead->dacl = const_cpu_to_le32(0);
Steve Kondik2111ad72013-07-07 12:07:44 -07003290 if (!ntfs_valid_descr(attr,pos+usidsz+gsidsz)) {
3291 printf("** Bad sample descriptor\n");
3292 free(attr);
3293 attr = (char*)NULL;
3294 errors++;
3295 }
3296 } else
3297 errno = ENOMEM;
3298 return (attr);
3299}
3300
3301/*
3302 * Check a few samples with special conditions
3303 */
3304
3305void check_samples()
3306{
3307 char *descr = (char*)NULL;
3308 BOOL isdir = FALSE;
3309 mode_t perms;
3310 mode_t expect = 0;
3311 int cnt;
3312 u32 expectacc;
3313 u32 expectdef;
3314#if POSIXACLS
3315 u32 accrights;
3316 u32 defrights;
3317 mode_t mixmode;
3318 struct POSIX_SECURITY *pxdesc;
3319 struct POSIX_SECURITY *pxsample;
3320 const char *txsample;
3321#endif
3322 le32 owner1[] = /* S-1-5-21-1833069642-4243175381-1340018762-1003 */
3323 {
Steve Kondike68cb602016-08-28 00:45:36 -07003324 const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000),
3325 const_cpu_to_le32(21), const_cpu_to_le32(1833069642),
3326 const_cpu_to_le32(4243175381), const_cpu_to_le32(1340018762),
3327 const_cpu_to_le32(1003)
Steve Kondik2111ad72013-07-07 12:07:44 -07003328 } ;
3329 le32 group1[] = /* S-1-5-21-1833069642-4243175381-1340018762-513 */
3330 {
Steve Kondike68cb602016-08-28 00:45:36 -07003331 const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000),
3332 const_cpu_to_le32(21), const_cpu_to_le32(1833069642),
3333 const_cpu_to_le32(4243175381), const_cpu_to_le32(1340018762),
3334 const_cpu_to_le32(513)
Steve Kondik2111ad72013-07-07 12:07:44 -07003335 } ;
3336 le32 group2[] = /* S-1-5-21-1607551490-981732888-1819828000-513 */
3337 {
Steve Kondike68cb602016-08-28 00:45:36 -07003338 const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000),
3339 const_cpu_to_le32(21), const_cpu_to_le32(1607551490),
3340 const_cpu_to_le32(981732888), const_cpu_to_le32(1819828000),
3341 const_cpu_to_le32(513)
Steve Kondik2111ad72013-07-07 12:07:44 -07003342 } ;
3343 le32 owner3[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */
3344 {
Steve Kondike68cb602016-08-28 00:45:36 -07003345 const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000),
3346 const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1),
3347 const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3),
3348 const_cpu_to_le32(1016)
Steve Kondik2111ad72013-07-07 12:07:44 -07003349 } ;
3350 le32 group3[] = /* S-1-5-21-3141592653-589793238-462843383-513 */
3351 {
Steve Kondike68cb602016-08-28 00:45:36 -07003352 const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000),
3353 const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1),
3354 const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3),
3355 const_cpu_to_le32(513)
Steve Kondik2111ad72013-07-07 12:07:44 -07003356 } ;
3357
3358#if POSIXACLS
3359 struct {
3360 struct POSIX_SECURITY head;
3361 struct POSIX_ACE ace[4];
3362 } sampletry1 =
3363 {
3364 { 0645, 4, 0, 4, 0x35,
3365 { POSIX_VERSION, 0, 0 }
3366 },
3367 {
3368 { 1, 6, -1 },
3369 { 4, 5, -1 },
3370 { 16, 4, -1 },
3371 { 32, 5, -1 }
3372 }
3373 } ;
3374
3375 struct {
3376 struct POSIX_SECURITY head;
3377 struct POSIX_ACE ace[6];
3378 } sampletry3 =
3379 {
3380 { 0100, 6, 0, 6, 0x3f,
3381 { POSIX_VERSION, 0, 0 }
3382 },
3383 {
3384 { 1, 1, -1 },
3385 { 2, 3, 1000 },
3386 { 4, 1, -1 },
3387 { 8, 3, 1002 },
3388 { 16, 0, -1 },
3389 { 32, 0, -1 }
3390 }
3391 } ;
3392
3393 struct {
3394 struct POSIX_SECURITY head;
3395 struct POSIX_ACE ace[8];
3396 } sampletry4 =
3397 {
3398 { 0140, 8, 0, 8, 0x3f,
3399 { POSIX_VERSION, 0, 0 }
3400 },
3401 {
3402 { 1, 1, -1 },
3403 { 2, 3, 516 },
3404 { 2, 6, 1000 },
3405 { 4, 1, -1 },
3406 { 8, 6, 500 },
3407 { 8, 3, 1002 },
3408 { 16, 4, -1 },
3409 { 32, 0, -1 }
3410 }
3411 } ;
3412
3413 struct {
3414 struct POSIX_SECURITY head;
3415 struct POSIX_ACE ace[6];
3416 } sampletry5 =
3417 {
3418 { 0454, 6, 0, 6, 0x3f,
3419 { POSIX_VERSION, 0, 0 }
3420 },
3421 {
3422 { 1, 4, -1 },
3423 { 2, 5, 516 },
3424 { 4, 4, -1 },
3425 { 8, 6, 500 },
3426 { 16, 5, -1 },
3427 { 32, 4, -1 }
3428 }
3429 } ;
3430
3431 struct {
3432 struct POSIX_SECURITY head;
3433 struct POSIX_ACE ace[8];
3434 } sampletry6 =
3435 {
3436 { 0332, 8, 0, 8, 0x3f,
3437 { POSIX_VERSION, 0, 0 }
3438 },
3439 {
3440 { 1, 3, -1 },
3441 { 2, 1, 0 },
3442 { 2, 2, 1000 },
3443 { 4, 6, -1 },
3444 { 8, 4, 0 },
3445 { 8, 5, 1002 },
3446 { 16, 3, -1 },
3447 { 32, 2, -1 }
3448 }
3449 } ;
3450
3451 struct {
3452 struct POSIX_SECURITY head;
3453 struct POSIX_ACE ace[4];
3454 } sampletry8 =
3455 {
3456 { 0677, 4, 0, 4, 0x35,
3457 { POSIX_VERSION, 0, 0 }
3458 },
3459 {
3460 { 1, 6, -1 },
3461 { 4, 7, -1 },
3462 { 16, 7, -1 },
3463 { 32, 7, -1 }
3464 }
3465 } ;
3466
3467#endif /* POSIXACLS */
3468
3469
3470#if POSIXACLS
3471 for (cnt=1; cnt<=8; cnt++) {
3472 switch (cnt) {
3473 case 1 :
3474 pxsample = &sampletry1.head;
3475 txsample = "sampletry1-a";
3476 isdir = FALSE;
3477 descr = ntfs_build_descr_posix(context.mapping,&sampletry1.head,
3478 isdir, (const SID*)owner3, (const SID*)group3);
3479 break;
3480 case 2 :
3481 pxsample = &sampletry1.head;
3482 txsample = "sampletry1-b";
3483 isdir = FALSE;
3484 descr = ntfs_build_descr_posix(context.mapping,&sampletry1.head,
3485 isdir, (const SID*)adminsid, (const SID*)group3);
3486 break;
3487 case 3 :
3488 isdir = FALSE;
3489 pxsample = &sampletry3.head;
3490 txsample = "sampletry3";
3491 descr = ntfs_build_descr_posix(context.mapping,pxsample,
3492 isdir, (const SID*)group3, (const SID*)group3);
3493 break;
3494 case 4 :
3495 isdir = FALSE;
3496 pxsample = &sampletry4.head;
3497 txsample = "sampletry4";
3498 descr = ntfs_build_descr_posix(context.mapping,pxsample,
3499 isdir, (const SID*)owner3, (const SID*)group3);
3500 break;
3501 case 5 :
3502 isdir = FALSE;
3503 pxsample = &sampletry5.head;
3504 txsample = "sampletry5";
3505 descr = ntfs_build_descr_posix(context.mapping,pxsample,
3506 isdir, (const SID*)owner3, (const SID*)group3);
3507 break;
3508 case 6 :
3509 isdir = FALSE;
3510 pxsample = &sampletry6.head;
3511 txsample = "sampletry6-a";
3512 descr = ntfs_build_descr_posix(context.mapping,pxsample,
3513 isdir, (const SID*)owner3, (const SID*)group3);
3514 break;
3515 case 7 :
3516 isdir = FALSE;
3517 pxsample = &sampletry6.head;
3518 txsample = "sampletry6-b";
3519 descr = ntfs_build_descr_posix(context.mapping,pxsample,
3520 isdir, (const SID*)adminsid, (const SID*)adminsid);
3521 break;
3522 case 8 :
3523 pxsample = &sampletry8.head;
3524 txsample = "sampletry8";
3525 isdir = FALSE;
3526 descr = ntfs_build_descr_posix(context.mapping,&sampletry8.head,
3527 isdir, (const SID*)owner3, (const SID*)group3);
3528 break;
3529 default :
3530 pxsample = (struct POSIX_SECURITY*)NULL;
3531 txsample = (const char*)NULL;
3532 }
3533 /* check we get original back */
3534 if (descr)
3535 pxdesc = linux_permissions_posix(descr, isdir);
3536 else
3537 pxdesc = (struct POSIX_SECURITY*)NULL;
3538 if (!descr || !pxdesc || !same_posix(pxsample,pxdesc)) {
3539 printf("** Error in %s\n",txsample);
3540 showposix(pxsample);
3541 showall(descr,0);
3542 showposix(pxdesc);
3543 errors++;
3544 }
3545 free(descr);
3546 free(pxdesc);
3547 }
3548
3549#endif /* POSIXACLS */
3550
3551
3552 /*
3553 * Check a few samples built by Windows,
3554 * which cannot be generated by Linux
3555 */
3556
3557 for (cnt=1; cnt<=10; cnt++) {
3558 switch(cnt) {
3559 case 1 : /* hp/tmp */
3560 isdir = TRUE;
3561 descr = build_dummy_descr(isdir,
3562 (const SID*)owner1, (const SID*)group1,
3563 1,
3564 (int)TRUE, worldsid, (int)0x3, (u32)0x1f01ff);
3565 expectacc = expect = 0777;
3566 expectdef = 0;
3567 break;
3568 case 2 : /* swsetup */
3569 isdir = TRUE;
3570 descr = build_dummy_descr(isdir, adminsid, (const SID*)group2,
3571 2,
3572 (int)TRUE, worldsid, (int)0x0, (u32)0x1f01ff,
3573 (int)TRUE, worldsid, (int)0xb, (u32)0x1f01ff);
3574 expectacc = expect = 0777;
3575 expectdef = 0777;
3576 break;
3577 case 3 : /* Dr Watson */
3578 isdir = TRUE;
3579 descr = build_dummy_descr(isdir, (const SID*)owner3, (const SID*)group3,
3580 0);
3581 expectacc = expect = 0700;
3582 expectdef = 0;
3583 break;
3584 case 4 :
3585 isdir = FALSE;
3586 descr = build_dummy_descr(isdir,
3587 (const SID*)owner3, (const SID*)group3,
3588 4,
3589 (int)TRUE, (const SID*)owner3, 0,
3590 le32_to_cpu(FILE_READ_DATA | OWNER_RIGHTS),
3591 (int)TRUE, (const SID*)group3, 0,
3592 le32_to_cpu(FILE_WRITE_DATA),
3593 (int)TRUE, (const SID*)group2, 0,
3594 le32_to_cpu(FILE_WRITE_DATA | FILE_READ_DATA),
3595 (int)TRUE, (const SID*)worldsid, 0,
3596 le32_to_cpu(FILE_EXECUTE));
3597 expect = 0731;
3598 expectacc = 07070731;
3599 expectdef = 0;
3600 break;
3601 case 5 : /* Vista/JP */
3602 isdir = TRUE;
3603 descr = build_dummy_descr(isdir, systemsid, systemsid,
3604 6,
3605 (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff,
3606 (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff,
3607 (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff,
3608 (int)TRUE, owner1, (int)0xb, (u32)0x10000000,
3609 (int)TRUE, systemsid, (int)0xb, (u32)0x10000000,
3610 (int)TRUE, adminsid, (int)0xb, (u32)0x10000000);
3611 expectacc = expect = 0700;
3612 expectdef = 0700;
3613 break;
3614 case 6 : /* Vista/JP2 */
3615 isdir = TRUE;
3616 descr = build_dummy_descr(isdir, systemsid, systemsid,
3617 7,
3618 (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff,
3619 (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff,
3620 (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff,
3621 (int)TRUE, owner1, (int)0xb, (u32)0x1f01ff,
3622 (int)TRUE, systemsid, (int)0xb, (u32)0x1f01ff,
3623 (int)TRUE, adminsid, (int)0xb, (u32)0x1f01ff,
3624 (int)TRUE, owner3, (int)0x3, (u32)0x1200a9);
3625 expectacc = 0500070700;
3626 expectdef = 0700;
3627 expect = 0700;
3628 break;
3629 case 7 : /* WinXP/JP */
3630 isdir = TRUE;
3631 descr = build_dummy_descr(isdir, adminsid, systemsid,
3632 6,
3633 (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff,
3634 (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff,
3635 (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff,
3636 (int)TRUE, owner1, (int)0xb, (u32)0x10000000,
3637 (int)TRUE, systemsid, (int)0xb, (u32)0x10000000,
3638 (int)TRUE, adminsid, (int)0xb, (u32)0x10000000);
3639 expectacc = expect = 0700;
3640 expectdef = 0700;
3641 break;
3642 case 8 : /* WinXP/JP2 */
3643 isdir = TRUE;
3644 descr = build_dummy_descr(isdir, adminsid, systemsid,
3645 6,
3646 (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff,
3647 (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff,
3648 (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff,
3649 (int)TRUE, owner1, (int)0xb, (u32)0x10000000,
3650 (int)TRUE, systemsid, (int)0xb, (u32)0x10000000,
3651 (int)TRUE, adminsid, (int)0xb, (u32)0x10000000);
3652 expectacc = expect = 0700;
3653 expectdef = 0700;
3654 break;
3655 case 9 : /* Win8/bin */
3656 isdir = TRUE;
3657 descr = build_dummy_descr(isdir,
3658 (const SID*)owner3, (const SID*)owner3,
3659 6,
3660 (int)TRUE, authsid, (int)0x3, (u32)0x1f01ff,
3661 (int)TRUE, adminsid, (int)0x13, (u32)0x1f01ff,
3662 (int)TRUE, systemsid, (int)0x13, (u32)0x1f01ff,
3663 (int)TRUE, localsid, (int)0x13, (u32)0x1200a9,
3664 (int)TRUE, authsid, (int)0x10, (u32)0x1301bf,
3665 (int)TRUE, authsid, (int)0x1b, (u32)0xe0010000);
3666 expectacc = expect = 0777;
3667 expectdef = 0777;
3668 break;
3669 case 10 : /* Win8/bin/linem.exe */
3670 isdir = FALSE;
3671 descr = build_dummy_descr(isdir,
3672 (const SID*)owner3, (const SID*)owner3,
3673 4,
3674 (int)TRUE, authsid, (int)0x10, (u32)0x1f01ff,
3675 (int)TRUE, adminsid, (int)0x10, (u32)0x1f01ff,
3676 (int)TRUE, systemsid, (int)0x10, (u32)0x1ff,
3677 (int)TRUE, localsid, (int)0x10, (u32)0x1200a9);
3678 expectacc = expect = 0777;
3679 expectdef = 0;
3680 break;
3681 default :
3682 expectacc = expectdef = 0;
3683 break;
3684 }
3685 if (descr) {
3686 perms = linux_permissions(descr, isdir);
3687 if (perms != expect) {
3688 printf("** Error in sample %d, perms 0%03o expected 0%03o\n",
3689 cnt,perms,expect);
3690 showall(descr,0);
3691 errors++;
3692 } else {
3693#if POSIXACLS
3694 pxdesc = linux_permissions_posix(descr, isdir);
3695 if (pxdesc) {
3696 accrights = merge_rights(pxdesc,FALSE);
3697 defrights = merge_rights(pxdesc,TRUE);
3698 if (!(pxdesc->tagsset & ~(POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER)))
3699 mixmode = expect;
3700 else
3701 mixmode = (expect & 07707) | ((accrights >> 9) & 070);
3702 if ((pxdesc->mode != mixmode)
3703 || (accrights != expectacc)
3704 || (defrights != expectdef)) {
3705 printf("** Error in sample %d : mode %03o expected 0%03o\n",
3706 cnt,pxdesc->mode,mixmode);
3707 printf(" Posix access rights 0%03lo expected 0%03lo\n",
3708 (long)accrights,(long)expectacc);
3709 printf(" default rights 0%03lo expected 0%03lo\n",
3710 (long)defrights,(long)expectdef);
3711 showall(descr,0);
3712 showposix(pxdesc);
3713exit(1);
3714 }
3715 free(pxdesc);
3716 }
3717#endif
3718 }
3719 free(descr);
3720 }
3721 }
3722}
3723
3724
3725/*
3726 * Check whether any basic permission setting is interpreted
3727 * back exactly as set
3728 */
3729
3730void basictest(int kind, BOOL isdir, const SID *owner, const SID *group)
3731{
3732 char *attr;
3733 mode_t perm;
3734 mode_t gotback;
3735 u32 count;
3736 u32 acecount;
3737 u32 globhash;
3738 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3739 const ACL *pacl;
3740 enum { ERRNO,
3741 ERRMA, ERRPA, /* error converting mode or Posix ACL to NTFS */
3742 ERRAM, ERRAP, /* error converting NTFS to mode or Posix ACL */
3743 } err;
3744 u32 expectcnt[] = {
3745 27800, 31896,
3746 24064, 28160,
3747 24064, 28160,
3748 24064, 28160,
Steve Kondike68cb602016-08-28 00:45:36 -07003749 24904, 29000
Steve Kondik2111ad72013-07-07 12:07:44 -07003750 } ;
3751 u32 expecthash[] = {
3752 0x8f80865b, 0x7bc7960,
3753 0x8fd9ecfe, 0xddd4db0,
3754 0xa8b07400, 0xa189c20,
3755 0xc5689a00, 0xb6c09000,
Steve Kondike68cb602016-08-28 00:45:36 -07003756 0xb040e509, 0x4f4db7f7
Steve Kondik2111ad72013-07-07 12:07:44 -07003757 } ;
3758#if POSIXACLS
3759 struct POSIX_SECURITY *pxdesc;
3760 char *pxattr;
3761 u32 pxcount;
3762 u32 pxacecount;
3763 u32 pxglobhash;
3764#endif
3765
3766 count = 0;
3767 acecount = 0;
3768 globhash = 0;
3769#if POSIXACLS
3770 pxcount = 0;
3771 pxacecount = 0;
3772 pxglobhash = 0;
3773#endif
3774 for (perm=0; (perm<=07777) && (errors < 10); perm++) {
3775 err = ERRNO;
3776 /* file owned by plain user and group */
3777 attr = ntfs_build_descr(perm,isdir,owner,(const SID*)group);
3778 if (attr && ntfs_valid_descr(attr, ntfs_attr_size(attr))) {
3779 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
3780 pacl = (const ACL*)&attr[le32_to_cpu(phead->dacl)];
3781 acecount += le16_to_cpu(pacl->ace_count);
3782 globhash += hash((const le32*)attr,ntfs_attr_size(attr));
3783 count++;
3784#if POSIXACLS
3785 /*
3786 * Build a NTFS ACL from a mode, and
3787 * decode to a Posix ACL, expecting to
3788 * get the original mode back.
3789 */
3790 pxdesc = linux_permissions_posix(attr, isdir);
3791 if (!pxdesc || (pxdesc->mode != perm)) {
3792 err = ERRAP;
3793 if (pxdesc)
3794 gotback = pxdesc->mode;
3795 else
3796 gotback = 0;
3797 } else {
3798 /*
3799 * Build a NTFS ACL from the Posix ACL, expecting to
3800 * get exactly the same NTFS ACL, then decode to a
3801 * mode, expecting to get the original mode back.
3802 */
3803 pxattr = ntfs_build_descr_posix(context.mapping,
3804 pxdesc,isdir,owner,
3805 (const SID*)group);
3806 if (pxattr && !memcmp(pxattr,attr,
3807 ntfs_attr_size(attr))) {
3808 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
3809 pacl = (const ACL*)&attr[le32_to_cpu(phead->dacl)];
3810 pxacecount += le16_to_cpu(pacl->ace_count);
3811 pxglobhash += hash((const le32*)attr,ntfs_attr_size(attr));
3812 pxcount++;
3813 gotback = linux_permissions(pxattr, isdir);
3814 if (gotback != perm)
3815 err = ERRAM;
3816 else
3817 free(pxattr);
3818 } else
3819 err = ERRPA;
3820 free(attr);
3821 }
3822 free(pxdesc);
3823#else
3824 gotback = linux_permissions(attr, isdir);
3825 if (gotback != perm)
3826 err = ERRAM;
3827 else
3828 free(attr);
3829#endif /* POSIXACLS */
3830 } else
3831 err = ERRMA;
3832
3833 switch (err) {
3834 case ERRMA :
3835 printf("** no or wrong permission settings "
3836 "for kind %d perm %03o\n",kind,perm);
3837 if (attr && opt_v)
3838 hexdump(attr,ntfs_attr_size(attr),8);
3839 if (attr && (opt_v >= 2)) {
3840 showheader(attr,4);
3841 showusid(attr,4);
3842 showgsid(attr,4);
3843 showdacl(attr,isdir,4);
3844 showsacl(attr,isdir,4);
3845 }
3846 errors++;
3847 break;
3848 case ERRPA :
3849 printf("** no or wrong permission settings from PX "
3850 "for kind %d perm %03o\n",kind,perm);
3851 errors++;
3852 break;
3853#if POSIXACLS
3854 case ERRAM :
3855 printf("** wrong permission settings, "
3856 "kind %d perm 0%03o, gotback %03o\n",
3857 kind, perm, gotback);
3858 if (opt_v)
3859 hexdump(pxattr,ntfs_attr_size(pxattr),8);
3860 if (opt_v >= 2) {
3861 showheader(pxattr,4);
3862 showusid(pxattr,4);
3863 showgsid(pxattr,4);
3864 showdacl(pxattr,isdir,4);
3865 showsacl(pxattr,isdir,4);
3866 }
3867 errors++;
3868 break;
3869 case ERRAP :
3870 /* continued */
3871#else
3872 case ERRAM :
3873 case ERRAP :
3874#endif /* POSIXACLS */
3875 printf("** wrong permission settings, "
3876 "kind %d perm 0%03o, gotback %03o\n",
3877 kind, perm, gotback);
3878 if (opt_v)
3879 hexdump(attr,ntfs_attr_size(attr),8);
3880 if (opt_v >= 2) {
3881 showheader(attr,4);
3882 showusid(attr,4);
3883 showgsid(attr,4);
3884 showdacl(attr,isdir,4);
3885 showsacl(attr,isdir,4);
3886 }
3887 errors++;
3888 free(attr);
3889 break;
3890 default :
3891 break;
3892 }
3893 }
3894 printf("%lu ACLs built from mode, %lu ACE built, mean count %lu.%02lu\n",
3895 (unsigned long)count,(unsigned long)acecount,
3896 (unsigned long)acecount/count,acecount*100L/count%100L);
3897 if (acecount != expectcnt[kind]) {
Steve Kondike68cb602016-08-28 00:45:36 -07003898 printf("** Error : ACE count %lu instead of %lu\n",
3899 (unsigned long)acecount,
Steve Kondik2111ad72013-07-07 12:07:44 -07003900 (unsigned long)expectcnt[kind]);
3901 errors++;
3902 }
3903 if (globhash != expecthash[kind]) {
3904 printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n",
3905 (unsigned long)globhash, (unsigned long)expecthash[kind]);
3906 errors++;
3907 }
3908#if POSIXACLS
3909 printf("%lu ACLs built from Posix ACLs, %lu ACE built, mean count %lu.%02lu\n",
3910 (unsigned long)pxcount,(unsigned long)pxacecount,
3911 (unsigned long)pxacecount/pxcount,pxacecount*100L/pxcount%100L);
3912 if (pxacecount != expectcnt[kind]) {
Steve Kondike68cb602016-08-28 00:45:36 -07003913 printf("** Error : ACE count %lu instead of %lu\n",
3914 (unsigned long)pxacecount,
Steve Kondik2111ad72013-07-07 12:07:44 -07003915 (unsigned long)expectcnt[kind]);
3916 errors++;
3917 }
3918 if (pxglobhash != expecthash[kind]) {
3919 printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n",
3920 (unsigned long)pxglobhash, (unsigned long)expecthash[kind]);
3921 errors++;
3922 }
3923#endif /* POSIXACLS */
3924}
3925
3926#if POSIXACLS
3927
3928/*
3929 * Check whether Posix ACL settings are interpreted
3930 * back exactly as set
3931 */
3932
3933void posixtest(int kind, BOOL isdir,
3934 const SID *owner, const SID *group)
3935{
3936 struct POSIX_SECURITY *pxdesc;
3937 struct {
3938 struct POSIX_SECURITY pxdesc;
3939 struct POSIX_ACE aces[10];
3940 } desc;
3941 int ownobj;
3942 int grpobj;
3943 int usr;
3944 int grp;
3945 int wrld;
3946 int mask;
3947 int mindes, maxdes;
3948 int minmsk, maxmsk;
3949 char *pxattr;
3950 u32 count;
3951 u32 acecount;
3952 u32 globhash;
3953 const SECURITY_DESCRIPTOR_RELATIVE *phead;
3954 const ACL *pacl;
3955 struct POSIX_SECURITY *gotback;
3956 enum { ERRNO,
3957 ERRMA, ERRPA, /* error converting mode or Posix ACL to NTFS */
3958 ERRAM, ERRAP, /* error converting NTFS to mode or Posix ACL */
3959 } err;
3960 u32 expectcnt[] = {
3961#ifdef STSC
3962 32400, 34992,
3963 25920, 28512,
3964 25920, 28512,
3965 25920, 28512,
3966 26460, 29052,
3967 0, 0,
3968 0, 0,
3969 0, 0,
3970 24516, 27108,
3971 20736, 23328,
3972 20736, 23328,
3973 20736, 23328,
3974 21060, 23652,
3975#else
3976 252720, 273456,
3977 199584, 220320,
3978 199584, 220320,
3979 199584, 220320,
3980 203904, 224640,
3981 0, 0,
3982 0, 0,
3983 0, 0,
3984 196452, 217188,
3985 165888, 186624,
3986 165888, 186624,
3987 165888, 186624,
3988 168480, 189216,
3989#endif
3990 0, 0,
3991 0, 0,
3992 0, 0,
3993 16368, 18672,
3994 0, 0,
3995 13824, 0,
3996 0, 0,
3997 14640, 0
3998 } ;
3999 u32 expecthash[] = {
4000#ifdef STSC
4001 0xf9f82115, 0x40666647,
4002 0xde826d30, 0xa181b660,
4003 0x952d4500, 0x8ac49450,
4004 0xf80acee0, 0xbd9ec6c0,
4005 0xfe09b868, 0xde24e84d,
4006 0, 0,
4007 0, 0,
4008 0, 0,
4009 0x2381438d, 0x3ab42dc6,
4010 0x7cccf6f8, 0x108ad430,
4011 0x5e448840, 0x83ab6c40,
4012 0x9b037100, 0x8f7c3b40,
4013 0x04a359dc, 0xa4619609,
4014#else
4015 0x1808a6cd, 0xd82f7c60,
4016 0x5ad29e85, 0x518c7620,
4017 0x188ce270, 0x7e44e590,
4018 0x48a64800, 0x5bdf0030,
4019 0x1c64aec6, 0x8b0168fa,
4020 0, 0,
4021 0, 0,
4022 0, 0,
4023 0x169fb80e, 0x382d9a59,
4024 0xf9c28164, 0x1855d352,
4025 0xf9685700, 0x44d16700,
4026 0x587ebe90, 0xf7c51480,
4027 0x2cb1b518, 0x52408df6,
4028#endif
4029 0, 0,
4030 0, 0,
4031 0, 0,
4032 0x905f2e38, 0xd40c22f0,
4033 0, 0,
4034 0xdd76da00, 0,
4035 0, 0,
4036 0x718e34a0, 0
4037 };
4038
4039 count = 0;
4040 acecount = 0;
4041 globhash = 0;
4042 /* fill headers */
4043 pxdesc = &desc.pxdesc;
4044 pxdesc->mode = 0;
4045 pxdesc->defcnt = 0;
4046 if (kind & 32) {
4047 pxdesc->acccnt = 4;
4048 pxdesc->firstdef = 4;
4049 pxdesc->tagsset = 0x35;
4050 } else {
4051 pxdesc->acccnt = 6;;
4052 pxdesc->firstdef = 6;
4053 pxdesc->tagsset = 0x3f;
4054 }
4055 pxdesc->acl.version = POSIX_VERSION;
4056 pxdesc->acl.flags = 0;
4057 pxdesc->acl.filler = 0;
4058 /* prefill aces */
4059 pxdesc->acl.ace[0].tag = POSIX_ACL_USER_OBJ;
4060 pxdesc->acl.ace[0].id = -1;
4061 if (kind & 32) {
4062 pxdesc->acl.ace[1].tag = POSIX_ACL_GROUP_OBJ;
4063 pxdesc->acl.ace[1].id = -1;
4064 pxdesc->acl.ace[2].tag = POSIX_ACL_MASK;
4065 pxdesc->acl.ace[2].id = -1;
4066 pxdesc->acl.ace[3].tag = POSIX_ACL_OTHER;
4067 pxdesc->acl.ace[3].id = -1;
4068 } else {
4069 pxdesc->acl.ace[1].tag = POSIX_ACL_USER;
4070 pxdesc->acl.ace[1].id = (kind & 16 ? 0 : 1000);
4071 pxdesc->acl.ace[2].tag = POSIX_ACL_GROUP_OBJ;
4072 pxdesc->acl.ace[2].id = -1;
4073 pxdesc->acl.ace[3].tag = POSIX_ACL_GROUP;
4074 pxdesc->acl.ace[3].id = (kind & 16 ? 0 : 1002);
4075 pxdesc->acl.ace[4].tag = POSIX_ACL_MASK;
4076 pxdesc->acl.ace[4].id = -1;
4077 pxdesc->acl.ace[5].tag = POSIX_ACL_OTHER;
4078 pxdesc->acl.ace[5].id = -1;
4079 }
4080
4081 mindes = 3;
4082 maxdes = (kind & 32 ? mindes : 6);
4083#ifdef STSC
4084 minmsk = (kind & 32 ? 0 : 3);
4085 maxmsk = (kind & 32 ? 7 : 3);
4086#else
4087 minmsk = 0;
4088 maxmsk = 7;
4089#endif
4090 for (mask=minmsk; mask<=maxmsk; mask++)
4091 for (ownobj=1; ownobj<7; ownobj++)
4092 for (grpobj=1; grpobj<7; grpobj++)
4093 for (wrld=0; wrld<8; wrld++)
4094 for (usr=mindes; usr<=maxdes; usr++)
4095 if (usr != 4)
4096 for (grp=mindes; grp<=maxdes; grp++)
4097 if (grp != 4) {
4098 pxdesc->mode = (ownobj << 6) | (mask << 3) | wrld;
4099
4100 pxdesc->acl.ace[0].perms = ownobj;
4101 if (kind & 32) {
4102 pxdesc->acl.ace[1].perms = grpobj;
4103 pxdesc->acl.ace[2].perms = mask;
4104 pxdesc->acl.ace[3].perms = wrld;
4105 } else {
4106 pxdesc->acl.ace[1].perms = usr;
4107 pxdesc->acl.ace[2].perms = grpobj;
4108 pxdesc->acl.ace[3].perms = grp;
4109 pxdesc->acl.ace[4].perms = mask;
4110 pxdesc->acl.ace[5].perms = wrld;
4111 }
4112
4113 err = ERRNO;
4114 gotback = (struct POSIX_SECURITY*)NULL;
4115 pxattr = ntfs_build_descr_posix(context.mapping,
4116 pxdesc,isdir,owner,group);
4117 if (pxattr && ntfs_valid_descr(pxattr, ntfs_attr_size(pxattr))) {
4118 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)pxattr;
4119 pacl = (const ACL*)&pxattr[le32_to_cpu(phead->dacl)];
4120 acecount += le16_to_cpu(pacl->ace_count);
4121 globhash += hash((const le32*)pxattr,ntfs_attr_size(pxattr));
4122 count++;
4123 gotback = linux_permissions_posix(pxattr, isdir);
4124 if (gotback) {
4125 if (ntfs_valid_posix(gotback)) {
4126 if (!same_posix(pxdesc,gotback)) {
4127 printf("Non matching got back Posix ACL\n");
4128 printf("input ACL\n");
4129 showposix(pxdesc);
4130 printf("NTFS owner\n");
4131 showusid(pxattr,4);
4132 printf("NTFS group\n");
4133 showgsid(pxattr,4);
4134 printf("NTFS DACL\n");
4135 showdacl(pxattr,isdir,4);
4136 printf("gotback ACL\n");
4137 showposix(gotback);
4138 errors++;
4139exit(1);
4140 }
4141 } else {
4142 printf("Got back an invalid Posix ACL\n");
4143 errors++;
4144 }
4145 free(gotback);
4146 } else {
4147 printf("Could not get Posix ACL back\n");
4148 errors++;
4149 }
4150
4151 } else {
4152 printf("NTFS ACL incorrect or not build\n");
4153 printf("input ACL\n");
4154 showposix(pxdesc);
4155 printf("NTFS DACL\n");
4156 if (pxattr)
4157 showdacl(pxattr,isdir,4);
4158 else
4159 printf(" (none)\n");
4160 if (gotback) {
4161 printf("gotback ACL\n");
4162 showposix(gotback);
4163 } else
4164 printf("no gotback ACL\n");
4165 errors++;
4166 }
4167 if (pxattr)
4168 free(pxattr);
4169 }
4170 printf("%lu ACLs built from Posix ACLs, %lu ACE built, mean count %lu.%02lu\n",
4171 (unsigned long)count,(unsigned long)acecount,
4172 (unsigned long)acecount/count,acecount*100L/count%100L);
4173 if (acecount != expectcnt[kind]) {
4174 printf("** Error ! expected ACE count %lu\n",
4175 (unsigned long)expectcnt[kind]);
4176 errors++;
4177 }
4178 if (globhash != expecthash[kind]) {
4179 printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n",
4180 (unsigned long)globhash, (unsigned long)expecthash[kind]);
4181 errors++;
4182 }
4183}
4184
4185#endif /* POSIXACLS */
4186
4187void selftests(void)
4188{
4189 le32 owner_sid[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */
4190 {
Steve Kondike68cb602016-08-28 00:45:36 -07004191 const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000),
4192 const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1),
4193 const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3),
4194 const_cpu_to_le32(1016)
Steve Kondik2111ad72013-07-07 12:07:44 -07004195 } ;
4196 le32 group_sid[] = /* S-1-5-21-3141592653-589793238-462843383-513 */
4197 {
Steve Kondike68cb602016-08-28 00:45:36 -07004198 const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000),
4199 const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1),
4200 const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3),
4201 const_cpu_to_le32(513)
Steve Kondik2111ad72013-07-07 12:07:44 -07004202 } ;
4203#if POSIXACLS
4204#ifdef STSC
4205 unsigned char kindlist[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
4206 16, 17, 18, 20, 22, 24,
4207 32, 33, 36, 40 } ;
4208#else
4209 unsigned char kindlist[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
4210 16, 17, 18, 20, 22, 24, 19, 21, 23, 25,
4211 32, 33, 36, 40 } ;
4212#endif
4213 unsigned int k;
4214#endif /* POSIXACLS */
4215 int kind;
4216 const SID *owner;
4217 const SID *group;
4218 BOOL isdir;
4219
4220#if POSIXACLS
4221 local_build_mapping(context.mapping, (const char*)NULL);
4222#endif
4223 /* first check samples */
4224 mappingtype = MAPDUMMY;
4225 check_samples();
4226if (errors) exit(1);
4227 /*
4228 * kind is oring of :
4229 * 1 : directory
4230 * 2 : owner is root
4231 * 4 : group is root
4232 * 8 : group is owner
4233 * 16 : root is designated user/group
4234 * 32 : mask present with no designated user/group
4235 */
4236 for (kind=0; (kind<10) && (errors<10); kind++) {
4237 isdir = kind & 1;
4238 if (kind & 8)
4239 owner = (const SID*)group_sid;
4240 else
4241 owner = (kind & 2 ? adminsid : (const SID*)owner_sid);
4242 group = (kind & 4 ? adminsid : (const SID*)group_sid);
4243 basictest(kind, isdir, owner, group);
4244 }
4245#if POSIXACLS
4246 for (k=0; (k<sizeof(kindlist)) && (errors<10); k++) {
4247 kind = kindlist[k];
4248 isdir = kind & 1;
4249 if (kind & 8)
4250 owner = (const SID*)group_sid;
4251 else
4252 owner = (kind & 2 ? adminsid : (const SID*)owner_sid);
4253 group = (kind & 4 ? adminsid : (const SID*)group_sid);
4254 posixtest(kind, isdir, owner, group);
4255 }
4256 ntfs_free_mapping(context.mapping);
4257#endif
4258 if (errors >= 10)
4259 printf("** too many errors, test aborted\n");
4260}
4261#endif /* SELFTESTS & !USESTUBS */
4262
4263#ifdef WIN32
4264
4265/*
4266 * Get the security descriptor of a file (Windows version)
4267 */
4268
4269unsigned int getfull(char *attr, const char *fullname)
4270{
4271 static char part[MAXATTRSZ];
4272 BIGSID ownsid;
4273 int xowner;
4274 int ownersz;
4275 u16 ownerfl;
4276 ULONG attrsz;
4277 ULONG partsz;
4278 BOOL overflow;
4279 HANDLE htoken;
4280 TOKEN_PRIVILEGES tkp;
4281 BOOL saclsuccess;
4282
4283 attrsz = 0;
4284 partsz = 0;
4285 overflow = FALSE;
4286 if (GetFileSecurityW((LPCWSTR)fullname,OWNER_SECURITY_INFORMATION,
4287 (char*)part,MAXATTRSZ,&partsz)) {
4288 xowner = get4l(part,4);
4289 if (xowner) {
4290 ownerfl = get2l(part,2);
4291 ownersz = ntfs_sid_size((SID*)&part[xowner]);
4292 if (ownersz <= (int)sizeof(BIGSID))
4293 memcpy(ownsid,&part[xowner],ownersz);
4294 else
4295 overflow = TRUE;
4296 } else {
4297 ownerfl = 0;
4298 ownersz = 0;
4299 }
4300 /*
4301 * SACL : just feed in or clean
4302 * This requires the SE_SECURITY_NAME privilege
4303 */
4304 saclsuccess = FALSE;
4305 if (OpenProcessToken(GetCurrentProcess(),
4306 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &htoken)) {
4307 if (LookupPrivilegeValue(NULL, SE_SECURITY_NAME,
4308 &tkp.Privileges[0].Luid)) {
4309 tkp.PrivilegeCount = 1;
4310 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
4311 if (AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0)) {
4312 if (GetFileSecurityW((LPCWSTR)fullname,
4313 SACL_SECURITY_INFORMATION,
4314 (char*)attr,MAXATTRSZ,&attrsz)) {
4315 saclsuccess = TRUE;
4316 }
4317 tkp.Privileges[0].Attributes = 0;
4318 AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0);
4319 }
4320 }
4321 }
4322 if (!saclsuccess) {
4323 attrsz = 20;
4324 set4l(attr,0);
4325 attr[0] = SECURITY_DESCRIPTOR_REVISION;
4326 set4l(&attr[12],0);
4327 if (opt_v >= 2)
4328 printf(" No SACL\n");
4329 }
4330 /*
4331 * append DACL and merge its flags
4332 */
4333 partsz = 0;
4334 set4l(&attr[16],0);
4335 if (GetFileSecurityW((LPCWSTR)fullname,DACL_SECURITY_INFORMATION,
4336 (char*)part,MAXATTRSZ,&partsz)) {
4337 if ((attrsz + partsz - 20) <= MAXATTRSZ) {
4338 memcpy(&attr[attrsz],&part[20],partsz-20);
4339 set4l(&attr[16],(partsz > 20 ? attrsz : 0));
4340 set2l(&attr[2],get2l(attr,2) | (get2l(part,2)
4341 & const_le16_to_cpu(SE_DACL_PROTECTED
4342 | SE_DACL_AUTO_INHERITED
4343 | SE_DACL_PRESENT)));
4344 attrsz += partsz - 20;
4345 } else
4346 overflow = TRUE;
4347 } else
4348 if (partsz > MAXATTRSZ)
4349 overflow = TRUE;
4350 else {
4351 if (opt_b)
4352 printf("# No discretionary access control list\n");
4353 else
4354 printf(" No discretionary access control list\n");
4355 warnings++;
4356 }
4357
4358 /*
4359 * append owner and merge its flag
4360 */
4361 if (xowner && !overflow) {
4362 memcpy(&attr[attrsz],ownsid,ownersz);
4363 set4l(&attr[4],attrsz);
4364 set2l(&attr[2],get2l(attr,2)
4365 | (ownerfl & const_le16_to_cpu(SE_OWNER_DEFAULTED)));
4366 attrsz += ownersz;
4367 } else
4368 set4l(&attr[4],0);
4369 /*
4370 * append group
4371 */
4372 partsz = 0;
4373 set4l(&attr[8],0);
4374 if (GetFileSecurityW((LPCWSTR)fullname,GROUP_SECURITY_INFORMATION,
4375 (char*)part,MAXATTRSZ,&partsz)) {
4376 if ((attrsz + partsz - 20) <= MAXATTRSZ) {
4377 memcpy(&attr[attrsz],&part[20],partsz-20);
4378 set4l(&attr[8],(partsz > 20 ? attrsz : 0));
4379 set2l(&attr[2],get2l(attr,2) | (get2l(part,2)
4380 & const_le16_to_cpu(SE_GROUP_DEFAULTED)));
4381 attrsz += partsz - 20;
4382 } else
4383 overflow = TRUE;
4384 } else
4385 if (partsz > MAXATTRSZ)
4386 overflow = TRUE;
4387 else {
4388 printf("** No group SID\n");
4389 warnings++;
4390 }
4391 set2l(&attr[2],get2l(attr,2)
4392 | const_le16_to_cpu(SE_SELF_RELATIVE));
4393 if (overflow) {
4394 printf("** Descriptor was too long (> %d)\n",MAXATTRSZ);
4395 warnings++;
4396 attrsz = 0;
4397 } else
4398 if (!ntfs_valid_descr((char*)attr,attrsz)) {
4399 printf("** Descriptor for ");
4400 printname(stdout,fullname);
4401 printf(" is not valid\n");
4402 errors++;
4403 attrsz = 0;
4404 }
4405
4406 } else {
4407 printf("** Could not get owner of ");
4408 printname(stdout,fullname);
4409 printf(", partsz %d\n",partsz);
4410 printerror(stdout);
4411 warnings++;
4412 attrsz = 0;
4413 }
4414 return (attrsz);
4415}
4416
4417/*
4418 * Update a security descriptor (Windows version)
4419 */
4420
4421BOOL updatefull(const char *name, DWORD flags, char *attr)
4422{
4423 BOOL bad;
4424
4425 bad = !SetFileSecurityW((LPCWSTR)name, flags, attr);
4426 if (bad
4427 && (flags & OWNER_SECURITY_INFORMATION)
4428 && (GetLastError() == 1307)) {
4429 printf("** Could not set owner of ");
4430 printname(stdout,name);
4431 printf(", retrying with no owner setting\n");
4432 warnings++;
4433 bad = !SetFileSecurityW((LPCWSTR)name,
4434 flags & ~OWNER_SECURITY_INFORMATION, (char*)attr);
4435 }
4436 if (bad) {
4437 printf("** Could not change attributes of ");
4438 printname(stdout,name);
4439 printf("\n");
4440 printerror(stdout);
4441 errors++;
4442 }
4443 return (!bad);
4444}
4445
4446#else
4447
4448/*
4449 * Get the security descriptor of a file (Linux version)
4450 */
4451
4452unsigned int getfull(char *attr, const char *fullname)
4453{
4454 static char part[MAXATTRSZ];
4455 BIGSID ownsid;
4456 int xowner;
4457 int ownersz;
4458 u16 ownerfl;
4459 u32 attrsz;
4460 u32 partsz;
4461 BOOL overflow;
4462
4463 attrsz = 0;
4464 partsz = 0;
4465 overflow = FALSE;
4466 if (ntfs_get_file_security(ntfs_context,fullname,
4467 OWNER_SECURITY_INFORMATION,
4468 (char*)part,MAXATTRSZ,&partsz)) {
4469 xowner = get4l(part,4);
4470 if (xowner) {
4471 ownerfl = get2l(part,2);
4472 ownersz = ntfs_sid_size((SID*)&part[xowner]);
4473 if (ownersz <= (int)sizeof(BIGSID))
4474 memcpy(ownsid,&part[xowner],ownersz);
4475 else
4476 overflow = TRUE;
4477 } else {
4478 ownerfl = 0;
4479 ownersz = 0;
4480 }
4481 /*
4482 * SACL : just feed in or clean
4483 */
4484 if (!ntfs_get_file_security(ntfs_context,fullname,
4485 SACL_SECURITY_INFORMATION,
4486 (char*)attr,MAXATTRSZ,&attrsz)) {
4487 attrsz = 20;
4488 set4l(attr,0);
4489 attr[0] = SECURITY_DESCRIPTOR_REVISION;
4490 set4l(&attr[12],0);
4491 if (opt_v >= 2)
4492 printf(" No SACL\n");
4493 }
4494 /*
4495 * append DACL and merge its flags
4496 */
4497 partsz = 0;
4498 set4l(&attr[16],0);
4499 if (ntfs_get_file_security(ntfs_context,fullname,
4500 DACL_SECURITY_INFORMATION,
4501 (char*)part,MAXATTRSZ,&partsz)) {
4502 if ((attrsz + partsz - 20) <= MAXATTRSZ) {
4503 memcpy(&attr[attrsz],&part[20],partsz-20);
4504 set4l(&attr[16],(partsz > 20 ? attrsz : 0));
4505 set2l(&attr[2],get2l(attr,2) | (get2l(part,2)
4506 & const_le16_to_cpu(SE_DACL_PROTECTED
4507 | SE_DACL_AUTO_INHERITED
4508 | SE_DACL_PRESENT)));
4509 attrsz += partsz - 20;
4510 } else
4511 overflow = TRUE;
4512 } else
4513 if (partsz > MAXATTRSZ)
4514 overflow = TRUE;
4515 else {
4516 if (opt_b)
4517 printf("# No discretionary access control list\n");
4518 else
4519 printf(" No discretionary access control list\n");
4520 warnings++;
4521 }
4522
4523 /*
4524 * append owner and merge its flag
4525 */
4526 if (xowner && !overflow) {
4527 memcpy(&attr[attrsz],ownsid,ownersz);
4528 set4l(&attr[4],attrsz);
4529 set2l(&attr[2],get2l(attr,2)
4530 | (ownerfl & const_le16_to_cpu(SE_OWNER_DEFAULTED)));
4531 attrsz += ownersz;
4532 } else
4533 set4l(&attr[4],0);
4534 /*
4535 * append group
4536 */
4537 partsz = 0;
4538 set4l(&attr[8],0);
4539 if (ntfs_get_file_security(ntfs_context,fullname,
4540 GROUP_SECURITY_INFORMATION,
4541 (char*)part,MAXATTRSZ,&partsz)) {
4542 if ((attrsz + partsz - 20) <= MAXATTRSZ) {
4543 memcpy(&attr[attrsz],&part[20],partsz-20);
4544 set4l(&attr[8],(partsz > 20 ? attrsz : 0));
4545 set2l(&attr[2],get2l(attr,2) | (get2l(part,2)
4546 & const_le16_to_cpu(SE_GROUP_DEFAULTED)));
4547 attrsz += partsz - 20;
4548 } else
4549 overflow = TRUE;
4550 } else
4551 if (partsz > MAXATTRSZ)
4552 overflow = TRUE;
4553 else {
4554 printf("** No group SID\n");
4555 warnings++;
4556 }
4557 if (overflow) {
4558 printf("** Descriptor was too long (> %d)\n",MAXATTRSZ);
4559 warnings++;
4560 attrsz = 0;
4561 } else
4562 if (!ntfs_valid_descr((char*)attr,attrsz)) {
4563 printf("** Descriptor for %s is not valid\n",fullname);
4564 errors++;
4565 attrsz = 0;
4566 }
4567
4568 } else {
4569 printf("** Could not get owner of %s\n",fullname);
4570 warnings++;
4571 attrsz = 0;
4572 }
4573 return (attrsz);
4574}
4575
4576/*
4577 * Update a security descriptor (Linux version)
4578 */
4579
4580BOOL updatefull(const char *name, DWORD flags, char *attr)
4581{
4582 BOOL ok;
4583
4584 ok = !ntfs_set_file_security(ntfs_context, name, flags, attr);
4585 if (ok) {
4586 printf("** Could not change attributes of %s\n",name);
4587 printerror(stdout);
4588 errors++;
4589 }
4590 return (ok);
4591}
4592
4593
4594#endif
4595
4596#if POSIXACLS
4597
4598/*
4599 * Set all the parameters associated to a file
4600 */
4601
4602BOOL setfull_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc,
4603 BOOL isdir)
4604{
4605 static char attr[MAXATTRSZ];
4606 struct POSIX_SECURITY *oldpxdesc;
4607 struct POSIX_SECURITY *newpxdesc;
4608 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4609 char *newattr;
4610 int err;
4611 unsigned int attrsz;
4612 int newattrsz;
4613 const SID *usid;
4614 const SID *gsid;
4615#if OWNERFROMACL
4616 const SID *osid;
4617#endif
4618
4619 printf("%s ",(isdir ? "Directory" : "File"));
4620 printname(stdout,fullname);
4621 if (pxdesc->acccnt)
4622 printf("\n");
4623 else
4624 printf(" mode 0%03o\n",pxdesc->mode);
4625
4626 err = FALSE;
4627 attrsz = getfull(attr, fullname);
4628 if (attrsz) {
4629 oldpxdesc = linux_permissions_posix(attr, isdir);
4630 if (opt_v >= 2) {
4631 printf("Posix equivalent of old ACL :\n");
4632 showposix(oldpxdesc);
4633 }
4634 if (oldpxdesc) {
4635 if (!pxdesc->defcnt
4636 && !(pxdesc->tagsset &
4637 (POSIX_ACL_USER | POSIX_ACL_GROUP | POSIX_ACL_MASK))) {
4638 if (!ntfs_merge_mode_posix(oldpxdesc,pxdesc->mode))
4639 newpxdesc = oldpxdesc;
4640 else {
4641 newpxdesc = (struct POSIX_SECURITY*)NULL;
4642 free(oldpxdesc);
4643 }
4644 } else {
4645 newpxdesc = ntfs_merge_descr_posix(pxdesc, oldpxdesc);
4646 free(oldpxdesc);
4647 }
4648 if (opt_v) {
4649 printf("New Posix ACL :\n");
4650 showposix(newpxdesc);
4651 }
4652 } else
4653 newpxdesc = (struct POSIX_SECURITY*)NULL;
4654 if (newpxdesc) {
4655 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4656 gsid = (const SID*)&attr[le32_to_cpu(phead->group)];
4657#if OWNERFROMACL
4658 osid = (const SID*)&attr[le32_to_cpu(phead->owner)];
4659 usid = ntfs_acl_owner((const char*)attr);
4660 if (!ntfs_same_sid(usid,osid))
4661 printf("== Windows owner might change\n");
4662#else
4663 usid = (const SID*)&attr[le32_to_cpu(phead->owner)];
4664#endif
4665 newattr = ntfs_build_descr_posix(context.mapping,
4666 newpxdesc,isdir,usid,gsid);
4667 free(newpxdesc);
4668 } else
4669 newattr = (char*)NULL;
4670 if (newattr) {
4671 newattrsz = ntfs_attr_size(newattr);
4672 if (opt_v) {
4673 printf("New NTFS security descriptor\n");
4674 hexdump(newattr,newattrsz,4);
4675 }
4676 if (opt_v >= 2) {
4677 printf("Expected hash : 0x%08lx\n",
4678 (unsigned long)hash((le32*)newattr,ntfs_attr_size(newattr)));
4679 showheader(newattr,0);
4680 showusid(newattr,0);
4681 showgsid(newattr,0);
4682 showdacl(newattr,isdir,0);
4683 showsacl(newattr,isdir,0);
4684 }
4685
4686#ifdef WIN32
4687 /*
4688 * avoid getting a set owner error on Windows
4689 * owner should not be changed anyway
4690 */
4691 if (!updatefull(fullname,
4692 DACL_SECURITY_INFORMATION
4693 | GROUP_SECURITY_INFORMATION
4694 | OWNER_SECURITY_INFORMATION,
4695 newattr))
4696#else
4697 if (!updatefull(fullname,
4698 DACL_SECURITY_INFORMATION
4699 | GROUP_SECURITY_INFORMATION
4700 | OWNER_SECURITY_INFORMATION,
4701 newattr))
4702#endif
4703 err = TRUE;
4704/*
4705{
4706struct POSIX_SECURITY *interp;
4707printf("Reinterpreted new Posix :\n");
4708interp = linux_permissions_posix(newattr,isdir);
4709showposix(interp);
4710free(interp);
4711}
4712*/
4713 free(newattr);
4714 } else
4715 err = TRUE;
4716 } else
4717 err = TRUE;
4718 return (!err);
4719}
4720
4721#endif
4722
4723BOOL setfull(const char *fullname, int mode, BOOL isdir)
4724{
4725 static char attr[MAXATTRSZ];
4726 const SECURITY_DESCRIPTOR_RELATIVE *phead;
4727 char *newattr;
4728 int err;
4729 unsigned int attrsz;
4730 int newattrsz;
4731 const SID *usid;
4732 const SID *gsid;
4733#if OWNERFROMACL
4734 const SID *osid;
4735#endif
4736
4737 printf("%s ",(isdir ? "Directory" : "File"));
4738 printname(stdout,fullname);
4739 printf(" mode 0%03o\n",mode);
4740 attrsz = getfull(attr, fullname);
4741 err = FALSE;
4742 if (attrsz) {
4743 phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
4744 gsid = (const SID*)&attr[le32_to_cpu(phead->group)];
4745#if OWNERFROMACL
4746 osid = (const SID*)&attr[le32_to_cpu(phead->owner)];
4747 usid = ntfs_acl_owner((const char*)attr);
4748 if (!ntfs_same_sid(usid,osid))
4749 printf("== Windows owner might change\n");
4750#else
4751 usid = (const SID*)&attr[le32_to_cpu(phead->owner)];
4752#endif
4753 newattr = ntfs_build_descr(mode,isdir,usid,gsid);
4754 if (newattr) {
4755 newattrsz = ntfs_attr_size(newattr);
4756 if (opt_v) {
4757 printf("Security descriptor\n");
4758 hexdump(newattr,newattrsz,4);
4759 }
4760 if (opt_v >= 2) {
4761 printf("Expected hash : 0x%08lx\n",
4762 (unsigned long)hash((le32*)newattr,ntfs_attr_size(newattr)));
4763 showheader(newattr,0);
4764 showusid(newattr,0);
4765 showgsid(newattr,0);
4766 showdacl(newattr,isdir,0);
4767 showsacl(newattr,isdir,0);
4768 }
4769
4770#ifdef WIN32
4771 /*
4772 * avoid getting a set owner error on Windows
4773 * owner should not be changed anyway
4774 */
4775 if (!updatefull(fullname,
4776 DACL_SECURITY_INFORMATION
4777 | GROUP_SECURITY_INFORMATION
4778 | OWNER_SECURITY_INFORMATION,
4779 newattr))
4780#else
4781 if (!updatefull(fullname,
4782 DACL_SECURITY_INFORMATION
4783 | GROUP_SECURITY_INFORMATION
4784 | OWNER_SECURITY_INFORMATION,
4785 newattr))
4786#endif
4787 err = TRUE;
4788 free(newattr);
4789 }
4790
4791 } else
4792 err = TRUE;
4793 return (err);
4794}
4795
4796BOOL proposal(const char *name, const char *attr)
4797{
Steve Kondik79165c32015-11-09 19:43:00 -08004798 char fullname[MAXFILENAME];
Steve Kondik2111ad72013-07-07 12:07:44 -07004799 int uoff, goff;
4800 int i;
4801 u64 uauth, gauth;
4802 int ucnt, gcnt;
4803 int uid, gid;
4804 BOOL err;
Steve Kondik79165c32015-11-09 19:43:00 -08004805#ifdef WIN32
4806 char driveletter;
4807#else
4808 struct stat st;
4809 char *p,*q;
4810#endif
Steve Kondik2111ad72013-07-07 12:07:44 -07004811
4812 err = FALSE;
4813#ifdef WIN32
4814 uid = gid = 0;
4815#else
4816 uid = getuid();
4817 gid = getgid();
4818#endif
4819 uoff = get4l(attr,4);
4820 uauth = get6h(attr,uoff+2);
4821 ucnt = attr[uoff+1] & 255;
4822 goff = get4l(attr,8);
4823 gauth = get6h(attr,goff+2);
4824 gcnt = attr[goff+1] & 255;
4825
4826 if ((ucnt == 5) && (gcnt == 5)
4827 && (uauth == 5) && (gauth == 5)
4828 && (get4l(attr,uoff+8) == 21) && (get4l(attr,goff+8) == 21)) {
Steve Kondik79165c32015-11-09 19:43:00 -08004829 printf("# User mapping proposal :\n");
4830 printf("# -------------------- cut here -------------------\n");
Steve Kondik2111ad72013-07-07 12:07:44 -07004831 if (uid)
4832 printf("%d::",uid);
4833 else
4834 printf("user::");
4835 printf("S-%d-%llu",attr[uoff] & 255,uauth);
4836 for (i=0; i<ucnt; i++)
4837 printf("-%lu",get4l(attr,uoff+8+4*i));
4838 printf("\n");
4839 if (gid)
4840 printf(":%d:",gid);
4841 else
4842 printf(":group:");
4843 printf("S-%d-%llu",attr[goff] & 255,gauth);
4844 for (i=0; i<gcnt; i++)
4845 printf("-%lu",get4l(attr,goff+8+4*i));
4846 printf("\n");
4847 /* generic rule, based on group */
4848 printf("::S-%d-%llu",attr[goff] & 255,gauth);
4849 for (i=0; i<gcnt-1; i++)
4850 printf("-%lu",get4l(attr,goff+8+4*i));
4851 printf("-10000\n");
Steve Kondik79165c32015-11-09 19:43:00 -08004852 printf("# -------------------- cut here -------------------\n");
Steve Kondik2111ad72013-07-07 12:07:44 -07004853 if (!uid || !gid) {
Steve Kondik79165c32015-11-09 19:43:00 -08004854 printf("# Please replace \"user\" and \"group\" above by the uid\n");
4855 printf("# and gid of the Linux owner and group of ");
Steve Kondik2111ad72013-07-07 12:07:44 -07004856 printname(stdout,name);
Steve Kondik79165c32015-11-09 19:43:00 -08004857 printf(", then\n");
Steve Kondike68cb602016-08-28 00:45:36 -07004858 printf("# insert the modified lines into .NTFS-3G/UserMapping, with .NTFS-3G\n");
Steve Kondik79165c32015-11-09 19:43:00 -08004859 } else
Steve Kondike68cb602016-08-28 00:45:36 -07004860 printf("# Insert the above lines into .NTFS-3G/UserMapping, with .NTFS-3G\n");
Steve Kondik79165c32015-11-09 19:43:00 -08004861#ifdef WIN32
4862 printf("# being a directory of the root of the NTFS file system.\n");
4863
4864 /* Get the drive letter to the file system */
4865 driveletter = 0;
4866 if ((((name[0] >= 'a') && (name[0] <= 'z'))
4867 || ((name[0] >= 'A') && (name[0] <= 'Z')))
4868 && (name[1] == ':'))
4869 driveletter = name[0];
4870 else {
4871 if (GetCurrentDirectoryA(MAXFILENAME, fullname)
4872 && (fullname[1] == ':'))
4873 driveletter = fullname[0];
Steve Kondik2111ad72013-07-07 12:07:44 -07004874 }
Steve Kondik79165c32015-11-09 19:43:00 -08004875 if (driveletter) {
4876 printf("# Example : %c:\\.NTFS-3G\\UserMapping\n",
4877 driveletter);
4878 }
4879#else
4880 printf("# being a hidden subdirectory of the root of the NTFS file system.\n");
4881
4882 /* Get the path to the root of the file system */
4883 if (name[0] != '/') {
4884 p = getcwd(fullname,MAXFILENAME);
4885 if (p) {
4886 strcat(fullname,"/");
4887 strcat(fullname,name);
4888 }
4889 } else {
4890 strcpy(fullname,name);
4891 p = fullname;
4892 }
4893 if (p) {
4894 /* go down the path to inode 5 (fails on symlinks) */
4895 do {
4896 lstat(fullname,&st);
4897 q = strrchr(p,'/');
4898 if (q && (st.st_ino != 5))
4899 *q = 0;
4900 } while (strchr(p,'/') && (st.st_ino != 5));
4901 }
4902 if (p && (st.st_ino == 5)) {
4903 printf("# Example : ");
4904 printname(stdout,p);
4905 printf("/.NTFS-3G/UserMapping\n");
4906 }
4907#endif
Steve Kondik2111ad72013-07-07 12:07:44 -07004908 } else {
4909 printf("** Not possible : ");
4910 printname(stdout,name);
4911 printf(" was not created by a Windows user\n");
4912 err = TRUE;
4913 }
4914 return (err);
4915}
4916
4917#ifdef WIN32
4918
4919/*
4920 * Check whether a directory with reparse data is a junction
4921 * or a symbolic link
4922 */
4923
4924BOOL islink(const char *filename)
4925{
4926 WIN32_FIND_DATAW found;
4927 HANDLE search;
4928 BOOL link;
4929
4930 link = FALSE;
4931 search = FindFirstFileW((LPCWSTR)filename, &found);
4932 if (search != INVALID_HANDLE_VALUE) {
4933 link = (found.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)
4934 || (found.dwReserved0 == IO_REPARSE_TAG_SYMLINK);
4935 FindClose(search);
4936 }
4937 return (link);
4938}
4939
4940#if POSIXACLS
4941BOOL iterate(RECURSE call, const char *fullname, const struct POSIX_SECURITY *pxdesc)
4942#else
4943BOOL iterate(RECURSE call, const char *fullname, mode_t mode)
4944#endif
4945{
4946 WIN32_FIND_DATAW found;
4947 HANDLE search;
4948 BOOL err;
4949 unsigned int len;
4950 char *filter;
4951 char *inner;
4952
4953 err = FALSE;
4954 filter = (char*)malloc(MAXFILENAME);
4955 inner = (char*)malloc(MAXFILENAME);
4956 if (filter && inner) {
4957 len = utf16len(fullname);
4958 memcpy(filter, fullname, 2*len);
4959 makeutf16(&filter[2*len],"\\*.*");
4960 search = FindFirstFileW((LPCWSTR)filter, &found);
4961 if (search != INVALID_HANDLE_VALUE) {
4962 do {
4963 if (found.cFileName[0] != UNICODE('.')) {
4964 memcpy(inner, fullname, 2*len);
4965 inner[2*len] = '\\';
4966 inner[2*len+1] = 0;
4967 memcpy(&inner[2*len+2],found.cFileName,
4968 2*utf16len((char*)found.cFileName)+2);
4969 if (opt_v)
4970 if (opt_b)
4971 printf("#\n#\n");
4972 else
4973 printf("\n\n");
4974 switch (call) {
4975 case RECSHOW :
4976 if (recurseshow(inner))
4977 err = TRUE;
4978 break;
4979#if POSIXACLS
4980 case RECSETPOSIX :
4981 if (recurseset_posix(inner,pxdesc))
4982 err = TRUE;
4983 break;
4984#else
4985 case RECSET :
4986 if (recurseset(inner,mode))
4987 err = TRUE;
4988 break;
4989#endif
4990 default :
4991 err = TRUE;
4992 }
4993 }
4994 } while (FindNextFileW(search, &found));
4995 FindClose(search);
4996 }
4997 free(filter);
4998 free(inner);
4999 } else {
5000 printf("** Cannot process deeper : not enough memory\n");
5001 errors++;
5002 err = TRUE;
5003 }
5004 return (err);
5005}
5006
5007
5008
5009/*
5010 * Display all the parameters associated to a file (Windows version)
5011 */
5012
5013void showfull(const char *fullname, BOOL isdir)
5014{
5015 static char attr[MAXATTRSZ];
5016#if POSIXACLS
5017 struct POSIX_SECURITY *pxdesc;
5018#endif
5019 ULONG attrsz;
5020 int mode;
5021 uid_t uid;
5022 gid_t gid;
5023 int attrib;
5024 int level;
5025
5026 printf("%s ",(isdir ? "Directory" : "File"));
5027 printname(stdout,fullname);
5028 printf("\n");
5029
5030 /* get individual parameters, as when trying to get them */
5031 /* all, and one (typically SACL) is missing, we get none, */
5032 /* and concatenate them, to be able to compute the hash code */
5033
5034 attrsz = getfull(attr, fullname);
5035 if (attrsz) {
5036 if (opt_v || opt_b) {
5037 hexdump(attr,attrsz,8);
5038 printf("Computed hash : 0x%08lx\n",
5039 (unsigned long)hash((le32*)attr,attrsz));
5040 }
5041 if (opt_v && opt_b) {
5042 printf("# %s ",(isdir ? "Directory" : "File"));
5043 printname(stdout,fullname);
5044 printf(" hash 0x%lx\n",
5045 (unsigned long)hash((le32*)attr,attrsz));
5046 }
5047 attrib = GetFileAttributesW((LPCWSTR)fullname);
5048 if (attrib == INVALID_FILE_ATTRIBUTES) {
5049 printf("** Could not get file attrib\n");
5050 errors++;
5051 } else
5052 printf("Windows attrib : 0x%x\n",attrib);
5053 if (ntfs_valid_descr(attr,attrsz)) {
5054#if POSIXACLS
5055 pxdesc = linux_permissions_posix(attr,isdir);
5056 if (pxdesc)
5057 mode = pxdesc->mode;
5058 else
5059 mode = 0;
5060#else
5061 mode = linux_permissions(attr,isdir);
5062#endif
5063 if (opt_v >= 2) {
5064 level = (opt_b ? 4 : 0);
5065 showheader(attr,level);
5066 showusid(attr,level);
5067 showgsid(attr,level);
5068 showdacl(attr,isdir,level);
5069 showsacl(attr,isdir,level);
5070 }
5071 uid = linux_owner(attr);
5072 gid = linux_group(attr);
5073 if (opt_b) {
Steve Kondik79165c32015-11-09 19:43:00 -08005074 showownership(attr);
Steve Kondik2111ad72013-07-07 12:07:44 -07005075 printf("# Interpreted Unix owner %d, group %d, mode 0%03o\n",
5076 (int)uid,(int)gid,mode);
5077 } else {
Steve Kondik79165c32015-11-09 19:43:00 -08005078 showownership(attr);
Steve Kondik2111ad72013-07-07 12:07:44 -07005079 printf("Interpreted Unix owner %d, group %d, mode 0%03o\n",
5080 (int)uid,(int)gid,mode);
5081 }
5082#if POSIXACLS
5083 if (pxdesc) {
5084 if (!opt_b
5085 && (pxdesc->defcnt
5086 || (pxdesc->tagsset
5087 & (POSIX_ACL_USER
5088 | POSIX_ACL_GROUP
5089 | POSIX_ACL_MASK))))
5090 showposix(pxdesc);
5091 free(pxdesc);
5092 }
5093#endif
5094 } else
5095 if (opt_b)
5096 printf("# Descriptor fails sanity check\n");
5097 else
5098 printf("Descriptor fails sanity check\n");
5099 }
5100}
5101
5102BOOL recurseshow(const char *fullname)
5103{
5104 int attrib;
5105 int err;
5106 BOOL isdir;
5107
5108 err = FALSE;
5109 attrib = GetFileAttributesW((LPCWSTR)fullname);
5110 if (attrib != INVALID_FILE_ATTRIBUTES) {
5111 isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0;
5112 showfull(fullname,isdir);
5113 if (isdir
5114 && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT)
5115 && islink(fullname))) {
5116#if POSIXACLS
5117 err = iterate(RECSHOW, fullname, (struct POSIX_SECURITY*)NULL);
5118#else
5119 err = iterate(RECSHOW, fullname, 0);
5120#endif
5121 }
5122 } else {
5123 printf("** Could not access ");
5124 printname(stdout,fullname);
5125 printf("\n");
5126 printerror(stdout);
5127 errors++;
5128 err = TRUE;
5129 }
5130 return (err);
5131}
5132
5133
5134BOOL singleshow(const char *fullname)
5135{
5136 int attrib;
5137 int err;
5138 BOOL isdir;
5139
5140 err = FALSE;
5141 attrib = GetFileAttributesW((LPCWSTR)fullname);
5142 if (attrib != INVALID_FILE_ATTRIBUTES) {
5143 isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0;
5144 showfull(fullname,isdir);
5145 } else {
5146 printf("** Could not access ");
5147 printname(stdout,fullname);
5148 printf("\n");
5149 printerror(stdout);
5150 errors++;
5151 err = TRUE;
5152 }
5153 return (err);
5154}
5155
5156BOOL mapproposal(const char *fullname)
5157{
5158 char attr[256];
5159 ULONG attrsz;
5160 int attrib;
5161 int err;
5162
5163 err = FALSE;
5164 attrsz = 0;
5165 attrib = GetFileAttributesW((LPCWSTR)fullname);
5166 if ((attrib != INVALID_FILE_ATTRIBUTES)
5167 && GetFileSecurityW((LPCWSTR)fullname,
5168 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
5169 (char*)attr,256,&attrsz)) {
5170 err = proposal(fullname,attr);
5171 } else {
5172 printf("** Could not access ");
5173 printname(stdout,fullname);
5174 printf("\n");
5175 printerror(stdout);
5176 err = TRUE;
5177 }
5178 return (err);
5179}
5180
5181#if POSIXACLS
5182
5183BOOL recurseset_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc)
5184{
5185 int attrib;
5186 int err;
5187 BOOL isdir;
5188
5189 err = FALSE;
5190 attrib = GetFileAttributesW((LPCWSTR)fullname);
5191 if (attrib != INVALID_FILE_ATTRIBUTES) {
5192 isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0;
5193 err = !setfull_posix(fullname,pxdesc,isdir);
5194 if (err) {
5195 printf("** Failed to update ");
5196 printname(stdout,fullname);
5197 printf("\n");
5198 errors++;
5199 } else
5200 if (isdir
5201 && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT)
5202 && islink(fullname)))
5203 iterate(RECSETPOSIX, fullname, pxdesc);
5204 } else {
5205 err = GetLastError();
5206 printf("** Could not access ");
5207 printname(stdout,fullname);
5208 printf("\n");
5209 printerror(stdout);
5210 err = TRUE;
5211 errors++;
5212 }
5213 return (err);
5214}
5215
5216#else
5217
5218BOOL recurseset(const char *fullname, int mode)
5219{
5220 int attrib;
5221 int err;
5222 BOOL isdir;
5223
5224 err = FALSE;
5225 attrib = GetFileAttributesW((LPCWSTR)fullname);
5226 if (attrib != INVALID_FILE_ATTRIBUTES) {
5227 isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0;
5228 setfull(fullname,mode,isdir);
5229 if (isdir
5230 && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT)
5231 && islink(fullname)))
5232 iterate(RECSETPOSIX, fullname, mode);
5233 } else {
5234 err = GetLastError();
5235 printf("** Could not access ");
5236 printname(stdout,fullname);
5237 printf("\n");
5238 printerror(stdout);
5239 err = TRUE;
5240 errors++;
5241 }
5242 return (err);
5243}
5244
5245#endif
5246
5247#if POSIXACLS
5248
5249BOOL singleset_posix(const char *path, const struct POSIX_SECURITY *pxdesc)
5250{
5251 BOOL isdir;
5252 BOOL err;
5253 int attrib;
5254
5255 err = FALSE;
5256 attrib = GetFileAttributesW((LPCWSTR)path);
5257 if (attrib != INVALID_FILE_ATTRIBUTES) {
5258 isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY);
5259 err = !setfull_posix(path,pxdesc,isdir);
5260 if (err) {
5261 printf("** Failed to update ");
5262 printname(stdout,path);
5263 printf("\n");
5264 errors++;
5265 }
5266 } else {
5267 printf("** Could not access ");
5268 printname(stdout,path);
5269 printf("\n");
5270 printerror(stdout);
5271 errors++;
5272 err = TRUE;
5273 }
5274 return (!err);
5275}
5276
5277#endif
5278
5279BOOL singleset(const char *path, int mode)
5280{
5281 BOOL isdir;
5282 BOOL err;
5283 int attrib;
5284
5285 err = FALSE;
5286 attrib = GetFileAttributesW((LPCWSTR)path);
5287 if (attrib != INVALID_FILE_ATTRIBUTES) {
5288 isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY);
5289 setfull(path,mode,isdir);
5290 } else {
5291 printf("** Could not access ");
5292 printname(stdout,path);
5293 printf("\n");
5294 printerror(stdout);
5295 errors++;
5296 err = TRUE;
5297 }
5298 return (!err);
5299}
5300
5301#else
5302
5303/*
5304 * Display all the parameters associated to a file (Linux version)
5305 */
5306
5307void showfull(const char *fullname, BOOL isdir)
5308{
5309 static char attr[MAXATTRSZ];
5310 static char part[MAXATTRSZ];
5311#if POSIXACLS
5312 struct POSIX_SECURITY *pxdesc;
5313#endif
5314 struct SECURITY_DATA *psecurdata;
5315 char *newattr;
5316 int securindex;
5317 int mode;
5318 int level;
5319 int attrib;
5320 u32 attrsz;
5321 u32 partsz;
5322 uid_t uid;
5323 gid_t gid;
5324
5325 if (opt_v || opt_b)
5326 printf("%s %s\n",(isdir ? "Directory" : "File"),fullname);
5327
5328 /* get individual parameters, as when trying to get them */
5329 /* all, and one (typically SACL) is missing, we get none */
5330 /* and concatenate them, to be able to compute the checksum */
5331
5332 partsz = 0;
5333 securindex = ntfs_get_file_security(ntfs_context,fullname,
5334 OWNER_SECURITY_INFORMATION,
5335 (char*)part,MAXATTRSZ,&partsz);
5336
5337 attrib = ntfs_get_file_attributes(ntfs_context, fullname);
5338 if (attrib == INVALID_FILE_ATTRIBUTES) {
5339 printf("** Could not get file attrib\n");
5340 errors++;
5341 }
5342 if ((securindex < 0)
5343 || (securindex >= MAXSECURID)
5344 || ((securindex > 0)
5345 && ((!opt_r && !opt_b)
5346 || !securdata[securindex >> SECBLKSZ]
5347 || !securdata[securindex >> SECBLKSZ][securindex & ((1 << SECBLKSZ) - 1)].filecount)))
5348 {
5349 if (opt_v || opt_b) {
5350 if ((securindex < -1) || (securindex >= MAXSECURID))
5351 printf("Security key : 0x%x out of range\n",securindex);
5352 else
5353 if (securindex == -1)
5354 printf("Security key : none\n");
5355 else
5356 printf("Security key : 0x%x\n",securindex);
5357 } else {
5358 printf("%s %s",(isdir ? "Directory" : "File"),fullname);
5359 if ((securindex < -1) || (securindex >= MAXSECURID))
5360 printf(" : key 0x%x out of range\n",securindex);
5361 else
5362 if (securindex == -1)
5363 printf(" : no key\n");
5364 else
5365 printf(" : key 0x%x\n",securindex);
5366 }
5367
5368 attrsz = getfull(attr, fullname);
5369 if (attrsz) {
5370 psecurdata = (struct SECURITY_DATA*)NULL;
5371 if ((securindex < MAXSECURID) && (securindex > 0)) {
5372 if (!securdata[securindex >> SECBLKSZ])
5373 newblock(securindex);
5374 if (securdata[securindex >> SECBLKSZ])
5375 psecurdata = &securdata[securindex >> SECBLKSZ]
5376 [securindex & ((1 << SECBLKSZ) - 1)];
5377 }
5378 if (opt_v && (opt_a || opt_b) && psecurdata) {
5379 newattr = (char*)malloc(attrsz);
5380 printf("# %s %s hash 0x%lx\n",(isdir ? "Directory" : "File"),
5381 fullname,
5382 (unsigned long)hash((le32*)attr,attrsz));
5383 if (newattr) {
5384 memcpy(newattr,attr,attrsz);
5385 psecurdata->attr = newattr;
5386 }
5387 }
5388 if ((opt_v || opt_b)
5389 && ((securindex >= MAXSECURID)
5390 || (securindex <= 0)
5391 || !psecurdata
5392 || (!psecurdata->filecount
5393 && !psecurdata->flags))) {
5394 hexdump(attr,attrsz,8);
5395 printf("Computed hash : 0x%08lx\n",
5396 (unsigned long)hash((le32*)attr,attrsz));
5397 }
5398 if (ntfs_valid_descr((char*)attr,attrsz)) {
5399#if POSIXACLS
5400 pxdesc = linux_permissions_posix(attr,isdir);
5401 if (pxdesc)
5402 mode = pxdesc->mode;
5403 else
5404 mode = 0;
5405#else
5406 mode = linux_permissions(attr,isdir);
5407#endif
5408 attrib = ntfs_get_file_attributes(ntfs_context,fullname);
5409 if (opt_v >= 2) {
5410 level = (opt_b ? 4 : 0);
5411 showheader(attr,level);
5412 showusid(attr,level);
5413 showgsid(attr,level);
5414 showdacl(attr,isdir,level);
5415 showsacl(attr,isdir,level);
5416 }
5417 if (attrib != INVALID_FILE_ATTRIBUTES)
5418 printf("Windows attrib : 0x%x\n",attrib);
5419 uid = linux_owner(attr);
5420 gid = linux_group(attr);
5421 if (opt_b) {
Steve Kondik79165c32015-11-09 19:43:00 -08005422 showownership(attr);
Steve Kondik2111ad72013-07-07 12:07:44 -07005423 printf("# Interpreted Unix owner %d, group %d, mode 0%03o\n",
5424 (int)uid,(int)gid,mode);
5425 } else {
Steve Kondik79165c32015-11-09 19:43:00 -08005426 showownership(attr);
Steve Kondik2111ad72013-07-07 12:07:44 -07005427 printf("Interpreted Unix owner %d, group %d, mode 0%03o\n",
5428 (int)uid,(int)gid,mode);
5429 }
5430#if POSIXACLS
5431 if (pxdesc) {
5432 if (!opt_b
5433 && (pxdesc->defcnt
5434 || (pxdesc->tagsset
5435 & (POSIX_ACL_USER
5436 | POSIX_ACL_GROUP
5437 | POSIX_ACL_MASK))))
5438 showposix(pxdesc);
5439#if USESTUBS
5440 stdfree(pxdesc); /* allocated within library */
5441#else
5442 free(pxdesc);
5443#endif
5444 }
5445#endif
5446 if ((opt_r || opt_b) && (securindex < MAXSECURID)
5447 && (securindex > 0) && psecurdata) {
5448 psecurdata->filecount++;
5449 psecurdata->mode = mode;
5450 }
5451 } else {
5452 printf("** Descriptor fails sanity check\n");
5453 errors++;
5454 }
5455 }
5456 } else
5457 if (securindex > 0) {
5458 if (securdata[securindex >> SECBLKSZ]) {
5459 psecurdata = &securdata[securindex >> SECBLKSZ]
5460 [securindex & ((1 << SECBLKSZ) - 1)];
5461 psecurdata->filecount++;
5462 if (opt_b || opt_r) {
5463 if (!opt_b && !opt_v)
5464 printf("%s %s\n",(isdir ? "Directory" : "File"),fullname);
5465 printf("Security key : 0x%x mode %03o (already displayed)\n",
5466 securindex,psecurdata->mode);
5467 if (attrib != INVALID_FILE_ATTRIBUTES)
5468 printf("Windows attrib : 0x%x\n",attrib);
5469 } else {
5470 printf("%s %s",(isdir ? "Directory" : "File"),fullname);
5471 printf(" : key 0x%x\n",securindex);
5472 }
5473 if ((opt_a || opt_b) && opt_v
5474 && psecurdata && psecurdata->attr) {
5475 printf("# %s %s hash 0x%lx\n",(isdir ? "Directory" : "File"),
5476 fullname,
5477 (unsigned long)hash((le32*)psecurdata->attr,
5478 ntfs_attr_size(psecurdata->attr)));
5479 }
5480 }
5481 } else {
5482 if (!opt_v && !opt_b)
5483 printf("%s %s",(isdir ? "Directory" : "File"),fullname);
5484 printf(" (Failed)\n");
5485 printf("** Could not get security data of %s, partsz %d\n",
5486 fullname,partsz);
5487 printerror(stdout);
5488 errors++;
5489 }
5490}
5491
5492BOOL recurseshow(const char *path)
5493{
5494 struct CALLBACK dircontext;
5495 struct LINK *current;
5496 BOOL isdir;
5497 BOOL err;
5498
5499 err = FALSE;
5500 dircontext.head = (struct LINK*)NULL;
5501 dircontext.dir = path;
5502 isdir = ntfs_read_directory(ntfs_context, path,
5503 callback, &dircontext);
5504 if (isdir) {
5505 showfull(path,TRUE);
5506 if (opt_v) {
5507 if (opt_b)
5508 printf("#\n#\n");
5509 else
5510 printf("\n\n");
5511 }
5512 while (dircontext.head) {
5513 current = dircontext.head;
5514 if (recurseshow(current->name)) err = TRUE;
5515 dircontext.head = dircontext.head->next;
5516 free(current);
5517 }
5518 } else
5519 if (errno == ENOTDIR) {
5520 showfull(path,FALSE);
5521 if (opt_v) {
5522 if (opt_b)
5523 printf("#\n#\n");
5524 else
5525 printf("\n\n");
5526 }
5527 } else {
5528 printf("** Could not access %s\n",path);
5529 printerror(stdout);
5530 errors++;
5531 err = TRUE;
5532 }
5533 return (!err);
5534}
5535
5536
5537BOOL singleshow(const char *path)
5538{
5539 BOOL isdir;
5540 BOOL err;
5541
5542 err = FALSE;
5543 isdir = ntfs_read_directory(ntfs_context, path,
5544 callback, (struct CALLBACK*)NULL);
5545 if (isdir || (errno == ENOTDIR))
5546 showfull(path,isdir);
5547 else {
5548 printf("** Could not access %s\n",path);
5549 printerror(stdout);
5550 errors++;
5551 err = TRUE;
5552 }
5553 return (err);
5554}
5555
5556#ifdef HAVE_SETXATTR
5557
5558static ssize_t ntfs_getxattr(const char *path, const char *name, void *value, size_t size)
5559{
5560#if defined(__APPLE__) || defined(__DARWIN__)
5561 return getxattr(path, name, value, size, 0, 0);
5562#else
5563 return getxattr(path, name, value, size);
5564#endif
5565}
5566
5567/*
5568 * Display all the parameters associated to a mounted file
5569 */
5570
5571BOOL showmounted(const char *fullname)
5572{
5573
5574 static char attr[MAXATTRSZ];
5575 struct stat st;
5576#if POSIXACLS
5577 struct POSIX_SECURITY *pxdesc;
5578#endif
5579 BOOL mapped;
5580 int attrsz;
5581 int mode;
5582 uid_t uid;
5583 gid_t gid;
5584 u32 attrib;
5585 int level;
5586 BOOL isdir;
5587 BOOL err;
5588
5589 err = FALSE;
5590 if (!stat(fullname,&st)) {
5591 isdir = S_ISDIR(st.st_mode);
5592 printf("%s ",(isdir ? "Directory" : "File"));
5593 printname(stdout,fullname);
5594 printf("\n");
5595
5596 attrsz = ntfs_getxattr(fullname,"system.ntfs_acl",attr,MAXATTRSZ);
5597 if (attrsz > 0) {
5598 if (opt_v) {
5599 hexdump(attr,attrsz,8);
5600 printf("Computed hash : 0x%08lx\n",
5601 (unsigned long)hash((le32*)attr,attrsz));
5602 }
5603 if (ntfs_getxattr(fullname,"system.ntfs_attrib",&attrib,4) != 4) {
5604 printf("** Could not get file attrib\n");
5605 errors++;
5606 } else
5607 printf("Windows attrib : 0x%x\n",(int)attrib);
5608 if (ntfs_valid_descr(attr,attrsz)) {
5609 mapped = !local_build_mapping(context.mapping,fullname);
5610#if POSIXACLS
5611 if (mapped) {
5612 pxdesc = linux_permissions_posix(attr,isdir);
5613 if (pxdesc)
5614 mode = pxdesc->mode;
5615 else
5616 mode = 0;
5617 } else {
5618 pxdesc = (struct POSIX_SECURITY*)NULL;
5619 mode = linux_permissions(attr,isdir);
5620 printf("No user mapping : "
5621 "cannot display the Posix ACL\n");
5622 }
5623#else
5624 mode = linux_permissions(attr,isdir);
5625#endif
5626 if (opt_v >= 2) {
5627 level = (opt_b ? 4 : 0);
5628 showheader(attr,level);
5629 showusid(attr,level);
5630 showgsid(attr,level);
5631 showdacl(attr,isdir,level);
5632 showsacl(attr,isdir,level);
5633 }
Steve Kondik79165c32015-11-09 19:43:00 -08005634 showownership(attr);
Steve Kondik2111ad72013-07-07 12:07:44 -07005635 if (mapped) {
5636 uid = linux_owner(attr);
5637 gid = linux_group(attr);
5638 printf("Interpreted Unix owner %d, group %d, mode 0%03o\n",
5639 (int)uid,(int)gid,mode);
5640 } else {
5641 printf("Interpreted Unix mode 0%03o (owner and group are unmapped)\n",
5642 mode);
5643 }
5644#if POSIXACLS
5645 if (pxdesc) {
5646 if ((pxdesc->defcnt
5647 || (pxdesc->tagsset
5648 & (POSIX_ACL_USER
5649 | POSIX_ACL_GROUP
5650 | POSIX_ACL_MASK))))
5651 showposix(pxdesc);
5652#if USESTUBS
5653 stdfree(pxdesc); /* allocated within library */
5654#else
5655 free(pxdesc);
5656#endif
5657 }
5658 if (mapped)
5659 ntfs_free_mapping(context.mapping);
5660#endif
5661 } else {
5662 printf("Descriptor fails sanity check\n");
5663 errors++;
5664 }
5665 } else {
5666 printf("** Could not get the NTFS ACL, check whether file is on NTFS\n");
5667 errors++;
5668 }
5669 } else {
5670 printf("%s not found\n",fullname);
5671 err = TRUE;
5672 }
5673 return (err);
5674}
5675
5676BOOL processmounted(const char *fullname)
5677{
5678
5679 static char attr[MAXATTRSZ];
5680 struct stat st;
5681 int attrsz;
5682 BOOL err;
5683
5684 err = FALSE;
5685 if (!opt_u)
5686 err = showmounted(fullname);
5687 else
5688 if (!stat(fullname,&st)) {
5689 attrsz = ntfs_getxattr(fullname,"system.ntfs_acl",attr,MAXATTRSZ);
5690 if (attrsz > 0) {
5691 if (opt_v) {
5692 hexdump(attr,attrsz,8);
5693 printf("Computed hash : 0x%08lx\n",
5694 (unsigned long)hash((le32*)attr,attrsz));
5695 }
5696 if (ntfs_valid_descr(attr,attrsz)) {
5697 err = proposal(fullname, attr);
5698 } else {
5699 printf("*** Descriptor fails sanity check\n");
5700 errors++;
5701 }
5702 } else {
5703 printf("** Could not get the NTFS ACL, check whether file is on NTFS\n");
5704 errors++;
5705 }
5706 } else {
5707 printf("%s not found\n",fullname);
5708 err = TRUE;
5709 }
5710 return (err);
5711}
5712
5713#else /* HAVE_SETXATTR */
5714
5715BOOL processmounted(const char *fullname __attribute__((unused)))
5716{
5717 fprintf(stderr,"Not possible on this configuration,\n");
5718 fprintf(stderr,"you have to use an unmounted partition\n");
5719 return (TRUE);
5720}
5721
5722#endif /* HAVE_SETXATTR */
5723
5724#if POSIXACLS
5725
5726BOOL recurseset_posix(const char *path, const struct POSIX_SECURITY *pxdesc)
5727{
5728 struct CALLBACK dircontext;
5729 struct LINK *current;
5730 BOOL isdir;
5731 BOOL err;
5732
5733 err = FALSE;
5734 dircontext.head = (struct LINK*)NULL;
5735 dircontext.dir = path;
5736 isdir = ntfs_read_directory(ntfs_context, path,
5737 callback, &dircontext);
5738 if (isdir) {
5739 err = !setfull_posix(path,pxdesc,TRUE);
5740 if (err) {
5741 printf("** Failed to update %s\n",path);
5742 printerror(stdout);
5743 errors++;
5744 } else {
5745 if (opt_b)
5746 printf("#\n#\n");
5747 else
5748 printf("\n\n");
5749 while (dircontext.head) {
5750 current = dircontext.head;
5751 recurseset_posix(current->name,pxdesc);
5752 dircontext.head = dircontext.head->next;
5753 free(current);
5754 }
5755 }
5756 } else
5757 if (errno == ENOTDIR) {
5758 err = !setfull_posix(path,pxdesc,FALSE);
5759 if (err) {
5760 printf("** Failed to update %s\n",path);
5761 printerror(stdout);
5762 errors++;
5763 }
5764 } else {
5765 printf("** Could not access %s\n",path);
5766 printerror(stdout);
5767 errors++;
5768 err = TRUE;
5769 }
5770 return (!err);
5771}
5772
5773#else
5774
5775BOOL recurseset(const char *path, int mode)
5776{
5777 struct CALLBACK dircontext;
5778 struct LINK *current;
5779 BOOL isdir;
5780 BOOL err;
5781
5782 err = FALSE;
5783 dircontext.head = (struct LINK*)NULL;
5784 dircontext.dir = path;
5785 isdir = ntfs_read_directory(ntfs_context, path,
5786 callback, &dircontext);
5787 if (isdir) {
5788 setfull(path,mode,TRUE);
5789 if (opt_b)
5790 printf("#\n#\n");
5791 else
5792 printf("\n\n");
5793 while (dircontext.head) {
5794 current = dircontext.head;
5795 recurseset(current->name,mode);
5796 dircontext.head = dircontext.head->next;
5797 free(current);
5798 }
5799 } else
5800 if (errno == ENOTDIR)
5801 setfull(path,mode,FALSE);
5802 else {
5803 printf("** Could not access %s\n",path);
5804 printerror(stdout);
5805 errors++;
5806 err = TRUE;
5807 }
5808 return (!err);
5809}
5810
5811#endif
5812
5813#if POSIXACLS
5814
5815BOOL singleset_posix(const char *path, const struct POSIX_SECURITY *pxdesc)
5816{
5817 BOOL isdir;
5818 BOOL err;
5819
5820 err = FALSE;
5821 isdir = ntfs_read_directory(ntfs_context, path,
5822 callback, (struct CALLBACK*)NULL);
5823 if (isdir || (errno == ENOTDIR)) {
5824 err = !setfull_posix(path,pxdesc,isdir);
5825 if (err) {
5826 printf("** Failed to update %s\n",path);
5827 printerror(stdout);
5828 errors++;
5829 }
5830 } else {
5831 printf("** Could not access %s\n",path);
5832 printerror(stdout);
5833 errors++;
5834 err = TRUE;
5835 }
5836 return (!err);
5837}
5838
5839#endif
5840
5841BOOL singleset(const char *path, int mode)
5842{
5843 BOOL isdir;
5844 BOOL err;
5845
5846 err = FALSE;
5847 isdir = ntfs_read_directory(ntfs_context, path,
5848 callback, (struct CALLBACK*)NULL);
5849 if (isdir || (errno == ENOTDIR))
5850 setfull(path,mode,isdir);
5851 else {
5852 printf("** Could not access %s\n",path);
5853 printerror(stdout);
5854 errors++;
5855 err = TRUE;
5856 }
5857 return (!err);
5858}
5859
5860int callback(struct CALLBACK *dircontext, char *ntfsname,
5861 int length, int type,
5862 long long pos __attribute__((unused)), u64 mft_ref __attribute__((unused)),
5863 unsigned int dt_type __attribute__((unused)))
5864{
5865 struct LINK *linkage;
5866 char *name;
5867 int newlth;
5868 int size;
5869
5870 size = utf8size(ntfsname,length);
5871 if (dircontext
5872 && (type != 2) /* 2 : dos name (8+3) */
5873 && (size > 0) /* chars convertible to utf8 */
5874 && ((length > 2)
5875 || (ntfsname[0] != '.')
5876 || (ntfsname[1] != '\0')
5877 || ((ntfsname[2] || ntfsname[3])
5878 && ((ntfsname[2] != '.') || (ntfsname[3] != '\0'))))) {
5879 linkage = (struct LINK*)malloc(sizeof(struct LINK)
5880 + strlen(dircontext->dir)
5881 + size + 2);
5882 if (linkage) {
5883 /* may find ".fuse_hidden*" files */
5884 /* recommendation is not to hide them, so that */
5885 /* the user has a clue to delete them */
5886 strcpy(linkage->name,dircontext->dir);
5887 if (linkage->name[strlen(linkage->name) - 1] != '/')
5888 strcat(linkage->name,"/");
5889 name = &linkage->name[strlen(linkage->name)];
5890 newlth = makeutf8(name,ntfsname,length);
5891 name[newlth] = 0;
5892 linkage->next = dircontext->head;
5893 dircontext->head = linkage;
5894 }
5895 }
5896 return (0);
5897}
5898
5899#endif
5900
5901#ifdef WIN32
5902
5903/*
5904 * Backup security descriptors in a directory tree (Windows mode)
5905 */
5906
5907BOOL backup(const char *root)
5908{
5909 BOOL err;
5910 time_t now;
5911 const char *txtime;
5912
5913 now = time((time_t*)NULL);
5914 txtime = ctime(&now);
5915 printf("#\n# Recursive ACL collection on %s#\n",txtime);
5916 err = recurseshow(root);
5917 return (err);
5918}
5919
5920#else
5921
5922/*
5923 * Backup security descriptors in a directory tree (Linux mode)
5924 */
5925
5926BOOL backup(const char *volume, const char *root)
5927{
5928 BOOL err;
5929 int count;
5930 int i,j;
5931 time_t now;
5932 const char *txtime;
5933
5934 now = time((time_t*)NULL);
5935 txtime = ctime(&now);
5936 if (!getuid() && open_security_api()) {
5937 if (open_volume(volume,NTFS_MNT_RDONLY)) {
5938 printf("#\n# Recursive ACL collection on %s#\n",txtime);
5939 err = recurseshow(root);
5940 count = 0;
5941 for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++)
5942 if (securdata[i])
5943 for (j=0; j<(1 << SECBLKSZ); j++)
5944 if (securdata[i][j].filecount) {
5945 count++;
5946 }
5947 printf("# %d security keys\n",count);
5948 close_volume(volume);
5949 } else {
5950 fprintf(stderr,"Could not open volume %s\n",volume);
5951 printerror(stdout);
5952 err = TRUE;
5953 }
5954 close_security_api();
5955 } else {
5956 if (getuid())
5957 fprintf(stderr,"This is only possible as root\n");
5958 else
5959 fprintf(stderr,"Could not open security API\n");
5960 err = TRUE;
5961 }
5962 return (err);
5963}
5964
5965#endif
5966
5967#ifdef WIN32
5968
5969/*
5970 * List security descriptors in a directory tree (Windows mode)
5971 */
5972
5973BOOL listfiles(const char *root)
5974{
5975 BOOL err;
5976
5977 if (opt_r) {
5978 printf("\nRecursive file check\n");
5979 err = recurseshow(root);
5980 } else
5981 err = singleshow(root);
5982 return (err);
5983}
5984
5985#else
5986
5987/*
5988 * List security descriptors in a directory tree (Linux mode)
5989 */
5990
5991BOOL listfiles(const char *volume, const char *root)
5992{
5993 BOOL err;
5994 int i,j;
5995 int count;
5996
5997 if (!getuid() && open_security_api()) {
5998 if (open_volume(volume,NTFS_MNT_RDONLY)) {
5999 if (opt_r) {
6000 printf("\nRecursive file check\n");
6001 err = recurseshow(root);
6002 printf("Summary\n");
6003 count = 0;
6004 for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++)
6005 if (securdata[i])
6006 for (j=0; j<(1 << SECBLKSZ); j++)
6007 if (securdata[i][j].filecount) {
6008 printf("Key 0x%x : %d files, mode 0%03o\n",
6009 i*(1 << SECBLKSZ)+j,securdata[i][j].filecount,
6010 securdata[i][j].mode);
6011 count++;
6012 }
6013 printf("%d security keys\n",count);
6014 } else
6015 err = singleshow(root);
6016 close_volume(volume);
6017 } else {
6018 fprintf(stderr,"Could not open volume %s\n",volume);
6019 printerror(stdout);
6020 err = TRUE;
6021 }
6022 close_security_api();
6023 } else {
6024 if (getuid())
6025 fprintf(stderr,"This is only possible as root\n");
6026 else
6027 fprintf(stderr,"Could not open security API\n");
6028 err = TRUE;
6029 }
6030 return (err);
6031}
6032
6033BOOL mapproposal(const char *volume, const char *name)
6034{
6035 BOOL err;
6036 u32 attrsz;
6037 int securindex;
6038 char attr[256]; /* header (20) and a couple of SIDs (max 40 each) */
6039
6040 err = FALSE;
6041 if (!getuid() && open_security_api()) {
6042 if (open_volume(volume,NTFS_MNT_RDONLY)) {
6043
6044 attrsz = 0;
6045 securindex = ntfs_get_file_security(ntfs_context,name,
6046 OWNER_SECURITY_INFORMATION
6047 | GROUP_SECURITY_INFORMATION,
6048 (char*)attr,MAXATTRSZ,&attrsz);
6049 if (securindex)
6050 err = proposal(name,attr);
6051 else {
6052 fprintf(stderr,"*** Could not get the ACL of %s\n",
6053 name);
6054 printerror(stdout);
6055 errors++;
6056 }
6057 close_volume(volume);
6058 } else {
6059 fprintf(stderr,"Could not open volume %s\n",volume);
6060 printerror(stdout);
6061 err = TRUE;
6062 }
6063 close_security_api();
6064 } else {
6065 if (getuid())
6066 fprintf(stderr,"This is only possible as root\n");
6067 else
6068 fprintf(stderr,"Could not open security API\n");
6069 err = TRUE;
6070 }
6071 return (err);
6072}
6073
6074#endif
6075
6076#ifndef WIN32
6077
6078/*
6079 * Check whether a SDS entry is valid
6080 */
6081
6082BOOL valid_sds(const char *attr, unsigned int offset,
6083 unsigned int entrysz, unsigned int size, u32 prevkey,
6084 BOOL second)
6085{
6086 BOOL unsane;
6087 u32 comphash;
6088 u32 key;
6089
6090 unsane = FALSE;
6091 if (!get4l(attr,0) && !get4l(attr,4)) {
6092 printf("Entry at 0x%lx was deleted\n",(long)offset);
6093 } else {
6094 if ((ntfs_attr_size(&attr[20]) + 20) > entrysz) {
6095 printf("** Entry is truncated (expected size %ld)\n",
6096 (long)ntfs_attr_size(&attr[20] + 20));
6097 unsane = TRUE;
6098 errors++;
6099 }
6100 if ((ntfs_attr_size(&attr[20]) + 20) < entrysz) {
6101 printf("** Extra data appended to entry (expected size %ld)\n",
6102 (long)ntfs_attr_size(&attr[20]) + 20);
6103 warnings++;
6104 }
6105 if (!unsane && !ntfs_valid_descr((const char*)&attr[20],size)) {
6106 printf("** General sanity check has failed\n");
6107 unsane = TRUE;
6108 errors++;
6109 }
6110 if (!unsane) {
6111 comphash = hash((const le32*)&attr[20],entrysz-20);
6112 if ((u32)get4l(attr,0) == comphash) {
6113 if (opt_v >= 2)
6114 printf("Hash 0x%08lx (correct)\n",
6115 (unsigned long)comphash);
6116 } else {
6117 printf("** hash 0x%08lx (computed : 0x%08lx)\n",
6118 (unsigned long)get4l(attr,0),
6119 (unsigned long)comphash);
6120 unsane = TRUE;
6121 errors++;
6122 }
6123 }
6124 if (!unsane) {
6125 if ((second ? get8l(attr,8) + 0x40000 : get8l(attr,8)) == offset) {
6126 if (opt_v >= 2)
6127 printf("Offset 0x%lx (correct)\n",(long)offset);
6128 } else {
6129 printf("** offset 0x%llx (expected : 0x%llx)\n",
6130 (long long)get8l(attr,8),
6131 (long long)(second ? get8l(attr,8) - 0x40000 : get8l(attr,8)));
6132// unsane = TRUE;
6133 errors++;
6134 }
6135 }
6136 if (!unsane) {
6137 key = get4l(attr,4);
6138 if (opt_v >= 2)
6139 printf("Key 0x%x\n",(int)key);
6140 if (key) {
6141 if (key <= prevkey) {
6142 printf("** Unordered key 0x%lx after 0x%lx\n",
6143 (long)key,(long)prevkey);
6144 unsane = TRUE;
6145 errors++;
6146 }
6147 }
6148 }
6149 }
6150 return (!unsane);
6151}
6152
6153/*
6154 * Check whether a SDS entry is consistent with other known data
6155 * and store current data for subsequent checks
6156 */
6157
6158int consist_sds(const char *attr, unsigned int offset,
6159 unsigned int entrysz, BOOL second)
6160{
6161 int errcnt;
6162 u32 key;
6163 u32 comphash;
6164 struct SECURITY_DATA *psecurdata;
6165
6166 errcnt = 0;
6167 key = get4l(attr,4);
6168 if ((key > 0) && (key < MAXSECURID)) {
6169 printf("Valid entry at 0x%lx for key 0x%lx\n",
6170 (long)offset,(long)key);
6171 if (!securdata[key >> SECBLKSZ])
6172 newblock(key);
6173 if (securdata[key >> SECBLKSZ]) {
6174 psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)];
6175 comphash = hash((const le32*)&attr[20],entrysz-20);
6176 if (psecurdata->flags & INSDS1) {
6177 if (psecurdata->hash != comphash) {
6178 printf("** Different hash values : $SDS-1 0x%08lx $SDS-2 0x%08lx\n",
6179 (unsigned long)psecurdata->hash,
6180 (unsigned long)comphash);
6181 errcnt++;
6182 errors++;
6183 }
6184 if (psecurdata->offset != get8l(attr,8)) {
6185 printf("** Different offsets : $SDS-1 0x%llx $SDS-2 0x%llx\n",
6186 (long long)psecurdata->offset,(long long)get8l(attr,8));
6187 errcnt++;
6188 errors++;
6189 }
6190 if (psecurdata->length != get4l(attr,16)) {
6191 printf("** Different lengths : $SDS-1 0x%lx $SDS-2 0x%lx\n",
6192 (long)psecurdata->length,(long)get4l(attr,16));
6193 errcnt++;
6194 errors++;
6195 }
6196 } else {
6197 if (second) {
6198 printf("** Entry was not present in $SDS-1\n");
6199 errcnt++;
6200 errors++;
6201 }
6202 psecurdata->hash = comphash;
6203 psecurdata->offset = get8l(attr,8);
6204 psecurdata->length = get4l(attr,16);
6205 }
6206 psecurdata->flags |= (second ? INSDS2 : INSDS1);
6207 }
6208 } else
6209 if (key || get4l(attr,0)) {
6210 printf("** Security_id 0x%x out of bounds\n",key);
6211 warnings++;
6212 }
6213 return (errcnt);
6214}
6215
6216
6217/*
6218 * Auditing of $SDS (Linux only)
6219 */
6220
6221int audit_sds(BOOL second)
6222{
6223 static char attr[MAXATTRSZ + 20];
6224 BOOL isdir;
6225 BOOL done;
6226 BOOL unsane;
6227 u32 prevkey;
6228 int errcnt;
6229 int size;
6230 unsigned int entrysz;
6231 unsigned int entryalsz;
6232 unsigned int offset;
6233 int count;
6234 int deleted;
6235 int mode;
6236
6237 if (second)
6238 printf("\nAuditing $SDS-2\n");
6239 else
6240 printf("\nAuditing $SDS-1\n");
6241 errcnt = 0;
6242 offset = (second ? 0x40000 : 0);
6243 count = 0;
6244 deleted = 0;
6245 done = FALSE;
6246 prevkey = 0;
6247
6248 /* get size of first record */
6249
6250 size = ntfs_read_sds(ntfs_context,(char*)attr,20,offset);
6251 if (size != 20) {
6252 if ((size < 0) && (errno == ENOTSUP))
6253 printf("** There is no $SDS-%d in this volume\n",
6254 (second ? 2 : 1));
6255 else {
6256 printf("** Could not open $SDS-%d, size %d\n",
6257 (second ? 2 : 1),size);
6258 errors++;
6259 errcnt++;
6260 }
6261 } else
6262 do {
6263 entrysz = get4l(attr,16);
6264 entryalsz = ((entrysz - 1) | 15) + 1;
6265 if (entryalsz <= (MAXATTRSZ + 20)) {
6266 /* read next header in anticipation, to get its size */
6267 size = ntfs_read_sds(ntfs_context,
6268 (char*)&attr[20],entryalsz,offset + 20);
6269 if (opt_v)
6270 printf("\nAt offset 0x%lx got %lu bytes\n",(long)offset,(long)size);
6271 } else {
6272 printf("** Security attribute is too long (%ld bytes) - stopping\n",
6273 (long)entryalsz);
6274 errcnt++;
6275 }
6276 if ((entryalsz > (MAXATTRSZ + 20)) || (size < (int)(entrysz - 20)))
6277 done = TRUE;
6278 else {
6279 if (opt_v) {
6280 printf("Entry size %d bytes\n",entrysz);
6281 hexdump(&attr[20],size,8);
6282 }
6283
6284 unsane = !valid_sds(attr,offset,entrysz,
6285 size,prevkey,second);
6286 if (!unsane) {
6287 if (!get4l(attr,0) && !get4l(attr,4))
6288 deleted++;
6289 else
6290 count++;
6291 errcnt += consist_sds(attr,offset,
6292 entrysz, second);
6293 if (opt_v >= 2) {
6294 isdir = guess_dir(&attr[20]);
6295 printf("Assuming %s descriptor\n",(isdir ? "directory" : "file"));
6296 showheader(&attr[20],0);
6297 showusid(&attr[20],0);
6298 showgsid(&attr[20],0);
6299 showdacl(&attr[20],isdir,0);
6300 showsacl(&attr[20],isdir,0);
Steve Kondik79165c32015-11-09 19:43:00 -08006301 showownership(&attr[20]);
Steve Kondik2111ad72013-07-07 12:07:44 -07006302 mode = linux_permissions(
6303 &attr[20],isdir);
6304 printf("Interpreted Unix mode 0%03o\n",mode);
6305 }
6306 prevkey = get4l(attr,4);
6307 }
6308 if (!unsane) {
6309 memcpy(attr,&attr[entryalsz],20);
6310 offset += entryalsz;
6311 if (!get4l(attr,16)
6312 || ((((offset - 1) | 0x3ffff) - offset + 1) < 20)) {
6313 if (second)
6314 offset = ((offset - 1) | 0x7ffff) + 0x40001;
6315 else
6316 offset = ((offset - 1) | 0x7ffff) + 1;
6317 if (opt_v)
6318 printf("Trying next SDS-%d block at offset 0x%lx\n",
6319 (second ? 2 : 1), (long)offset);
6320 size = ntfs_read_sds(ntfs_context,
6321 (char*)attr,20,offset);
6322 if (size != 20) {
6323 if (opt_v)
6324 printf("Assuming end of $SDS, got %d bytes\n",size);
6325 done = TRUE;
6326 }
6327 }
6328 } else {
6329 printf("** Sanity check failed - stopping there\n");
6330 errcnt++;
6331 errors++;
6332 done = TRUE;
6333 }
6334 }
6335 } while (!done);
6336 if (count || deleted || errcnt) {
6337 printf("%d valid and %d deleted entries in $SDS-%d\n",
6338 count,deleted,(second ? 2 : 1));
6339 printf("%d errors in $SDS-%c\n",errcnt,(second ? '2' : '1'));
6340 }
6341 return (errcnt);
6342}
6343
6344/*
6345 * Check whether a SII entry is sane
6346 */
6347
6348BOOL valid_sii(const char *entry, u32 prevkey)
6349{
6350 BOOL valid;
6351 u32 key;
6352
6353 valid = TRUE;
6354 key = get4l(entry,16);
6355 if (key <= prevkey) {
6356 printf("** Unordered key 0x%lx after 0x%lx\n",
6357 (long)key,(long)prevkey);
6358 valid = FALSE;
6359 errors++;
6360 }
6361 prevkey = key;
6362 if (get2l(entry,0) != 20) {
6363 printf("** offset %d (instead of 20)\n",(int)get2l(entry,0));
6364 valid = FALSE;
6365 errors++;
6366 }
6367 if (get2l(entry,2) != 20) {
6368 printf("** size %d (instead of 20)\n",(int)get2l(entry,2));
6369 valid = FALSE;
6370 errors++;
6371 }
6372 if (get4l(entry,4) != 0) {
6373 printf("** fill1 %d (instead of 0)\n",(int)get4l(entry,4));
6374 valid = FALSE;
6375 errors++;
6376 }
6377 if (get2l(entry,12) & 1) {
6378 if (get2l(entry,8) != 48) {
6379 printf("** index size %d (instead of 48)\n",(int)get2l(entry,8));
6380 valid = FALSE;
6381 errors++;
6382 }
6383 } else
6384 if (get2l(entry,8) != 40) {
6385 printf("** index size %d (instead of 40)\n",(int)get2l(entry,8));
6386 valid = FALSE;
6387 errors++;
6388 }
6389 if (get2l(entry,10) != 4) {
6390 printf("** index key size %d (instead of 4)\n",(int)get2l(entry,10));
6391 valid = FALSE;
6392 errors++;
6393 }
6394 if ((get2l(entry,12) & ~3) != 0) {
6395 printf("** flags 0x%x (instead of < 4)\n",(int)get2l(entry,12));
6396 valid = FALSE;
6397 errors++;
6398 }
6399 if (get2l(entry,14) != 0) {
6400 printf("** fill2 %d (instead of 0)\n",(int)get2l(entry,14));
6401 valid = FALSE;
6402 errors++;
6403 }
6404 if (get4l(entry,24) != key) {
6405 printf("** key 0x%x (instead of 0x%x)\n",
6406 (int)get4l(entry,24),(int)key);
6407 valid = FALSE;
6408 errors++;
6409 }
6410 return (valid);
6411}
6412
6413/*
6414 * Check whether a SII entry is consistent with other known data
6415 */
6416
6417int consist_sii(const char *entry)
6418{
6419 int errcnt;
6420 u32 key;
6421 struct SECURITY_DATA *psecurdata;
6422
6423 errcnt = 0;
6424 key = get4l(entry,16);
6425 if ((key > 0) && (key < MAXSECURID)) {
6426 printf("Valid entry for key 0x%lx\n",(long)key);
6427 if (!securdata[key >> SECBLKSZ])
6428 newblock(key);
6429 if (securdata[key >> SECBLKSZ]) {
6430 psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)];
6431 psecurdata->flags |= INSII;
6432 if (psecurdata->flags & (INSDS1 | INSDS2)) {
6433 if ((u32)get4l(entry,20) != psecurdata->hash) {
6434 printf("** hash 0x%x (instead of 0x%x)\n",
6435 (unsigned int)get4l(entry,20),
6436 (unsigned int)psecurdata->hash);
6437 errors++;
6438 }
6439 if (get8l(entry,28) != psecurdata->offset) {
6440 printf("** offset 0x%llx (instead of 0x%llx)\n",
6441 (long long)get8l(entry,28),
6442 (long long)psecurdata->offset);
6443 errors++;
6444 }
6445 if (get4l(entry,36) != psecurdata->length) {
6446 printf("** length 0x%lx (instead of %ld)\n",
6447 (long)get4l(entry,36),
6448 (long)psecurdata->length);
6449 errors++;
6450 }
6451 } else {
6452 printf("** Entry was not present in $SDS\n");
6453 errors++;
6454 psecurdata->hash = get4l(entry,20);
6455 psecurdata->offset = get8l(entry,28);
6456 psecurdata->length = get4l(entry,36);
6457 if (opt_v) {
6458 printf(" hash 0x%x\n",(unsigned int)psecurdata->hash);
6459 printf(" offset 0x%llx\n",(long long)psecurdata->offset);
6460 printf(" length %ld\n",(long)psecurdata->length);
6461 }
6462 errcnt++;
6463 }
6464 }
6465 } else {
6466 printf("** Security_id 0x%x out of bounds\n",key);
6467 warnings++;
6468 }
6469 return (errcnt);
6470}
6471
6472
6473/*
6474 * Auditing of $SII (Linux only)
6475 */
6476
6477int audit_sii()
6478{
6479 char *entry;
6480 int errcnt;
6481 u32 prevkey;
6482 BOOL valid;
6483 BOOL done;
6484 int count;
6485
6486 printf("\nAuditing $SII\n");
6487 errcnt = 0;
6488 count = 0;
6489 entry = (char*)NULL;
6490 prevkey = 0;
6491 done = FALSE;
6492 do {
6493 entry = (char*)ntfs_read_sii(ntfs_context,(void*)entry);
6494 if (entry) {
6495 valid = valid_sii(entry,prevkey);
6496 if (valid) {
6497 count++;
6498 errcnt += consist_sii(entry);
6499 prevkey = get4l(entry,16);
6500 } else
6501 errcnt++;
6502 } else
6503 if ((errno == ENOTSUP) && !prevkey)
6504 printf("** There is no $SII in this volume\n");
6505 } while (entry && !done);
6506 if (count || errcnt) {
6507 printf("%d valid entries in $SII\n",count);
6508 printf("%d errors in $SII\n",errcnt);
6509 }
6510 return (errcnt);
6511}
6512
6513/*
6514 * Check whether a SII entry is sane
6515 */
6516
6517BOOL valid_sdh(const char *entry, u32 prevkey, u32 prevhash)
6518{
6519 BOOL valid;
6520 u32 key;
6521 u32 currhash;
6522
6523 valid = TRUE;
6524 currhash = get4l(entry,16);
6525 key = get4l(entry,20);
6526 if ((currhash < prevhash)
6527 || ((currhash == prevhash) && (key <= prevkey))) {
6528 printf("** Unordered hash and key 0x%x 0x%x after 0x%x 0x%x\n",
6529 (unsigned int)currhash,(unsigned int)key,
6530 (unsigned int)prevhash,(unsigned int)prevkey);
6531 valid = FALSE;
6532 errors++;
6533 }
6534 if ((opt_v >= 2) && (currhash == prevhash))
6535 printf("Hash collision (not an error)\n");
6536
6537 if (get2l(entry,0) != 24) {
6538 printf("** offset %d (instead of 24)\n",(int)get2l(entry,0));
6539 valid = FALSE;
6540 errors++;
6541 }
6542 if (get2l(entry,2) != 20) {
6543 printf("** size %d (instead of 20)\n",(int)get2l(entry,2));
6544 valid = FALSE;
6545 errors++;
6546 }
6547 if (get4l(entry,4) != 0) {
6548 printf("** fill1 %d (instead of 0)\n",(int)get4l(entry,4));
6549 valid = FALSE;
6550 errors++;
6551 }
6552 if (get2l(entry,12) & 1) {
6553 if (get2l(entry,8) != 56) {
6554 printf("** index size %d (instead of 56)\n",(int)get2l(entry,8));
6555 valid = FALSE;
6556 errors++;
6557 }
6558 } else
6559 if (get2l(entry,8) != 48) {
6560 printf("** index size %d (instead of 48)\n",(int)get2l(entry,8));
6561 valid = FALSE;
6562 errors++;
6563 }
6564 if (get2l(entry,10) != 8) {
6565 printf("** index key size %d (instead of 8)\n",(int)get2l(entry,10));
6566 valid = FALSE;
6567 errors++;
6568 }
6569 if ((get2l(entry,12) & ~3) != 0) {
6570 printf("** flags 0x%x (instead of < 4)\n",(int)get2l(entry,12));
6571 valid = FALSE;
6572 errors++;
6573 }
6574 if (get2l(entry,14) != 0) {
6575 printf("** fill2 %d (instead of 0)\n",(int)get2l(entry,14));
6576 valid = FALSE;
6577 errors++;
6578 }
6579 if ((u32)get4l(entry,24) != currhash) {
6580 printf("** hash 0x%x (instead of 0x%x)\n",
6581 (unsigned int)get4l(entry,24),(unsigned int)currhash);
6582 valid = FALSE;
6583 errors++;
6584 }
6585 if (get4l(entry,28) != key) {
6586 printf("** key 0x%x (instead of 0x%x)\n",
6587 (int)get4l(entry,28),(int)key);
6588 valid = FALSE;
6589 errors++;
6590 }
6591 if (get4l(entry,44)
6592 && (get4l(entry,44) != 0x490049)) {
6593 printf("** fill3 0x%lx (instead of 0 or 0x490049)\n",
6594 (long)get4l(entry,44));
6595 valid = FALSE;
6596 errors++;
6597 }
6598 return (valid);
6599}
6600
6601/*
6602 * Check whether a SDH entry is consistent with other known data
6603 */
6604
6605int consist_sdh(const char *entry)
6606{
6607 int errcnt;
6608 u32 key;
6609 struct SECURITY_DATA *psecurdata;
6610
6611 errcnt = 0;
6612 key = get4l(entry,20);
6613 if ((key > 0) && (key < MAXSECURID)) {
6614 printf("Valid entry for key 0x%lx\n",(long)key);
6615 if (!securdata[key >> SECBLKSZ])
6616 newblock(key);
6617 if (securdata[key >> SECBLKSZ]) {
6618 psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)];
6619 psecurdata->flags |= INSDH;
6620 if (psecurdata->flags & (INSDS1 | INSDS2 | INSII)) {
6621 if ((u32)get4l(entry,24) != psecurdata->hash) {
6622 printf("** hash 0x%x (instead of 0x%x)\n",
6623 (unsigned int)get4l(entry,24),
6624 (unsigned int)psecurdata->hash);
6625 errors++;
6626 }
6627 if (get8l(entry,32) != psecurdata->offset) {
6628 printf("** offset 0x%llx (instead of 0x%llx)\n",
6629 (long long)get8l(entry,32),
6630 (long long)psecurdata->offset);
6631 errors++;
6632 }
6633 if (get4l(entry,40) != psecurdata->length) {
6634 printf("** length %ld (instead of %ld)\n",
6635 (long)get4l(entry,40),
6636 (long)psecurdata->length);
6637 errors++;
6638 }
6639 } else {
6640 printf("** Entry was not present in $SDS nor in $SII\n");
6641 errors++;
6642 psecurdata->hash = get4l(entry,24);
6643 psecurdata->offset = get8l(entry,32);
6644 psecurdata->length = get4l(entry,40);
6645 if (opt_v) {
6646 printf(" offset 0x%llx\n",(long long)psecurdata->offset);
6647 printf(" length %ld\n",(long)psecurdata->length);
6648 }
6649 errcnt++;
6650 }
6651 }
6652 } else {
6653 printf("** Security_id 0x%x out of bounds\n",key);
6654 warnings++;
6655 }
6656 return (errcnt);
6657}
6658
6659/*
6660 * Auditing of $SDH (Linux only)
6661 */
6662
6663int audit_sdh()
6664{
6665 char *entry;
6666 int errcnt;
6667 int count;
6668 u32 prevkey;
6669 u32 prevhash;
6670 BOOL valid;
6671 BOOL done;
6672
6673 printf("\nAuditing $SDH\n");
6674 count = 0;
6675 errcnt = 0;
6676 prevkey = 0;
6677 prevhash = 0;
6678 entry = (char*)NULL;
6679 done = FALSE;
6680 do {
6681 entry = (char*)ntfs_read_sdh(ntfs_context,(void*)entry);
6682 if (entry) {
6683 valid = valid_sdh(entry,prevkey,prevhash);
6684 if (valid) {
6685 count++;
6686 errcnt += consist_sdh(entry);
6687 prevhash = get4l(entry,16);
6688 prevkey = get4l(entry,20);
6689 } else
6690 errcnt++;
6691 } else
6692 if ((errno == ENOTSUP) && !prevkey)
6693 printf("** There is no $SDH in this volume\n");
6694 } while (entry && !done);
6695 if (count || errcnt) {
6696 printf("%d valid entries in $SDH\n",count);
6697 printf("%d errors in $SDH\n",errcnt);
6698 }
6699 return (errcnt);
6700}
6701
6702/*
6703 * Audit summary
6704 */
6705
6706void audit_summary()
6707{
6708 int count;
6709 int flags;
6710 int cnt;
6711 int found;
6712 int i,j;
6713
6714 count = 0;
6715 found = 0;
6716 if (opt_r) printf("Summary of security key use :\n");
6717 for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++)
6718 if (securdata[i])
6719 for (j=0; j<(1 << SECBLKSZ); j++) {
6720 flags = securdata[i][j].flags & (INSDS1 + INSDS2 + INSII + INSDH);
6721 if (flags) found++;
6722 if (flags
6723 && (flags != (INSDS1 + INSDS2 + INSII + INSDH)))
6724 {
6725 if (!count && !opt_r)
6726 printf("\n** Keys not present in all files :\n");
6727 cnt = securdata[i][j].filecount;
6728 if (opt_r)
6729 printf("Key 0x%x used by %d %s, not in",
6730 i*(1 << SECBLKSZ)+j,cnt,
6731 (cnt > 1 ? "files" : "file"));
6732 else
6733 printf("Key 0x%x not in", i*(1 << SECBLKSZ)+j);
6734 if (!(flags & INSDS1))
6735 printf(" SDS-1");
6736 if (!(flags & INSDS2))
6737 printf(" SDS-2");
6738 if (!(flags & INSII))
6739 printf(" SII");
6740 if (!(flags & INSDH))
6741 printf(" SDH");
6742 printf("\n");
6743 count++;
6744 } else {
6745 cnt = securdata[i][j].filecount;
6746 if (opt_r && cnt)
6747 printf("Key 0x%x used by %d %s\n",
6748 i*(1 << SECBLKSZ)+j,cnt,
6749 (cnt > 1 ? "files" : "file"));
6750 }
6751 }
6752 if (found) {
6753 if (count)
6754 printf("%d keys not present in all lists\n",count);
6755 else
6756 printf("All keys are present in all lists\n");
6757 }
6758}
6759
6760/*
6761 * Auditing (Linux only)
6762 */
6763
6764BOOL audit(const char *volume)
6765{
6766 BOOL err;
6767
6768 err = FALSE;
6769 if (!getuid() && open_security_api()) {
6770 if (open_volume(volume,NTFS_MNT_RDONLY)) {
6771 if (audit_sds(FALSE)) err = TRUE;
6772 if (audit_sds(TRUE)) err = TRUE;
6773 if (audit_sii()) err = TRUE;
6774 if (audit_sdh()) err = TRUE;
6775 if (opt_r) recurseshow("/");
6776
6777 audit_summary();
6778 close_volume(volume);
6779 }
6780 else {
6781 fprintf(stderr,"Could not open volume %s\n",volume);
6782 printerror(stdout);
6783 err = TRUE;
6784 }
6785 close_security_api();
6786 }
6787 else {
6788 if (getuid())
6789 fprintf(stderr,"This is only possible as root\n");
6790 else fprintf(stderr,"Could not open security API\n");
6791 err = TRUE;
6792 }
6793 return (err);
6794}
6795
6796#endif
6797
6798#if POSIXACLS
6799
6800/*
6801 * Encode a Posix ACL string
6802 * [d:]{ugmo}:uid[:perms],...
6803 */
6804
6805struct POSIX_SECURITY *encode_posix_acl(const char *str)
6806{
6807 int acccnt;
6808 int defcnt;
6809 int i,k,l;
6810 int c;
6811 s32 id;
6812 u16 perms;
6813 u16 apermsset;
6814 u16 dpermsset;
6815 u16 tag;
6816 u16 tagsset;
6817 mode_t mode;
6818 BOOL defacl;
6819 BOOL dmask;
6820 BOOL amask;
6821 const char *p;
6822 struct POSIX_ACL *acl;
6823 struct POSIX_SECURITY *pxdesc;
6824 enum { PXBEGIN, PXTAG, PXTAG1, PXID, PXID1, PXID2,
6825 PXPERM, PXPERM1, PXPERM2, PXOCT, PXNEXT, PXEND, PXERR
6826 } state;
6827
6828 /* raw evaluation of ACE count */
6829 p = str;
6830 amask = FALSE;
6831 dmask = FALSE;
6832 if (*p == 'd') {
6833 acccnt = 0;
6834 defcnt = 1;
6835 } else {
6836 if ((*p >= '0') && (*p <= '7'))
6837 acccnt = 0;
6838 else
6839 acccnt = 1;
6840 defcnt = 0;
6841 }
6842 while (*p)
6843 if (*p++ == ',') {
6844 if (*p == 'd') {
6845 defcnt++;
6846 if (p[1] && (p[2] == 'm'))
6847 dmask = TRUE;
6848 } else {
6849 acccnt++;
6850 if (*p == 'm')
6851 amask = TRUE;
6852 }
6853 }
6854 /* account for an implicit mask if none defined */
6855 if (acccnt && !amask)
6856 acccnt++;
6857 if (defcnt && !dmask)
6858 defcnt++;
6859 pxdesc = (struct POSIX_SECURITY*)malloc(sizeof(struct POSIX_SECURITY)
6860 + (acccnt + defcnt)*sizeof(struct POSIX_ACE));
6861 if (pxdesc) {
6862 pxdesc->acccnt = acccnt;
6863 pxdesc->firstdef = acccnt;
6864 pxdesc->defcnt = defcnt;
6865 acl = &pxdesc->acl;
6866 p = str;
6867 state = PXBEGIN;
6868 id = 0;
6869 defacl = FALSE;
6870 mode = 0;
6871 apermsset = 0;
6872 dpermsset = 0;
6873 tag = 0;
6874 perms = 0;
6875 k = l = 0;
6876 c = *p++;
6877 while ((state != PXEND) && (state != PXERR)) {
6878 switch (state) {
6879 case PXBEGIN :
6880 if (c == 'd') {
6881 defacl = TRUE;
6882 state = PXTAG1;
6883 break;
6884 } else
6885 if ((c >= '0') && (c <= '7')) {
6886 mode = c - '0';
6887 state = PXOCT;
6888 break;
6889 }
6890 defacl = FALSE;
6891 /* fall through */
6892 case PXTAG :
6893 switch (c) {
6894 case 'u' :
6895 tag = POSIX_ACL_USER;
6896 state = PXID;
6897 break;
6898 case 'g' :
6899 tag = POSIX_ACL_GROUP;
6900 state = PXID;
6901 break;
6902 case 'o' :
6903 tag = POSIX_ACL_OTHER;
6904 state = PXID;
6905 break;
6906 case 'm' :
6907 tag = POSIX_ACL_MASK;
6908 state = PXID;
6909 break;
6910 default :
6911 state = PXERR;
6912 break;
6913 }
6914 break;
6915 case PXTAG1 :
6916 if (c == ':')
6917 state = PXTAG;
6918 else
6919 state = PXERR;
6920 break;
6921 case PXID :
6922 if (c == ':') {
6923 if ((tag == POSIX_ACL_OTHER)
6924 || (tag == POSIX_ACL_MASK))
6925 state = PXPERM;
6926 else
6927 state = PXID1;
6928 } else
6929 state = PXERR;
6930 break;
6931 case PXID1 :
6932 if ((c >= '0') && (c <= '9')) {
6933 id = c - '0';
6934 state = PXID2;
6935 } else
6936 if (c == ':') {
6937 id = -1;
6938 if (tag == POSIX_ACL_USER)
6939 tag = POSIX_ACL_USER_OBJ;
6940 if (tag == POSIX_ACL_GROUP)
6941 tag = POSIX_ACL_GROUP_OBJ;
6942 state = PXPERM1;
6943 } else
6944 state = PXERR;
6945 break;
6946 case PXID2 :
6947 if ((c >= '0') && (c <= '9'))
6948 id = 10*id + c - '0';
6949 else
6950 if (c == ':')
6951 state = PXPERM1;
6952 else
6953 state = PXERR;
6954 break;
6955 case PXPERM :
6956 if (c == ':') {
6957 id = -1;
6958 state = PXPERM1;
6959 } else
6960 state = PXERR;
6961 break;
6962 case PXPERM1 :
6963 if ((c >= '0') && (c <= '7')) {
6964 perms = c - '0';
6965 state = PXNEXT;
6966 break;
6967 }
6968 state = PXPERM2;
6969 perms = 0;
6970 /* fall through */
6971 case PXPERM2 :
6972 switch (c) {
6973 case 'r' :
6974 perms |= POSIX_PERM_R;
6975 break;
6976 case 'w' :
6977 perms |= POSIX_PERM_W;
6978 break;
6979 case 'x' :
6980 perms |= POSIX_PERM_X;
6981 break;
6982 case ',' :
6983 case '\0' :
6984 if (defacl) {
6985 i = acccnt + l++;
6986 dpermsset |= perms;
6987 } else {
6988 i = k++;
6989 apermsset |= perms;
6990 }
6991 acl->ace[i].tag = tag;
6992 acl->ace[i].perms = perms;
6993 acl->ace[i].id = id;
6994 if (c == '\0')
6995 state = PXEND;
6996 else
6997 state = PXBEGIN;
6998 break;
6999 }
7000 break;
7001 case PXNEXT :
7002 if (!c || (c == ',')) {
7003 if (defacl) {
7004 i = acccnt + l++;
7005 dpermsset |= perms;
7006 } else {
7007 i = k++;
7008 apermsset |= perms;
7009 }
7010 acl->ace[i].tag = tag;
7011 acl->ace[i].perms = perms;
7012 acl->ace[i].id = id;
7013 if (c == '\0')
7014 state = PXEND;
7015 else
7016 state = PXBEGIN;
7017 } else
7018 state = PXERR;
7019 break;
7020 case PXOCT :
7021 if ((c >= '0') && (c <= '7'))
7022 mode = (mode << 3) + c - '0';
7023 else
7024 if (c == '\0')
7025 state = PXEND;
7026 else
7027 state = PXBEGIN;
7028 break;
7029 default :
7030 break;
7031 }
7032 c = *p++;
7033 }
7034 /* insert default mask if none defined */
7035 if (acccnt && !amask) {
7036 i = k++;
7037 acl->ace[i].tag = POSIX_ACL_MASK;
7038 acl->ace[i].perms = apermsset;
7039 acl->ace[i].id = -1;
7040 }
7041 if (defcnt && !dmask) {
7042 i = acccnt + l++;
7043 acl->ace[i].tag = POSIX_ACL_MASK;
7044 acl->ace[i].perms = dpermsset;
7045 acl->ace[i].id = -1;
7046 }
7047 /* compute the mode and tagsset */
7048 tagsset = 0;
7049 for (i=0; i<acccnt; i++)
7050 tagsset |= acl->ace[i].tag;
7051 switch (acl->ace[i].tag) {
7052 case POSIX_ACL_USER_OBJ :
7053 mode |= acl->ace[i].perms << 6;
7054 break;
7055 case POSIX_ACL_GROUP_OBJ :
7056 mode |= acl->ace[i].perms << 3;
7057 break;
7058 case POSIX_ACL_OTHER :
7059 mode |= acl->ace[i].perms;
7060 break;
7061 default :
7062 break;
7063 }
7064 pxdesc->mode = mode;
7065 pxdesc->tagsset = tagsset;
7066 pxdesc->acl.version = POSIX_VERSION;
7067 pxdesc->acl.flags = 0;
7068 pxdesc->acl.filler = 0;
7069 if (state != PXERR)
7070 ntfs_sort_posix(pxdesc);
7071showposix(pxdesc);
7072 if ((state == PXERR)
7073 || (k != acccnt)
7074 || (l != defcnt)
7075 || !ntfs_valid_posix(pxdesc)) {
7076 if (~pxdesc->tagsset
7077 & (POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER))
7078 fprintf(stderr,"User, group or other permissions missing\n");
7079 else
7080 fprintf(stderr,"Bad ACL description\n");
7081 free(pxdesc);
7082 pxdesc = (struct POSIX_SECURITY*)NULL;
7083 } else
7084 if (opt_v >= 2) {
7085 printf("Interpreted input description :\n");
7086 showposix(pxdesc);
7087 }
7088 } else
7089 errno = ENOMEM;
7090 return (pxdesc);
7091}
7092
7093#endif /* POSIXACLS */
7094
7095
7096int getoptions(int argc, char *argv[])
7097{
7098 int xarg;
7099 int narg;
7100 const char *parg;
7101 BOOL err;
7102
7103 opt_a = FALSE;
7104 opt_b = FALSE;
7105 opt_e = FALSE;
7106 opt_h = FALSE;
7107#if FORCEMASK
7108 opt_m = FALSE;
7109#endif
7110 opt_r = FALSE;
7111 opt_s = FALSE;
7112#if SELFTESTS & !USESTUBS
7113 opt_t = FALSE;
7114#endif
7115 opt_u = FALSE;
7116 opt_v = 0;
7117 xarg = 1;
7118 err = FALSE;
7119 while ((xarg < argc) && (argv[xarg][0] == '-')) {
7120 parg = argv[xarg++];
7121 while (*++parg)
7122 switch (*parg)
7123 {
7124#ifndef WIN32
7125 case 'a' :
7126 opt_a = TRUE;
7127 break;
7128#endif
7129 case 'b' :
7130 opt_b = TRUE;
7131 break;
7132 case 'e' :
7133 opt_e = TRUE;
7134 break;
7135 case 'h' :
7136 opt_h = TRUE;
7137 break;
7138#if FORCEMASK
7139 case 'm' :
7140 opt_m = TRUE;
7141 break;
7142#endif
7143 case 'r' :
7144 case 'R' :
7145 opt_r = TRUE;
7146 break;
7147 case 's' :
7148 opt_s = TRUE;
7149 break;
7150#if SELFTESTS & !USESTUBS
7151 case 't' :
7152 opt_t = TRUE;
7153 break;
7154#endif
7155 case 'u' :
7156 opt_u = TRUE;
7157 break;
7158 case 'v' :
7159 opt_v++;
7160 break;
7161 default :
7162 fprintf(stderr,"Invalid option -%c\n",*parg);
7163 err = TRUE;
7164 }
7165 }
7166 narg = argc - xarg;
7167#ifdef WIN32
7168 if ( ((opt_h || opt_s) && (narg > 1))
7169 || ((opt_r || opt_b || opt_u) && ((narg < 1) || (narg > 2)))
7170#if SELFTESTS & !USESTUBS
7171 || (opt_t && (narg > 0))
7172#endif
7173 || (opt_e && !opt_s)
7174 || (!opt_h && !opt_r && !opt_b && !opt_s
7175#if SELFTESTS & !USESTUBS
7176 && !opt_t
7177#endif
7178 && ((narg < 1) || (narg > 2))))
7179
7180 err = TRUE;
7181 if (err) {
7182 xarg = 0;
7183 fprintf(stderr,"Usage:\n");
7184#if SELFTESTS & !USESTUBS
7185 fprintf(stderr," secaudit -t\n");
7186 fprintf(stderr," run self-tests\n");
7187#endif
7188 fprintf(stderr," secaudit -h [file]\n");
7189 fprintf(stderr," display security descriptors within file\n");
7190 fprintf(stderr," secaudit [-v] file\n");
7191 fprintf(stderr," display the security parameters of file\n");
7192 fprintf(stderr," secaudit -r[v] directory\n");
7193 fprintf(stderr," display the security parameters of files in directory\n");
7194 fprintf(stderr," secaudit -b[v] directory\n");
7195 fprintf(stderr," backup the security parameters of files in directory\n");
7196 fprintf(stderr," secaudit -s[ev] [backupfile]\n");
7197 fprintf(stderr," set the security parameters as indicated in backup file\n");
7198 fprintf(stderr," with -e also set extra parameters (Windows attrib)\n");
7199 fprintf(stderr," secaudit perms file\n");
7200 fprintf(stderr," set the security parameters of file to perms\n");
7201 fprintf(stderr," secaudit -r[v] perms directory\n");
7202 fprintf(stderr," set the security parameters of files in directory to perms\n");
7203 fprintf(stderr," secaudit -u file\n");
7204 fprintf(stderr," get a user mapping proposal applicable to file\n");
7205#if POSIXACLS
7206 fprintf(stderr," Note: perms can be an octal mode or a Posix ACL description\n");
7207#else
7208 fprintf(stderr," Note: perms is an octal mode\n");
7209#endif
7210 fprintf(stderr," -v is for verbose, -vv for very verbose\n");
7211 }
7212#else
7213 if ( (opt_h && (narg > 1))
7214 || (opt_a && (narg != 1))
7215 || ((opt_r || opt_b || opt_s || opt_u)
7216 && ((narg < 1) || (narg > 3)))
7217#if SELFTESTS & !USESTUBS
7218 || (opt_t && (narg > 0))
7219#endif
7220 || (opt_e && !opt_s)
7221 || (!opt_h && !opt_a && !opt_r && !opt_b && !opt_s && !opt_u
7222#if SELFTESTS & !USESTUBS
7223 && !opt_t
7224#endif
7225#ifdef HAVE_SETXATTR
7226 && ((narg < 1) || (narg > 3))))
7227#else
7228 && ((narg < 2) || (narg > 3))))
7229#endif
7230 err = TRUE;
7231 if (err) {
7232 xarg = 0;
7233 fprintf(stderr,"Usage:\n");
7234#if SELFTESTS & !USESTUBS
7235 fprintf(stderr," secaudit -t\n");
7236 fprintf(stderr," run self-tests\n");
7237#endif
7238 fprintf(stderr," secaudit -h [file]\n");
7239 fprintf(stderr," display security descriptors within file\n");
7240 fprintf(stderr," secaudit -a[rv] volume\n");
7241 fprintf(stderr," audit the volume\n");
7242 fprintf(stderr," secaudit [-v] volume file\n");
7243 fprintf(stderr," display the security parameters of file\n");
7244 fprintf(stderr," secaudit -r[v] volume directory\n");
7245 fprintf(stderr," display the security parameters of files in directory\n");
7246 fprintf(stderr," secaudit -b[v] volume directory\n");
7247 fprintf(stderr," backup the security parameters of files in directory\n");
7248 fprintf(stderr," secaudit -s[ev] volume [backupfile]\n");
7249 fprintf(stderr," set the security parameters as indicated in backup file\n");
7250 fprintf(stderr," with -e also set extra parameters (Windows attrib)\n");
7251 fprintf(stderr," secaudit volume perms file\n");
7252 fprintf(stderr," set the security parameters of file to perms\n");
7253 fprintf(stderr," secaudit -r[v] volume perms directory\n");
7254 fprintf(stderr," set the security parameters of files in directory to perms\n");
7255 fprintf(stderr," secaudit -u volume file\n");
7256 fprintf(stderr," get a user mapping proposal applicable to file\n");
7257#ifdef HAVE_SETXATTR
7258 fprintf(stderr," special cases, do not require being root :\n");
7259 fprintf(stderr," secaudit -u mounted-file\n");
7260 fprintf(stderr," get a user mapping proposal applicable to mounted file\n");
7261 fprintf(stderr," secaudit [-v] mounted-file\n");
7262 fprintf(stderr," display the security parameters of a mounted file\n");
7263#endif
7264#if POSIXACLS
7265 fprintf(stderr," Note: perms can be an octal mode or a Posix ACL description\n");
7266#else
7267 fprintf(stderr," Note: perms is an octal mode\n");
7268#endif
7269 fprintf(stderr," -v is for verbose, -vv for very verbose\n");
7270 }
7271#endif
7272 if ((sizeof(SID) != 12) && !err) {
7273 fprintf(stderr,"Possible alignment problem, check your compiler options\n");
7274 err = TRUE;
7275 xarg = 0;
7276 }
7277 return (xarg);
7278}
7279
7280/*
7281 * Memory allocation with checks
7282 */
7283
7284#undef malloc
7285#undef calloc
7286#undef free
7287#undef isalloc
7288
7289void dumpalloc(const char *txt)
7290{
7291 struct CHKALLOC *q;
7292
7293 if (firstalloc) {
7294 printf("alloc table at %s\n",txt);
7295 for (q=firstalloc; q; q=q->next)
Steve Kondike68cb602016-08-28 00:45:36 -07007296#ifdef __x86_64__
7297 printf("%08llx : %u bytes at %08llx allocated at %s line %d\n",
7298 (long long)q,(unsigned int)q->size,
7299 (long long)q->alloc,q->file,q->line);
7300#else
Steve Kondik2111ad72013-07-07 12:07:44 -07007301 printf("%08lx : %u bytes at %08lx allocated at %s line %d\n",
7302 (long)q,(unsigned int)q->size,
7303 (long)q->alloc,q->file,q->line);
Steve Kondike68cb602016-08-28 00:45:36 -07007304#endif
Steve Kondik2111ad72013-07-07 12:07:44 -07007305 }
7306}
7307
7308void *chkmalloc(size_t size, const char *file, int line)
7309{
7310 void *p;
7311 struct CHKALLOC *q;
7312
7313 p = (void*)malloc(size+1);
7314 if (p) {
7315 ((unsigned char*)p)[size] = 0xaa;
7316 q = (struct CHKALLOC*)malloc(sizeof(struct CHKALLOC));
7317 if (q) {
7318 q->next = firstalloc;
7319 q->alloc = p;
7320 q->size = size;
7321 q->file = file;
7322 q->line = line;
7323 firstalloc = q;
7324 }
7325 }
7326 return (p);
7327}
7328
7329void *chkcalloc(size_t cnt, size_t size, const char *file, int line)
7330{
7331 return (chkmalloc(cnt*size,file,line));
7332}
7333
7334void chkfree(void *p, const char *file, int line)
7335{
7336 struct CHKALLOC *q;
7337 struct CHKALLOC *r;
7338
7339 if (p) {
7340 if (firstalloc && (firstalloc->alloc == p)) {
7341 r = firstalloc;
7342 firstalloc = firstalloc->next;
7343 } else {
7344 q = firstalloc;
7345 if (q)
7346 while (q->next && (q->next->alloc != p))
7347 q = q->next;
7348 if (q && q->next) {
7349 r = q->next;
7350 q->next = r->next;
7351 } else {
7352 r = (struct CHKALLOC*)NULL;
7353 printf("** freeing unallocated memory in %s line %d\n",file,line);
7354 if (!isatty(1))
7355 fprintf(stderr,"** freeing unallocated memory in %s line %d\n",file,line);
7356 }
7357 }
7358 if (r) {
7359 if (((unsigned char*)p)[r->size] != 0xaa) {
7360 printf("** memory corruption, alloc in %s line %d release in %s %d\n",
7361 r->file,r->line,file,line);
7362 if (!isatty(1))
7363 fprintf(stderr,"** memory corruption, alloc in %s line %d release in %s %d\n",
7364 r->file,r->line,file,line);
7365 }
7366 memset(p,0xaa,r->size);
7367 free(r);
7368 free(p);
7369 }
7370 }
7371}
7372
7373void *stdmalloc(size_t size)
7374{
7375 return (malloc(size));
7376}
7377
7378void stdfree(void *p)
7379{
7380 free(p);
7381}
7382
7383BOOL chkisalloc(void *p, const char *file, int line)
7384{
7385 struct CHKALLOC *q;
7386
7387 if (p) {
7388 q = firstalloc;
7389 while (q && (q->alloc != p))
7390 q = q->next;
7391 } else
7392 q = (struct CHKALLOC*)NULL;
7393 if (!p || !q) {
Steve Kondike68cb602016-08-28 00:45:36 -07007394#ifdef __x86_64__
7395 printf("error in %s %d : 0x%llx not allocated\n",file,line,
7396 (long long)p);
7397#else
7398 printf("error in %s %d : 0x%lx not allocated\n",file,line,
7399 (long)p);
7400#endif
Steve Kondik2111ad72013-07-07 12:07:44 -07007401 }
7402 return (p && q);
7403}
7404
7405
7406
7407
7408#ifdef WIN32
7409
7410/*
7411 * Windows version
7412 */
7413
7414main(argc,argv)
7415int argc;
7416char *argv[];
7417{
7418 FILE *fd;
7419 int xarg;
7420 int mode;
7421 unsigned int size;
7422 BOOL cmderr;
7423 char *filename;
7424 const char *p;
7425 int i;
7426#if POSIXACLS
7427 struct POSIX_SECURITY *pxdesc;
7428#endif
7429
7430 printf("%s\n",BANNER);
7431 cmderr = FALSE;
7432 errors = 0;
7433 warnings = 0;
7434 xarg = getoptions(argc,argv);
7435 if (xarg) {
7436 for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++)
7437 securdata[i] = (struct SECURITY_DATA*)NULL;
7438#if POSIXACLS
7439 context.mapping[MAPUSERS] = (struct MAPPING*)NULL;
7440 context.mapping[MAPGROUPS] = (struct MAPPING*)NULL;
7441#endif
7442 firstalloc = (struct CHKALLOC*)NULL;
7443 mappingtype = MAPNONE;
7444 switch (argc - xarg) {
7445 case 0 :
7446 if (opt_h)
7447 showhex(stdin);
7448 else
7449 if (opt_s)
7450 restore(stdin);
7451#if SELFTESTS & !USESTUBS
7452 if (opt_t)
7453 selftests();
7454#endif
7455 break;
7456 case 1 :
7457 if (opt_h || opt_s) {
7458 fd = fopen(argv[xarg],"r");
7459 if (fd) {
7460 if (opt_h)
7461 showhex(fd);
7462 else
7463 restore(fd);
7464 fclose(fd);
7465 } else {
7466 fprintf(stderr,"Could not open %s\n",argv[xarg]);
7467 cmderr = TRUE;
7468 }
7469 } else {
7470 size = utf16size(argv[xarg]);
7471 if (size) {
7472 filename = (char*)malloc(2*size + 2);
7473 if (filename) {
7474 makeutf16(filename,argv[xarg]);
7475 if (opt_u) {
7476 cmderr = mapproposal(filename);
7477 } else {
7478#if POSIXACLS
7479 if (local_build_mapping(context.mapping,filename)) {
7480 printf("*** Could not get user mapping data\n");
7481 warnings++;
7482 }
7483#endif
7484 if (opt_b)
7485 cmderr = backup(filename);
7486 else {
7487 if (opt_r)
7488 cmderr = listfiles(filename);
7489 else
7490 cmderr = singleshow(filename);
7491 }
7492#if POSIXACLS
7493 ntfs_free_mapping(context.mapping);
7494#endif
7495 }
7496 free(filename);
7497 } else {
7498 fprintf(stderr,"No more memory\n");
7499 cmderr = TRUE;
7500 }
7501 } else {
7502 fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg]);
7503 cmderr = TRUE;
7504 }
7505 }
7506 break;
7507 case 2 :
7508 mode = 0;
7509 p = argv[xarg];
7510#if POSIXACLS
7511 pxdesc = encode_posix_acl(p);
7512 if (pxdesc) {
7513 size = utf16size(argv[xarg + 1]);
7514 if (size) {
7515 filename = (char*)malloc(2*size + 2);
7516 if (filename) {
7517 makeutf16(filename,argv[xarg + 1]);
7518 if (local_build_mapping(context.mapping,filename)) {
7519 printf("*** Could not get user mapping data\n");
7520 warnings++;
7521 }
7522 if (opt_r) {
7523 for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++)
7524 securdata[i] = (struct SECURITY_DATA*)NULL;
7525 recurseset_posix(filename,pxdesc);
7526 } else
7527 singleset_posix(filename,pxdesc);
7528 ntfs_free_mapping(context.mapping);
7529 free(filename);
7530 } else {
7531 fprintf(stderr,"No more memory\n");
7532 cmderr = TRUE;
7533 }
7534 chkfree(pxdesc,__FILE__,__LINE__);
7535 } else {
7536 fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg + 1]);
7537 cmderr = TRUE;
7538 }
7539 }
7540#else
7541 while ((*p >= '0') && (*p <= '7'))
7542 mode = (mode << 3) + (*p++) - '0';
7543 if (*p) {
7544 fprintf(stderr,"New mode should be given in octal\n");
7545 cmderr = TRUE;
7546 } else {
7547 size = utf16size(argv[xarg + 1]);
7548 if (size) {
7549 filename = (char*)malloc(2*size + 2);
7550 if (filename) {
7551 makeutf16(filename,argv[xarg + 1]);
7552#if POSIXACLS
7553 if (local_build_mapping(&context,filename)) {
7554 printf("*** Could not get user mapping data\n");
7555 warnings++;
7556 }
7557#endif
7558 if (opt_r) {
7559 for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++)
7560 securdata[i] = (struct SECURITY_DATA*)NULL;
7561 recurseset(filename,mode);
7562 } else
7563 singleset(filename,mode);
7564 free(filename);
7565 } else {
7566 fprintf(stderr,"No more memory\n");
7567 cmderr = TRUE;
7568 }
7569 } else {
7570 fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg + 1]);
7571 cmderr = TRUE;
7572 }
7573 }
7574#endif
7575 break;
7576#if FORCEMASK
7577 case 3 :
7578 mode = 0;
7579 forcemsk = 0;
7580 p = argv[xarg];
7581 while (*p) {
7582 if ((*p >= '0') && (*p <= '9'))
7583 forcemsk = (forcemsk << 4) + *p - '0';
7584 else forcemsk = (forcemsk << 4) + (*p & 7) + 9;
7585 p++;
7586 }
7587 p = argv[xarg + 1];
7588 while ((*p >= '0') && (*p <= '7'))
7589 mode = (mode << 3) + (*p++) - '0';
7590 if (*p) {
7591 fprintf(stderr,"New mode should be given in octal\n");
7592 cmderr = TRUE;
7593 } else {
7594 if (opt_r) {
7595 recurseset(argv[xarg + 2],mode);
7596 }
7597 else singleset(argv[xarg + 2],mode);
7598 }
7599 break;
7600#endif
7601 }
7602 if (warnings)
7603 printf("** %u %s signalled\n",warnings,
7604 (warnings > 1 ? "warnings were" : "warning was"));
7605 if (errors)
7606 printf("** %u %s found\n",errors,
7607 (errors > 1 ? "errors were" : "error was"));
7608 else
7609 if (!cmderr)
7610 printf("No errors were found\n");
7611 if (!isatty(1)) {
7612 fflush(stdout);
7613 if (warnings)
7614 fprintf(stderr,"** %u %s signalled\n",warnings,
7615 (warnings > 1 ? "warnings were" : "warning was"));
7616 if (errors)
7617 fprintf(stderr,"** %u %s found\n",errors,
7618 (errors > 1 ? "errors were" : "error was"));
7619 else
7620 fprintf(stderr,"No errors were found\n");
7621 freeblocks();
7622 }
7623 }
7624 dumpalloc("termination");
7625 if (cmderr || errors)
7626 exit(1);
7627 return (0);
7628}
7629
7630#else
7631
7632/*
7633 * Linux version
7634 */
7635
7636int main(int argc, char *argv[])
7637{
7638 FILE *fd;
7639 const char *p;
7640 int xarg;
7641 BOOL cmderr;
7642 int i;
7643#if POSIXACLS
7644 struct POSIX_SECURITY *pxdesc;
7645#else
7646 unsigned int mode;
7647#endif
7648
7649 printf("%s\n",BANNER);
7650 cmderr = FALSE;
7651 errors = 0;
7652 warnings = 0;
7653 xarg = getoptions(argc,argv);
7654 if (xarg) {
7655 for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++)
7656 securdata[i] = (struct SECURITY_DATA*)NULL;
7657#if POSIXACLS
7658 context.mapping[MAPUSERS] = (struct MAPPING*)NULL;
7659 context.mapping[MAPGROUPS] = (struct MAPPING*)NULL;
7660#endif
7661 firstalloc = (struct CHKALLOC*)NULL;
7662 mappingtype = MAPNONE;
7663 switch (argc - xarg) {
7664 case 0 :
7665 if (opt_h)
7666 showhex(stdin);
7667#if SELFTESTS & !USESTUBS
7668 if (opt_t)
7669 selftests();
7670#endif
7671 break;
7672 case 1 :
7673 if (opt_a)
7674 cmderr = audit(argv[xarg]);
7675 else
7676 if (opt_h) {
7677 fd = fopen(argv[xarg],"rb");
7678 if (fd) {
7679 showhex(fd);
7680 fclose(fd);
7681 } else {
7682 fprintf(stderr,"Could not open %s\n",argv[xarg]);
7683 cmderr = TRUE;
7684 }
7685 } else
7686 if (opt_b)
7687 cmderr = backup(argv[xarg],"/");
7688 else
7689 if (opt_r)
7690 cmderr = listfiles(argv[xarg],"/");
7691 else
7692 if (opt_s)
7693 cmderr = dorestore(argv[xarg],stdin);
7694 else
7695 cmderr = processmounted(argv[xarg]);
7696 break;
7697 case 2 :
7698 if (opt_b)
7699 cmderr = backup(argv[xarg],argv[xarg+1]);
7700 else
7701 if (opt_s) {
7702 fd = fopen(argv[xarg+1],"rb");
7703 if (fd) {
7704 if (dorestore(argv[xarg],fd))
7705 cmderr = TRUE;
7706 fclose(fd);
7707 } else {
7708 fprintf(stderr,"Could not open %s\n",argv[xarg]);
7709 cmderr = TRUE;
7710 }
7711 } else
7712 if (opt_u)
7713 cmderr = mapproposal(argv[xarg],argv[xarg+1]);
7714 else
7715 cmderr = listfiles(argv[xarg],argv[xarg+1]);
7716 break;
7717 case 3 :
7718 p = argv[xarg+1];
7719#if POSIXACLS
7720 pxdesc = encode_posix_acl(p);
7721 if (pxdesc) {
7722 if (!getuid() && open_security_api()) {
7723 if (open_volume(argv[xarg],NTFS_MNT_NONE)) {
7724 if (opt_r) {
7725 for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++)
7726 securdata[i] = (struct SECURITY_DATA*)NULL;
7727 recurseset_posix(argv[xarg + 2],pxdesc);
7728 } else
7729 singleset_posix(argv[xarg + 2],pxdesc);
7730 close_volume(argv[xarg]);
7731 } else {
7732 fprintf(stderr,"Could not open volume %s\n",argv[xarg]);
7733 printerror(stderr);
7734 cmderr = TRUE;
7735 }
7736 close_security_api();
7737 } else {
7738 if (getuid())
7739 fprintf(stderr,"This is only possible as root\n");
7740 else
7741 fprintf(stderr,"Could not open security API\n");
7742 cmderr = TRUE;
7743 }
7744 chkfree(pxdesc,__FILE__,__LINE__);
7745 } else
7746 cmderr = TRUE;
7747#else
7748 mode = 0;
7749 while ((*p >= '0') && (*p <= '7'))
7750 mode = (mode << 3) + (*p++) - '0';
7751 if (*p) {
7752 fprintf(stderr,"New mode should be given in octal\n");
7753 cmderr = TRUE;
7754 } else
7755 if (!getuid() && open_security_api()) {
7756 if (open_volume(argv[xarg],NTFS_MNT_NONE)) {
7757 if (opt_r) {
7758 for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++)
7759 securdata[i] = (struct SECURITY_DATA*)NULL;
7760 recurseset(argv[xarg + 2],mode);
7761 } else
7762 singleset(argv[xarg + 2],mode);
7763 close_volume(argv[xarg]);
7764 } else {
7765 fprintf(stderr,"Could not open volume %s\n",argv[xarg]);
7766 printerror(stderr);
7767 cmderr = TRUE;
7768 }
7769 close_security_api();
7770 } else {
7771 if (getuid())
7772 fprintf(stderr,"This is only possible as root\n");
7773 else
7774 fprintf(stderr,"Could not open security API\n");
7775 cmderr = TRUE;
7776 }
7777#endif
7778 break;
7779 }
7780 if (warnings)
7781 printf("** %u %s signalled\n",warnings,
7782 (warnings > 1 ? "warnings were" : "warning was"));
7783 if (errors)
7784 printf("** %u %s found\n",errors,
7785 (errors > 1 ? "errors were" : "error was"));
7786 else
7787 if (!cmderr)
7788 printf("No errors were found\n");
7789 if (!isatty(1)) {
7790 fflush(stdout);
7791 if (warnings)
7792 fprintf(stderr,"** %u %s signalled\n",warnings,
7793 (warnings > 1 ? "warnings were" : "warning was"));
7794 if (errors)
7795 fprintf(stderr,"** %u %s found\n",errors,
7796 (errors > 1 ? "errors were" : "error was"));
7797 else
7798 if (!cmderr)
7799 fprintf(stderr,"No errors were found\n");
7800 }
7801 freeblocks();
7802 } else
7803 cmderr = TRUE;
7804 dumpalloc("termination");
7805 if (cmderr || errors)
7806 exit(1);
7807 return (0);
7808}
7809
7810#endif