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