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