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