| /* |
| * Display and audit security attributes in an NTFS volume |
| * |
| * Copyright (c) 2007-2015 Jean-Pierre Andre |
| * |
| * Options : |
| * -a auditing security data |
| * -b backing up NTFS ACLs |
| * -e set extra backed-up parameters (in conjunction with -s) |
| * -h displaying hexadecimal security descriptors within a file |
| * -r recursing in a directory |
| * -s setting backed-up NTFS ACLs |
| * -u getting a user mapping proposal |
| * -v verbose (very verbose if set twice) |
| * also, if compile-time option is set |
| * -t run internal tests (with no access to storage) |
| * |
| * On Linux (being root, with volume not mounted) : |
| * secaudit -h [file] |
| * display the security descriptors found in file |
| * secaudit -a[rv] volume |
| * audit the volume |
| * secaudit [-v] volume file |
| * display the security parameters of file |
| * secaudit -r[v] volume directory |
| * display the security parameters of files in directory |
| * secaudit -b[v] volume [directory] |
| * backup the security parameters of files in directory |
| * secaudit -s[ve] volume [backupfile] |
| * set the security parameters as indicated in backup |
| * with -e set extra parameters (Windows attrib) |
| * secaudit volume perms file |
| * set the security parameters of file to perms (mode or acl) |
| * secaudit -r[v] volume perms directory |
| * set the security parameters of files in directory to perms |
| * special case, does not require being root : |
| * secaudit [-v] mounted-file |
| * display the security parameters of mounted file |
| * |
| * |
| * On Windows (the volume being part of file name) |
| * secaudit -h [file] |
| * display the security descriptors found in file |
| * secaudit [-v] file |
| * display the security parameters of file |
| * secaudit -r[v] directory |
| * display the security parameters of files in directory |
| * secaudit -b[v] directory |
| * backup the security parameters of files in directory |
| * secaudit -s[v] [backupfile] |
| * set the security parameters as indicated in backup |
| * with -e set extra parameters (Windows attrib) |
| * secaudit perms file |
| * set the security parameters of file to perms (mode or acl) |
| * secaudit -r[v] perms directory |
| * set the security parameters of files in directory to perms |
| */ |
| |
| /* History |
| * |
| * Nov 2007 |
| * - first version, by concatenating miscellaneous utilities |
| * |
| * Jan 2008, version 1.0.1 |
| * - fixed mode displaying |
| * - added a global severe errors count |
| * |
| * Feb 2008, version 1.0.2 |
| * - implemented conversions for big-endian machines |
| * |
| * Mar 2008, version 1.0.3 |
| * - avoided consistency checks on $Secure when there is no such file |
| * |
| * Mar 2008, version 1.0.4 |
| * - changed ordering of ACE's |
| * - changed representation for special flags |
| * - defaulted to stdin for option -h |
| * - added self tests (compile time option) |
| * - fixed errors specific to big-endian computers |
| * |
| * Apr 2008, version 1.1.0 |
| * - developped Posix ACLs to NTFS ACLs conversions |
| * - developped NTFS ACLs backup and restore |
| * |
| * Apr 2008, version 1.1.1 |
| * - fixed an error specific to big-endian computers |
| * - checked hash value and fixed error report in restore |
| * - improved display in showhex() and restore() |
| * |
| * Apr 2008, version 1.1.2 |
| * - improved and fixed Posix ACLs to NTFS ACLs conversions |
| * |
| * Apr 2008, version 1.1.3 |
| * - reenabled recursion for setting a new mode or ACL |
| * - processed Unicode file names and displayed them as UTF-8 |
| * - allocated dynamically memory for file names when recursing |
| * |
| * May 2008, version 1.1.4 |
| * - all Unicode/UTF-8 strings checked and processed |
| * |
| * Jul 2008, version 1.1.5 |
| * - made Windows owner consistent with Linux owner when changing mode |
| * - allowed owner change on Windows when it does not match Linux owner |
| * - skipped currently unused code |
| * |
| * Aug 2008, version 1.2.0 |
| * - processed \.NTFS-3G\UserMapping on Windows |
| * - made use of user mappings through the security API or direct access |
| * - fixed a bug in restore |
| * - fixed UTF-8 conversions |
| * |
| * Sep 2008, version 1.3.0 |
| * - split the code to have part of it shared with ntfs-3g library |
| * - fixed testing for end of SDS block |
| * - added samples checking in selftest for easier debugging |
| * |
| * Oct 2008, version 1.3.1 |
| * - fixed outputting long long data when testing on a Palm organizer |
| * |
| * Dec 2008, version 1.3.2 |
| * - fixed restoring ACLs |
| * - added optional logging of ACL hashes to facilitate restore checks |
| * - fixed collecting SACLs |
| * - fixed setting special control flags |
| * - fixed clearing existing SACLs (Linux only) and DACLs |
| * - changed the sequencing of items when quering a security descriptor |
| * - avoided recursing on junctions and symlinks on Windows |
| * |
| * Jan 2009, version 1.3.3 |
| * - save/restore Windows attributes (code from Faisal) |
| * |
| * Mar 2009, version 1.3.4 |
| * - enabled displaying attributes of a mounted file over Linux |
| * |
| * Apr 2009, version 1.3.5 |
| * - fixed initialisation of stand-alone user mapping |
| * - fixed POSIXACL redefinition when included in the ntfs-3g package |
| * - fixed displaying of options |
| * - fixed a dependency on the shared library version used |
| * |
| * May 2009, version 1.3.6 |
| * - added new samples for self testing |
| * |
| * Jun 2009, version 1.3.7 |
| * - fixed displaying owner and group of a mounted file over Linux |
| * |
| * Jul 2009, version 1.3.8 |
| * - fixed again displaying owner and group of a mounted file over Linux |
| * - cleaned some code to avoid warnings |
| * |
| * Nov 2009, version 1.3.9 |
| * - allowed security descriptors up to 64K |
| * |
| * Nov 2009, version 1.3.10 |
| * - applied patches for MacOSX from Erik Larsson |
| * |
| * Nov 2009, version 1.3.11 |
| * - replace <attr/xattr.h> by <sys/xattr.h> (provided by glibc) |
| * |
| * Dec 2009, version 1.3.12 |
| * - worked around "const" possibly redefined in config.h |
| * |
| * Dec 2009, version 1.3.13 |
| * - fixed the return code of dorestore() |
| * |
| * Dec 2009, version 1.3.14 |
| * - adapted to opensolaris |
| * |
| * Jan 2010, version 1.3.15 |
| * - more adaptations to opensolaris |
| * - removed the fix for return code of dorestore() |
| * |
| * Jan 2010, version 1.3.16 |
| * - repeated the fix for return code of dorestore() |
| * |
| * Mar 2010, version 1.3.17 |
| * - adapted to new default user mapping |
| * - fixed #ifdef'd code for selftest |
| * |
| * May 2010, version 1.3.18 |
| * - redefined early error logging |
| * |
| * Mar 2011, version 1.3.19 |
| * - fixed interface to ntfs_initialize_file_security() |
| * |
| * Apr 2011, version 1.3.20 |
| * - fixed false memory leak detection |
| * |
| * Jun 2011, version 1.3.21 |
| * - cleaned a few unneeded variables |
| * |
| * Nov 2011, version 1.3.22 |
| * - added a distinctive prefix to owner and group SID |
| * - fixed a false memory leak detection |
| * |
| * Jun 2012, version 1.3.23 |
| * - added support for SACL (nickgarvey) |
| * |
| * Jul 2012, version 1.3.24 |
| * - added self-tests for authenticated users |
| * - added display of ace-inherited flag |
| * - made runnable on OpenIndiana |
| * |
| * Aug 2012, version 1.4.0 |
| * - added an option for user mapping proposal |
| * |
| * Sep 2013, version 1.4.1 |
| * - silenced an aliasing warning by gcc >= 4.8 |
| * |
| * May 2014, version 1.4.2 |
| * - decoded GENERIC_ALL permissions |
| * - decoded more "well-known" and generic SIDs |
| * - showed Windows ownership in verbose situations |
| * - fixed apparent const violations |
| * |
| * Dec 2014, version 1.4.3 |
| * - fixed displaying "UserMapping" as a file name |
| * |
| * Mar 2015, version 1.4.5 |
| * - adapted to new NTFS ACLs when owner is same as group |
| * |
| * May 2015, version 1.4.6 |
| * - made to load shared library based on generic name |
| */ |
| |
| /* |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program (in the main directory of the NTFS-3G |
| * distribution in the file COPYING); if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| /* |
| * General parameters which may have to be adapted to needs |
| */ |
| |
| #define AUDT_VERSION "1.4.6" |
| |
| #define GET_FILE_SECURITY "ntfs_get_file_security" |
| #define SET_FILE_SECURITY "ntfs_set_file_security" |
| #define GET_FILE_ATTRIBUTES "ntfs_get_file_attributes" |
| #define SET_FILE_ATTRIBUTES "ntfs_set_file_attributes" |
| #define READ_DIRECTORY "ntfs_read_directory" |
| #define READ_SDS "ntfs_read_sds" |
| #define READ_SII "ntfs_read_sii" |
| #define READ_SDH "ntfs_read_sdh" |
| #define GET_USER "ntfs_get_user" |
| #define GET_GROUP "ntfs_get_group" |
| #define GET_USID "ntfs_get_usid" |
| #define GET_GSID "ntfs_get_gsid" |
| #define INIT_FILE_SECURITY "ntfs_initialize_file_security" |
| #define LEAVE_FILE_SECURITY "ntfs_leave_file_security" |
| |
| /* |
| * External declarations |
| */ |
| |
| #include <stdio.h> |
| #include <time.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <stdarg.h> |
| |
| /* |
| * integration into secaudit, check whether Win32, |
| * may have to be adapted to compiler or something else |
| */ |
| |
| #ifndef WIN32 |
| #if defined(__WIN32) | defined(__WIN32__) | defined(WNSC) |
| #define WIN32 1 |
| #endif |
| #endif |
| |
| /* |
| * integration into secaudit/Win32 |
| */ |
| #ifdef WIN32 |
| #include <windows.h> |
| #define __LITTLE_ENDIAN 1234 |
| #define __BYTE_ORDER __LITTLE_ENDIAN |
| #else |
| /* |
| * integration into secaudit/STSC |
| */ |
| #ifdef STSC |
| #include <stat.h> |
| #undef __BYTE_ORDER |
| #define __BYTE_ORDER __BIG_ENDIAN |
| #else |
| /* |
| * integration into secaudit/Linux |
| */ |
| |
| #include <sys/stat.h> |
| #ifdef HAVE_ENDIAN_H |
| #include <endian.h> |
| #endif |
| #ifdef HAVE_MACHINE_ENDIAN_H |
| #include <machine/endian.h> |
| #endif |
| #include <unistd.h> |
| #include <dlfcn.h> |
| #endif /* STSC */ |
| #endif /* WIN32 */ |
| #include "secaudit.h" |
| |
| #ifndef WIN32 |
| |
| #ifndef STSC |
| |
| #if !defined(HAVE_CONFIG_H) && POSIXACLS && !defined(__SVR4) |
| /* require <sys/xattr.h> if not integrated into ntfs-3g package */ |
| #define HAVE_SETXATTR 1 |
| #endif |
| |
| #ifdef HAVE_CONFIG_H |
| #ifdef _FILE_OFFSET_BITS |
| #undef _FILE_OFFSET_BITS /* work around "_FILE_OFFSET_BITS" possibly already defined */ |
| #endif |
| /* <sys/xattr.h> according to config.h if integrated into ntfs-3g package */ |
| #include "config.h" |
| #ifdef const /* work around "const" possibly redefined in config.h */ |
| #undef const |
| #endif |
| #ifndef POSIXACLS |
| #define POSIXACLS 0 |
| #endif |
| #endif /* HAVE_CONFIG_H */ |
| |
| #ifdef HAVE_SETXATTR |
| #include <sys/xattr.h> |
| #else |
| #warning "The extended attribute package is not available" |
| #endif /* HAVE_SETXATTR */ |
| |
| #endif /* STSC */ |
| |
| #define NTFS_MNT_NONE 0 /* no flag for mounting the device */ |
| #define NTFS_MNT_RDONLY 1 /* flag for mounting the device read-only */ |
| |
| struct CALLBACK; |
| |
| typedef int (*dircallback)(struct CALLBACK *context, char *ntfsname, |
| int length, int type, long long pos, u64 mft_ref, |
| unsigned int dt_type); |
| |
| #ifndef HAVE_SYSLOG_H |
| void ntfs_log_early_error(const char *format, ...) |
| __attribute__((format(printf, 1, 2))); |
| #endif |
| |
| #if USESTUBS | defined(STSC) |
| |
| int ntfs_get_file_security(void *scapi, |
| const char *path, DWORD selection, |
| char *buf, DWORD buflen, LPDWORD psize); |
| BOOL ntfs_set_file_security(void *scapi, |
| const char *path, DWORD selection, const char *attr); |
| int ntfs_get_file_attributes(void *scapi, |
| const char *path); |
| BOOL ntfs_set_file_attributes(void *scapi, |
| const char *path, DWORD attrib); |
| BOOL ntfs_read_directory(void *scapi, |
| const char *path, dircallback callback, void *context); |
| int ntfs_read_sds(void *scapi, |
| char *buf, DWORD buflen, DWORD offset); |
| void *ntfs_read_sii(void *scapi, void *entry); |
| void *ntfs_read_sdh(void *scapi, void *entry); |
| |
| int ntfs_get_usid(void *scapi, uid_t uid, char *buf); |
| int ntfs_get_gsid(void *scapi, gid_t gid, char *buf); |
| int ntfs_get_user(void *scapi, const char *usid); |
| int ntfs_get_group(void *scapi, const char *gsid); |
| |
| void *ntfs_initialize_file_security(const char *device, unsigned long flags); |
| BOOL ntfs_leave_file_security(void *scapi); |
| |
| #else |
| |
| typedef int (*type_get_file_security)(void *scapi, |
| const char *path, DWORD selection, |
| char *buf, DWORD buflen, LPDWORD psize); |
| typedef BOOL (*type_set_file_security)(void *scapi, |
| const char *path, DWORD selection, const char *attr); |
| typedef int (*type_get_file_attributes)(void *scapi, |
| const char *path); |
| typedef BOOL (*type_set_file_attributes)(void *scapi, |
| const char *path, DWORD attrib); |
| typedef BOOL (*type_read_directory)(void *scapi, |
| const char *path, dircallback callback, void *context); |
| typedef int (*type_read_sds)(void *scapi, |
| char *buf, DWORD buflen, DWORD offset); |
| typedef void *(*type_read_sii)(void *scapi, void *entry); |
| typedef void *(*type_read_sdh)(void *scapi, void *entry); |
| |
| typedef int (*type_get_usid)(void *scapi, uid_t uid, char *buf); |
| typedef int (*type_get_gsid)(void *scapi, gid_t gid, char *buf); |
| typedef int (*type_get_user)(void *scapi, const char *usid); |
| typedef int (*type_get_group)(void *scapi, const char *gsid); |
| |
| typedef void *(*type_initialize_file_security)(const char *device, |
| unsigned long flags); |
| typedef BOOL (*type_leave_file_security)(void *scapi); |
| |
| type_get_file_security ntfs_get_file_security; |
| type_set_file_security ntfs_set_file_security; |
| type_get_file_attributes ntfs_get_file_attributes; |
| type_set_file_attributes ntfs_set_file_attributes; |
| type_read_directory ntfs_read_directory; |
| type_read_sds ntfs_read_sds; |
| type_read_sii ntfs_read_sii; |
| type_read_sdh ntfs_read_sdh; |
| |
| type_get_usid ntfs_get_usid; |
| type_get_gsid ntfs_get_gsid; |
| type_get_user ntfs_get_user; |
| type_get_group ntfs_get_group; |
| |
| type_initialize_file_security ntfs_initialize_file_security; |
| type_leave_file_security ntfs_leave_file_security; |
| |
| |
| #endif /* USESTUBS | defined(STSC) */ |
| #endif /* WIN32 */ |
| |
| #define ACCOUNTSIZE 256 /* maximum size of an account name */ |
| |
| /* |
| * Prototypes for local functions |
| */ |
| |
| BOOL open_security_api(void); |
| BOOL close_security_api(void); |
| #ifndef WIN32 |
| BOOL open_volume(const char*, unsigned long flags); |
| BOOL close_volume(const char*); |
| #endif |
| unsigned int get2l(const char*, int); |
| unsigned long get4l(const char*, int); |
| u64 get6l(const char*, int); |
| u64 get6h(const char*, int); |
| u64 get8l(const char*, int); |
| void set2l(char*, unsigned int); |
| void set4l(char*, unsigned long); |
| void hexdump(const char*, int, int); |
| u32 hash(const le32*, int); |
| unsigned int utf8size(const char*, int); |
| unsigned int makeutf8(char*, const char*, int); |
| unsigned int utf16size(const char*); |
| unsigned int makeutf16(char*, const char*); |
| unsigned int utf16len(const char*); |
| void printname(FILE*, const char*); |
| void printerror(FILE*); |
| BOOL guess_dir(const char*); |
| void showsid(const char*, int, const char*, int); |
| void showusid(const char*, int); |
| void showgsid(const char*, int); |
| void showownership(const char*); |
| void showheader(const char*, int); |
| void showace(const char*, int, int, int); |
| void showacl(const char*, int, int, int); |
| void showdacl(const char*, int, int); |
| void showsacl(const char*, int, int); |
| void showall(const char*, int); |
| void showposix(const struct POSIX_SECURITY*); |
| int linux_permissions(const char*, BOOL); |
| uid_t linux_owner(const char*); |
| gid_t linux_group(const char*); |
| int basicread(void*, char*, size_t, off_t); |
| int dummyread(void*, char*, size_t, off_t); |
| int local_build_mapping(struct MAPPING *[], const char*); |
| void newblock(s32); |
| void freeblocks(void); |
| u32 getmsbhex(const char*); |
| u32 getlsbhex(const char*); |
| BOOL ishexdump(const char*, int, int); |
| void showhex(FILE*); |
| void showfull(const char*, BOOL); |
| BOOL applyattr(const char*, const char*, BOOL, int, s32); |
| BOOL restore(FILE*); |
| BOOL dorestore(const char*, FILE*); |
| u32 merge_rights(const struct POSIX_SECURITY*, BOOL); |
| void tryposix(struct POSIX_SECURITY*); |
| void check_samples(void); |
| void basictest(int, BOOL, const SID*, const SID*); |
| void posixtest(int, BOOL, const SID*, const SID*); |
| void selftests(void); |
| unsigned int getfull(char*, const char*); |
| BOOL updatefull(const char *name, DWORD flags, char *attr); |
| BOOL setfull(const char*, int, BOOL); |
| BOOL singleshow(const char*); |
| BOOL proposal(const char*, const char*); |
| BOOL showmounted(const char*); |
| BOOL processmounted(const char*); |
| BOOL recurseshow(const char*); |
| BOOL singleset(const char*, int); |
| BOOL recurseset(const char*, int); |
| #ifdef WIN32 |
| BOOL backup(const char*); |
| BOOL listfiles(const char*); |
| #if POSIXACLS |
| BOOL iterate(RECURSE, const char*, const struct POSIX_SECURITY*); |
| #else |
| BOOL iterate(RECURSE, const char*, mode_t); |
| #endif |
| #else |
| BOOL backup(const char*, const char*); |
| BOOL listfiles(const char*, const char*); |
| BOOL mapproposal(const char*, const char*); |
| #endif |
| #if POSIXACLS |
| BOOL setfull_posix(const char *, const struct POSIX_SECURITY*, BOOL); |
| struct POSIX_SECURITY *linux_permissions_posix(const char*, BOOL); |
| BOOL recurseset_posix(const char*, const struct POSIX_SECURITY*); |
| BOOL singleset_posix(const char*, const struct POSIX_SECURITY*); |
| struct POSIX_SECURITY *encode_posix_acl(const char*); |
| #endif |
| static void *stdmalloc(size_t); |
| static void stdfree(void*); |
| |
| BOOL valid_sds(const char*, unsigned int, unsigned int, |
| unsigned int, u32, BOOL); |
| BOOL valid_sii(const char*, u32); |
| BOOL valid_sdh(const char*, u32, u32); |
| int consist_sds(const char*, unsigned int, unsigned int, BOOL); |
| int consist_sii(const char*); |
| int consist_sdh(const char*); |
| int audit_sds(BOOL); |
| int audit_sii(void); |
| int audit_sdh(void); |
| void audit_summary(void); |
| BOOL audit(const char*); |
| int getoptions(int, char*[]); |
| |
| #ifndef WIN32 |
| |
| /* |
| * Structures for collecting directory contents (Linux only) |
| */ |
| |
| struct LINK { |
| struct LINK *next; |
| char name[1]; |
| } ; |
| |
| struct CALLBACK { |
| struct LINK *head; |
| const char *dir; |
| } ; |
| |
| int callback(struct CALLBACK *context, char *ntfsname, |
| int length, int type, long long pos, u64 mft_ref, |
| unsigned int dt_type); |
| #endif |
| |
| /* |
| * Global constants |
| */ |
| |
| #define BANNER "secaudit " AUDT_VERSION " : NTFS security data auditing" |
| |
| #if SELFTESTS & !USESTUBS |
| |
| /* |
| * Dummy mapping file (self tests only) |
| */ |
| |
| #define DUMMYAUTH "S-1-5-21-3141592653-589793238-462843383-" |
| char dummymapping[] = "500::" DUMMYAUTH "1000\n" |
| "501::" DUMMYAUTH "1001\n" |
| "502::" DUMMYAUTH "1002\n" |
| "503::" DUMMYAUTH "1003\n" |
| "516::" DUMMYAUTH "1016\n" |
| ":500:" DUMMYAUTH "513\r\n" |
| ":511:S-1-5-21-1607551490-981732888-1819828000-513\n" |
| ":516:" DUMMYAUTH "1012\r\n" |
| "::" DUMMYAUTH "10000\n"; |
| |
| /* |
| * SID for world (S-1-1-0) |
| */ |
| |
| static const char worldsidbytes[] = { |
| 1, /* revision */ |
| 1, /* auth count */ |
| 0, 0, 0, 0, 0, 1, /* base */ |
| 0, 0, 0, 0 /* 1st level */ |
| } ; |
| static const SID *worldsid = (const SID*)worldsidbytes; |
| |
| /* |
| * SID for authenticated user (S-1-5-11) |
| */ |
| |
| static const char authsidbytes[] = { |
| 1, /* revision */ |
| 1, /* auth count */ |
| 0, 0, 0, 0, 0, 5, /* base */ |
| 11, 0, 0, 0 /* 1st level */ |
| }; |
| |
| static const SID *authsid = (const SID*)authsidbytes; |
| |
| /* |
| * SID for administrator (S-1-5-32-544) |
| */ |
| |
| static const char adminsidbytes[] = { |
| 1, /* revision */ |
| 2, /* auth count */ |
| 0, 0, 0, 0, 0, 5, /* base */ |
| 32, 0, 0, 0, /* 1st level */ |
| 32, 2, 0, 0 /* 2nd level */ |
| }; |
| |
| static const SID *adminsid = (const SID*)adminsidbytes; |
| |
| /* |
| * SID for local users (S-1-5-32-545) |
| */ |
| |
| static const char localsidbytes[] = { |
| 1, /* revision */ |
| 2, /* auth count */ |
| 0, 0, 0, 0, 0, 5, /* base */ |
| 32, 0, 0, 0, /* 1st level */ |
| 33, 2, 0, 0 /* 2nd level */ |
| }; |
| |
| static const SID *localsid = (const SID*)localsidbytes; |
| |
| /* |
| * SID for system (S-1-5-18) |
| */ |
| |
| static const char systemsidbytes[] = { |
| 1, /* revision */ |
| 1, /* auth count */ |
| 0, 0, 0, 0, 0, 5, /* base */ |
| 18, 0, 0, 0 /* 1st level */ |
| }; |
| |
| static const SID *systemsid = (const SID*)systemsidbytes; |
| |
| #endif |
| |
| /* |
| * Global variables |
| */ |
| |
| BOOL opt_a; /* audit security data */ |
| BOOL opt_b; /* backup NTFS ACLs */ |
| BOOL opt_e; /* restore extra (currently windows attribs) */ |
| BOOL opt_h; /* display an hexadecimal descriptor in a file */ |
| BOOL opt_r; /* recursively apply to subdirectories */ |
| BOOL opt_s; /* restore NTFS ACLs */ |
| BOOL opt_u; /* user mapping proposal */ |
| #if SELFTESTS & !USESTUBS |
| BOOL opt_t; /* run self-tests */ |
| #endif |
| int opt_v; /* verbose or very verbose*/ |
| struct SECURITY_DATA *securdata[(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ)]; |
| #if FORCEMASK |
| BOOL opt_m; /* force a mask - dangerous */ |
| u32 forcemsk /* mask to force */ |
| #endif |
| unsigned int errors; /* number of severe errors */ |
| unsigned int warnings; /* number of non-severe errors */ |
| |
| struct CHKALLOC *firstalloc; |
| struct SECURITY_CONTEXT context; |
| MAPTYPE mappingtype; |
| |
| #ifdef STSC |
| #define static |
| #endif |
| |
| #ifndef WIN32 |
| |
| void *ntfs_handle; |
| void *ntfs_context = (void*)NULL; |
| |
| /* |
| * Open and close the security API (platform dependent) |
| */ |
| |
| BOOL open_security_api(void) |
| { |
| #if USESTUBS | defined(STSC) |
| return (TRUE); |
| #else |
| char *error; |
| BOOL err; |
| const char *libfile; |
| |
| err = TRUE; |
| libfile = getenv(ENVNTFS3G); |
| if (!libfile) |
| libfile = (sizeof(char*) == 8 ? LIBFILE64 : LIBFILE); |
| #ifdef __SVR4 |
| /* do not override library functions by caller ones */ |
| ntfs_handle = dlopen(libfile,RTLD_LAZY | RTLD_GROUP); |
| #else |
| ntfs_handle = dlopen(libfile,RTLD_LAZY); |
| #endif |
| if (ntfs_handle) { |
| ntfs_initialize_file_security = (type_initialize_file_security) |
| dlsym(ntfs_handle,INIT_FILE_SECURITY); |
| error = dlerror(); |
| if (error) |
| fprintf(stderr," %s\n",error); |
| else { |
| ntfs_leave_file_security = (type_leave_file_security) |
| dlsym(ntfs_handle,LEAVE_FILE_SECURITY); |
| ntfs_get_file_security = (type_get_file_security) |
| dlsym(ntfs_handle,GET_FILE_SECURITY); |
| ntfs_set_file_security = (type_set_file_security) |
| dlsym(ntfs_handle,SET_FILE_SECURITY); |
| ntfs_get_file_attributes = (type_get_file_attributes) |
| dlsym(ntfs_handle,GET_FILE_ATTRIBUTES); |
| ntfs_set_file_attributes = (type_set_file_attributes) |
| dlsym(ntfs_handle,SET_FILE_ATTRIBUTES); |
| ntfs_read_directory = (type_read_directory) |
| dlsym(ntfs_handle,READ_DIRECTORY); |
| ntfs_read_sds = (type_read_sds) |
| dlsym(ntfs_handle,READ_SDS); |
| ntfs_read_sii = (type_read_sii) |
| dlsym(ntfs_handle,READ_SII); |
| ntfs_read_sdh = (type_read_sdh) |
| dlsym(ntfs_handle,READ_SDH); |
| ntfs_get_user = (type_get_user) |
| dlsym(ntfs_handle,GET_USER); |
| ntfs_get_group = (type_get_group) |
| dlsym(ntfs_handle,GET_GROUP); |
| ntfs_get_usid = (type_get_usid) |
| dlsym(ntfs_handle,GET_USID); |
| ntfs_get_gsid = (type_get_gsid) |
| dlsym(ntfs_handle,GET_GSID); |
| err = !ntfs_initialize_file_security |
| || !ntfs_leave_file_security |
| || !ntfs_get_file_security |
| || !ntfs_set_file_security |
| || !ntfs_get_file_attributes |
| || !ntfs_set_file_attributes |
| || !ntfs_read_directory |
| || !ntfs_read_sds |
| || !ntfs_read_sii |
| || !ntfs_read_sdh |
| || !ntfs_get_user |
| || !ntfs_get_group |
| || !ntfs_get_usid |
| || !ntfs_get_gsid; |
| |
| if (error) |
| fprintf(stderr,"ntfs-3g API not available\n"); |
| } |
| } else { |
| fprintf(stderr,"Could not open ntfs-3g library\n"); |
| fprintf(stderr,"\nPlease set environment variable \"" ENVNTFS3G "\"\n"); |
| fprintf(stderr,"to appropriate path and retry\n"); |
| } |
| return (!err); |
| #endif /* USESTUBS | defined(STSC) */ |
| } |
| |
| BOOL close_security_api(void) |
| { |
| #if USESTUBS | defined(STSC) |
| return (0); |
| #else |
| return (!dlclose(ntfs_handle)); |
| #endif /* USESTUBS | defined(STSC) */ |
| } |
| |
| /* |
| * Open and close a volume (platform dependent) |
| * Assumes a single volume is opened |
| */ |
| |
| BOOL open_volume(const char *volume, unsigned long flags) |
| { |
| BOOL ok; |
| |
| ok = FALSE; |
| if (!ntfs_context) { |
| ntfs_context = ntfs_initialize_file_security(volume,flags); |
| if (ntfs_context) { |
| if (*(u32*)ntfs_context != MAGIC_API) { |
| fprintf(stderr,"Versions of ntfs-3g and secaudit" |
| " are not compatible\n"); |
| } else { |
| fprintf(stderr,"\"%s\" opened\n",volume); |
| mappingtype = MAPEXTERN; |
| ok = TRUE; |
| } |
| } else { |
| fprintf(stderr,"Could not open \"%s\"\n",volume); |
| fprintf(stderr,"Make sure \"%s\" is not mounted\n",volume); |
| } |
| } else |
| fprintf(stderr,"A volume is already open\n"); |
| return (ok); |
| } |
| |
| BOOL close_volume(const char *volume) |
| { |
| BOOL r; |
| |
| r = ntfs_leave_file_security(ntfs_context); |
| if (r) |
| fprintf(stderr,"\"%s\" closed\n",volume); |
| else |
| fprintf(stderr,"Could not close \"%s\"\n",volume); |
| ntfs_context = (void*)NULL; |
| return (r); |
| } |
| |
| #endif /* WIN32 */ |
| |
| /* |
| * Extract small or big endian data from an array of bytes |
| */ |
| |
| unsigned int get2l(const char *attr, int p) |
| { |
| int i; |
| unsigned int v; |
| |
| v = 0; |
| for (i=0; i<2; i++) |
| v += (attr[p+i] & 255) << (8*i); |
| return (v); |
| } |
| |
| unsigned long get4l(const char *attr, int p) |
| { |
| int i; |
| unsigned long v; |
| |
| v = 0; |
| for (i=0; i<4; i++) |
| v += ((long)(attr[p+i] & 255)) << (8*i); |
| return (v); |
| } |
| |
| u64 get6l(const char *attr, int p) |
| { |
| int i; |
| u64 v; |
| |
| v = 0; |
| for (i=0; i<6; i++) |
| v += ((long long)(attr[p+i] & 255)) << (8*i); |
| return (v); |
| } |
| |
| u64 get6h(const char *attr, int p) |
| { |
| int i; |
| u64 v; |
| |
| v = 0; |
| for (i=0; i<6; i++) |
| v = (v << 8) + (attr[p+i] & 255); |
| return (v); |
| } |
| |
| u64 get8l(const char *attr, int p) |
| { |
| int i; |
| u64 v; |
| |
| v = 0; |
| for (i=0; i<8; i++) |
| v += ((long long)(attr[p+i] & 255)) << (8*i); |
| return (v); |
| } |
| |
| /* |
| * Set small or big endian data into an array of bytes |
| */ |
| |
| void set2l(char *p, unsigned int v) |
| { |
| int i; |
| |
| for (i=0; i<2; i++) |
| p[i] = ((v >> 8*i) & 255); |
| } |
| |
| void set4l(char *p, unsigned long v) |
| { |
| int i; |
| |
| for (i=0; i<4; i++) |
| p[i] = ((v >> 8*i) & 255); |
| } |
| |
| |
| /* |
| * hexadecimal dump of an array of bytes |
| */ |
| |
| void hexdump(const char *attr, int size, int level) |
| { |
| int i,j; |
| |
| for (i=0; i<size; i+=16) { |
| if (level) |
| printf("%*c",level,' '); |
| printf("%06x ",i); |
| for (j=i; (j<(i+16)) && (j<size); j++) |
| printf((j & 3 ? "%02x" : " %02x"),attr[j] & 255); |
| printf("\n"); |
| } |
| } |
| |
| u32 hash(const le32 *buf, int size /* bytes */) |
| { |
| u32 h; |
| int i; |
| |
| h = 0; |
| for (i=0; 4*i<size; i++) |
| h = le32_to_cpu(buf[i]) + (h << 3) + ((h >> 29) & 7); |
| return (h); |
| } |
| |
| /* |
| * Evaluate the size of UTS-8 conversion of a UTF-16LE text |
| * trailing '\0' not accounted for |
| * Returns 0 for invalid input |
| */ |
| |
| unsigned int utf8size(const char *utf16, int length) |
| { |
| int i; |
| unsigned int size; |
| enum { BASE, SURR, ERR } state; |
| |
| size = 0; |
| state = BASE; |
| for (i=0; i<2*length; i+=2) { |
| switch (state) { |
| case BASE : |
| if (utf16[i+1] & 0xf8) { |
| if ((utf16[i+1] & 0xf8) == 0xd8) |
| state = (utf16[i+1] & 4 ? ERR : SURR); |
| else |
| #if NOREVBOM |
| if (((utf16[i+1] & 0xff) == 0xff) |
| && ((utf16[i] & 0xfe) == 0xfe)) |
| state = ERR; |
| else |
| size += 3; |
| #else |
| size += 3; |
| #endif |
| } else |
| if ((utf16[i] & 0x80) || utf16[i+1]) |
| size += 2; |
| else |
| size++; |
| break; |
| case SURR : |
| if ((utf16[i+1] & 0xfc) == 0xdc) { |
| state = BASE; |
| size += 4; |
| } else |
| state = ERR; |
| break; |
| case ERR : |
| break; |
| } |
| } |
| if (state != BASE) |
| size = 0; |
| return (size); |
| } |
| |
| /* |
| * Convert a UTF-16LE text to UTF-8 |
| * Note : wcstombs() not used because on Linux it fails for characters |
| * not present in current locale |
| * Returns size or zero for invalid input |
| */ |
| |
| unsigned int makeutf8(char *utf8, const char *utf16, int length) |
| { |
| int i; |
| unsigned int size; |
| unsigned int rem; |
| enum { BASE, SURR, ERR } state; |
| |
| size = 0; |
| rem = 0; |
| state = BASE; |
| for (i=0; i<2*length; i+=2) { |
| switch (state) { |
| case BASE : |
| if (utf16[i+1] & 0xf8) { |
| if ((utf16[i+1] & 0xf8) == 0xd8) { |
| if (utf16[i+1] & 4) |
| state = ERR; |
| else { |
| utf8[size++] = 0xf0 + (utf16[i+1] & 7) |
| + ((utf16[i] & 0xc0) == 0xc0); |
| utf8[size++] = 0x80 + (((utf16[i] + 64) >> 2) & 63); |
| rem = utf16[i] & 3; |
| state = SURR; |
| } |
| } else { |
| #if NOREVBOM |
| if (((utf16[i+1] & 0xff) == 0xff) |
| && ((utf16[i] & 0xfe) == 0xfe)) |
| state = ERR; |
| else { |
| utf8[size++] = 0xe0 + ((utf16[i+1] >> 4) & 15); |
| utf8[size++] = 0x80 |
| + ((utf16[i+1] & 15) << 2) |
| + ((utf16[i] >> 6) & 3); |
| utf8[size++] = 0x80 + (utf16[i] & 63); |
| } |
| #else |
| utf8[size++] = 0xe0 + ((utf16[i+1] >> 4) & 15); |
| utf8[size++] = 0x80 |
| + ((utf16[i+1] & 15) << 2) |
| + ((utf16[i] >> 6) & 3); |
| utf8[size++] = 0x80 + (utf16[i] & 63); |
| #endif |
| } |
| } else |
| if ((utf16[i] & 0x80) || utf16[i+1]) { |
| utf8[size++] = 0xc0 |
| + ((utf16[i+1] & 15) << 2) |
| + ((utf16[i] >> 6) & 3); |
| utf8[size++] = 0x80 + (utf16[i] & 63); |
| } else |
| utf8[size++] = utf16[i]; |
| break; |
| case SURR : |
| if ((utf16[i+1] & 0xfc) == 0xdc) { |
| utf8[size++] = 0x80 + (rem << 4) |
| + ((utf16[i+1] & 3) << 2) |
| + ((utf16[i] >> 6) & 3); |
| utf8[size++] = 0x80 + (utf16[i] & 63); |
| state = BASE; |
| } else |
| state = ERR; |
| break; |
| case ERR : |
| break; |
| } |
| } |
| utf8[size] = 0; |
| if (state != BASE) |
| state = ERR; |
| return (state == ERR ? 0 : size); |
| } |
| |
| #ifdef WIN32 |
| |
| /* |
| * Evaluate the size of UTF-16LE conversion of a UTF-8 text |
| * (basic conversions only) |
| * trailing '\0' not accounted for |
| */ |
| |
| unsigned int utf16size(const char *utf8) |
| { |
| unsigned int size; |
| const char *p; |
| int c; |
| unsigned int code; |
| enum { BASE, TWO, THREE, THREE2, THREE3, FOUR, ERR } state; |
| |
| p = utf8; |
| size = 0; |
| state = BASE; |
| while (*p) { |
| c = *p++ & 255; |
| switch (state) { |
| case BASE : |
| if (!(c & 0x80)) |
| size++; |
| else |
| if (c < 0xc2) |
| state = ERR; |
| else |
| if (c < 0xe0) |
| state = TWO; |
| else |
| if (c < 0xf0) { |
| if (c == 0xe0) |
| state = THREE2; |
| else |
| if (c == 0xed) |
| state = THREE3; |
| else |
| state = THREE; |
| } else |
| if (c < 0xf8) { |
| state = FOUR; |
| code = c & 7; |
| } else |
| state = ERR; |
| break; |
| case TWO : |
| if ((c & 0xc0) != 0x80) |
| state = ERR; |
| else { |
| size++; |
| state = BASE; |
| } |
| break; |
| case THREE : |
| if ((c & 0xc0) != 0x80) |
| state = ERR; |
| else |
| state = TWO; |
| break; |
| case THREE2 : |
| if ((c & 0xe0) != 0xa0) |
| state = ERR; |
| else |
| state = TWO; |
| break; |
| case THREE3 : |
| if ((c & 0xe0) != 0x80) |
| state = ERR; |
| else |
| state = TWO; |
| break; |
| case FOUR : |
| if ((((code << 6) + (c & 63)) > 0x10f) |
| || (((code << 6) + (c & 63)) < 0x10)) |
| state = ERR; |
| else { |
| size++; |
| state = THREE; |
| } |
| break; |
| case ERR : |
| break; |
| } |
| } |
| if (state != BASE) size = 0; |
| return (size); |
| } |
| |
| /* |
| * Convert a UTF8 text to UTF-16LE |
| * (basic conversions only) |
| * Note : mbstowcs() not used because on Linux it fails for characters |
| * not present in current locale |
| */ |
| |
| unsigned int makeutf16(char *target, const char *utf8) |
| { |
| unsigned int size; |
| unsigned int code; |
| const char *p; |
| int c; |
| enum { BASE, TWO, THREE, THREE2, THREE3, FOUR, FOUR2, FOUR3, ERR } state; |
| |
| p = utf8; |
| size = 0; |
| c = 0; |
| state = BASE; |
| while (*p) { |
| c = *p++ & 255; |
| switch (state) { |
| case BASE : |
| if (!(c & 0x80)) { |
| target[2*size] = c; |
| target[2*size + 1] = 0; |
| size++; |
| } else { |
| if (c < 0xc2) |
| state = ERR; |
| else |
| if (c < 0xe0) { |
| code = c & 31; |
| state = TWO; |
| } else |
| if (c < 0xf0) { |
| code = c & 15; |
| if (c == 0xe0) |
| state = THREE2; |
| else |
| if (c == 0xed) |
| state = THREE3; |
| else |
| state = THREE; |
| } else |
| if (c < 0xf8) { |
| code = c & 7; |
| state = FOUR; |
| } else |
| state = ERR; |
| } |
| break; |
| case TWO : |
| #if NOREVBOM |
| if (((c & 0xc0) != 0x80) |
| || ((code == 0x3ff) && (c >= 0xbe))) |
| #else |
| if ((c & 0xc0) != 0x80) |
| #endif |
| state = ERR; |
| else { |
| target[2*size] = ((code & 3) << 6) + (c & 63); |
| target[2*size + 1] = ((code >> 2) & 255); |
| size++; |
| state = BASE; |
| } |
| break; |
| case THREE : |
| if ((c & 0xc0) != 0x80) |
| state = ERR; |
| else { |
| code = ((code & 15) << 6) + (c & 63); |
| state = TWO; |
| } |
| break; |
| case THREE2 : |
| if ((c & 0xe0) != 0xa0) |
| state = ERR; |
| else { |
| code = ((code & 15) << 6) + (c & 63); |
| state = TWO; |
| } |
| break; |
| case THREE3 : |
| if ((c & 0xe0) != 0x80) |
| state = ERR; |
| else { |
| code = ((code & 15) << 6) + (c & 63); |
| state = TWO; |
| } |
| break; |
| case FOUR : |
| if ((c & 0xc0) != 0x80) |
| state = ERR; |
| else { |
| code = (code << 6) + (c & 63); |
| state = FOUR2; |
| } |
| break; |
| case FOUR2 : |
| if ((c & 0xc0) != 0x80) |
| state = ERR; |
| else { |
| code = (code << 6) + (c & 63); |
| state = FOUR3; |
| } |
| break; |
| case FOUR3 : |
| if ((code > 0x43ff) |
| || (code < 0x400) |
| || ((c & 0xc0) != 0x80)) |
| state = ERR; |
| else { |
| target[2*size] = ((code - 0x400) >> 4) & 255; |
| target[2*size+1] = 0xd8 + (((code - 0x400) >> 12) & 3); |
| target[2*size+2] = ((code & 3) << 6) + (c & 63); |
| target[2*size+3] = 0xdc + ((code >> 2) & 3); |
| size += 2; |
| state = BASE; |
| } |
| break; |
| case ERR : |
| break; |
| } |
| } |
| if (state != BASE) |
| size = 0; |
| target[2*size] = 0; |
| target[2*size + 1] = 0; |
| return (size); |
| } |
| |
| unsigned int utf16len(const char *str) |
| { |
| unsigned int len; |
| |
| len = 0; |
| while (str[2*len] || str[2*len+1]) len++; |
| return (len); |
| } |
| |
| #endif |
| |
| /* |
| * Print a file name |
| * on Windows it prints UTF-16LE names as UTF-8 |
| */ |
| |
| void printname(FILE *file, const char *name) |
| { |
| #ifdef WIN32 |
| char utf8name[MAXFILENAME]; |
| |
| makeutf8(utf8name,name,utf16len(name)); |
| fprintf(file,"%s",utf8name); |
| #else |
| fprintf(file,"%s",name); |
| #endif |
| } |
| |
| /* |
| * Print the last error code |
| */ |
| |
| void printerror(FILE *file) |
| { |
| #ifdef WIN32 |
| int err; |
| const char *txt; |
| |
| err = GetLastError(); |
| switch (err) { |
| case 5 : |
| txt = "Access to security descriptor was denied"; |
| break; |
| case 1307 : |
| txt = "This SID may not be assigned as the owner of this object"; |
| break; |
| case 1308 : |
| txt = "This SID may not be assigned as the group of this object"; |
| break; |
| case 1314 : |
| txt = "You do not have the privilege to change this SID"; |
| break; |
| default : |
| txt = (const char*)NULL; |
| break; |
| } |
| if (txt) |
| fprintf(file,"Error %d : %s\n",err,txt); |
| else |
| fprintf(file,"Error %d\n",err); |
| #else |
| #ifdef STSC |
| if (errno) fprintf(file,"Error code %d\n",errno); |
| #else |
| if (errno) fprintf(file,"Error code %d : %s\n",errno,strerror(errno)); |
| #endif |
| #endif |
| } |
| |
| #ifndef HAVE_SYSLOG_H |
| |
| /* |
| * Redefine early error messages in stand-alone situations |
| */ |
| |
| void ntfs_log_early_error(const char *format, ...) |
| { |
| va_list args; |
| |
| va_start(args, format); |
| vfprintf(stderr,format,args); |
| va_end(args); |
| } |
| |
| #endif |
| |
| /* |
| * Guess whether a security attribute is intended for a directory |
| * based on the presence of inheritable ACE |
| * (not 100% reliable) |
| */ |
| |
| BOOL guess_dir(const char *attr) |
| { |
| int off; |
| int isdir; |
| int cnt; |
| int i; |
| int x; |
| |
| isdir = 0; |
| off = get4l(attr,16); |
| if (off) { |
| cnt = get2l(attr,off+4); |
| x = 8; |
| for (i=0; i<cnt; i++) { |
| if (attr[off + x + 1] & 3) |
| isdir = 1; |
| x += get2l(attr,off + x + 2); |
| } |
| } |
| return (isdir); |
| } |
| |
| /* |
| * Display a SID |
| * See http://msdn2.microsoft.com/en-us/library/aa379649.aspx |
| */ |
| |
| void showsid(const char *attr, int off, const char *prefix, int level) |
| { |
| int cnt; |
| int i; |
| BOOL known; |
| u64 auth; |
| unsigned long first; |
| unsigned long second; |
| unsigned long last; |
| char marker; |
| |
| if (opt_b) |
| marker = '#'; |
| else |
| marker = ' '; |
| cnt = attr[off+1] & 255; |
| auth = get6h(attr,off+2); |
| first = get4l(attr,off+8); |
| known = FALSE; |
| if ((attr[off] == 1) /* revision */ |
| && (auth < 100)) |
| switch (cnt) { |
| case 0 : /* no level (error) */ |
| break; |
| case 1 : /* single level */ |
| switch (auth) { |
| case 0 : |
| if (first == 0) { |
| known = TRUE; |
| printf("%*cNull SID\n",-level,marker); |
| } |
| break; |
| case 1 : |
| if (first == 0) { |
| known = TRUE; |
| printf("%*cWorld SID\n",-level,marker); |
| } |
| break; |
| case 3 : |
| switch (first) { |
| case 0 : |
| known = TRUE; |
| printf("%*cCreator owner SID\n",-level,marker); |
| break; |
| case 1 : |
| known = TRUE; |
| printf("%*cCreator group SID\n",-level,marker); |
| break; |
| } |
| break; |
| case 5 : |
| switch (first) { |
| case 1 : |
| known = TRUE; |
| printf("%*cDialup SID\n",-level,marker); |
| break; |
| case 2 : |
| known = TRUE; |
| printf("%*cNetwork SID\n",-level,marker); |
| break; |
| case 3 : |
| known = TRUE; |
| printf("%*cBatch SID\n",-level,marker); |
| break; |
| case 4 : |
| known = TRUE; |
| printf("%*cInteractive SID\n",-level,marker); |
| break; |
| case 6 : |
| known = TRUE; |
| printf("%*cService SID\n",-level,marker); |
| break; |
| case 7 : |
| known = TRUE; |
| printf("%*cAnonymous logon SID\n",-level,marker); |
| break; |
| case 11 : |
| known = TRUE; |
| printf("%*cAuthenticated user SID\n",-level,marker); |
| break; |
| case 13 : |
| known = TRUE; |
| printf("%*cLocal service SID\n",-level,marker); |
| break; |
| case 14 : |
| known = TRUE; |
| printf("%*cNetwork service SID\n",-level,marker); |
| break; |
| case 18 : |
| known = TRUE; |
| printf("%*cNT System SID\n",-level,marker); |
| break; |
| } |
| break; |
| } |
| break; |
| case 2 : /* double level */ |
| second = get4l(attr,off+12); |
| switch (auth) { |
| case 5 : |
| if (first == 32) { |
| known = TRUE; |
| switch (second) { |
| case 544 : |
| printf("%*cLocal admins SID\n",-level,marker); |
| break; |
| case 545 : |
| printf("%*cLocal users SID\n",-level,marker); |
| break; |
| case 546 : |
| printf("%*cLocal guests SID\n",-level,marker); |
| break; |
| default : |
| printf("%*cSome domain SID\n",-level,marker); |
| break; |
| } |
| } |
| break; |
| } |
| default : /* three levels or more */ |
| second = get4l(attr,off+12); |
| last = get4l(attr,off+4+4*cnt); |
| switch (auth) { |
| case 5 : |
| if (first == 21) { |
| known = TRUE; |
| switch (last) { |
| case 500 : |
| printf("%*cSystem admin SID\n",-level,marker); |
| break; |
| case 501 : |
| printf("%*cGuest SID\n",-level,marker); |
| break; |
| case 512 : |
| printf("%*cLocal admins SID\n",-level,marker); |
| break; |
| case 513 : |
| printf("%*cLocal users SID\n",-level,marker); |
| break; |
| case 514 : |
| printf("%*cLocal guests SID\n",-level,marker); |
| break; |
| default : |
| printf("%*cLocal user-%lu SID\n",-level,marker,last); |
| break; |
| } |
| } |
| break; |
| } |
| } |
| if (!known) |
| printf("%*cUnknown SID\n",-level,marker); |
| printf("%*c%shex S-%d-",-level,marker,prefix,attr[off] & 255); |
| printf("%llx",auth); |
| for (i=0; i<cnt; i++) |
| printf("-%lx",get4l(attr,off+8+4*i)); |
| printf("\n"); |
| printf("%*c%sdec S-%d-",-level,marker,prefix,attr[off] & 255); |
| printf("%llu",auth); |
| for (i=0; i<cnt; i++) |
| printf("-%lu",get4l(attr,off+8+4*i)); |
| printf("\n"); |
| } |
| |
| void showusid(const char *attr, int level) |
| { |
| int off; |
| char marker; |
| |
| if (opt_b) |
| marker = '#'; |
| else |
| marker = ' '; |
| if (level) |
| printf("%*c",-level,marker); |
| printf("Owner SID\n"); |
| off = get4l(attr,4); |
| showsid(attr,off,"O:",level+4); |
| } |
| |
| void showgsid(const char *attr, int level) |
| { |
| int off; |
| char marker; |
| |
| if (opt_b) |
| marker = '#'; |
| else |
| marker = ' '; |
| if (level) |
| printf("%*c",-level,marker); |
| printf("Group SID\n"); |
| off = get4l(attr,8); |
| showsid(attr,off,"G:",level+4); |
| } |
| |
| void showownership(const char *attr) |
| { |
| #ifdef WIN32 |
| char account[ACCOUNTSIZE]; |
| BIGSID sidcopy; |
| SID_NAME_USE use; |
| unsigned long accountsz; |
| unsigned long domainsz; |
| #endif |
| enum { SHOWOWN, SHOWGRP, SHOWINT } shown; |
| const char *sid; |
| const char *prefix; |
| u64 auth; |
| int cnt; |
| int off; |
| int i; |
| |
| for (shown=SHOWOWN; shown<=SHOWINT; shown++) { |
| switch (shown) { |
| case SHOWOWN : |
| off = get4l(attr,4); |
| sid = &attr[off]; |
| prefix = "Windows owner"; |
| break; |
| case SHOWGRP : |
| off = get4l(attr,8); |
| sid = &attr[off]; |
| prefix = "Windows group"; |
| break; |
| #if OWNERFROMACL |
| case SHOWINT : |
| off = get4l(attr,4); |
| prefix = "Interpreted owner"; |
| sid = (const char*)ntfs_acl_owner((const char*)attr); |
| if (ntfs_same_sid((const SID*)sid, |
| (const SID*)&attr[off])) |
| sid = (const char*)NULL; |
| break; |
| #endif |
| default : |
| sid = (const char*)NULL; |
| prefix = (const char*)NULL; |
| break; |
| } |
| if (sid) { |
| cnt = sid[1] & 255; |
| auth = get6h(sid,2); |
| if (opt_b) |
| printf("# %s S-%d-",prefix,sid[0] & 255); |
| else |
| printf("%s S-%d-",prefix,sid[0] & 255); |
| printf("%llu",auth); |
| for (i=0; i<cnt; i++) |
| printf("-%lu",get4l(sid,8+4*i)); |
| #ifdef WIN32 |
| memcpy(sidcopy,sid,ntfs_sid_size((const SID*)sid)); |
| accountsz = ACCOUNTSIZE; |
| domainsz = ACCOUNTSIZE; |
| if (LookupAccountSidA((const char*)NULL, sidcopy, |
| account, &accountsz, |
| (char*)NULL, &domainsz, &use)) |
| printf(" (%s)", account); |
| #endif |
| printf("\n"); |
| } |
| } |
| } |
| |
| void showheader(const char *attr, int level) |
| { |
| int flags; |
| char marker; |
| |
| if (opt_b) |
| marker = '#'; |
| else |
| marker = ' '; |
| if (level) |
| printf("%*c",-level,marker); |
| printf("Global header\n"); |
| printf("%*crevision %d\n",-level-4,marker,attr[0]); |
| flags = get2l(attr,2); |
| printf("%*cflags 0x%x\n",-level-4,marker,flags); |
| if (flags & 1) |
| printf("%*c owner is defaulted\n",-level-4,marker); |
| if (flags & 2) |
| printf("%*c group is defaulted\n",-level-4,marker); |
| if (flags & 4) |
| printf("%*c DACL present\n",-level-4,marker); |
| if (flags & 8) |
| printf("%*c DACL is defaulted\n",-level-4,marker); |
| if (flags & 0x10) |
| printf("%*c SACL present\n",-level-4,marker); |
| if (flags & 0x20) |
| printf("%*c SACL is defaulted\n",-level-4,marker); |
| if (flags & 0x100) |
| printf("%*c DACL inheritance is requested\n",-level-4,marker); |
| if (flags & 0x200) |
| printf("%*c SACL inheritance is requested\n",-level-4,marker); |
| if (flags & 0x400) |
| printf("%*c DACL was inherited automatically\n",-level-4,marker); |
| if (flags & 0x800) |
| printf("%*c SACL was inherited automatically\n",-level-4,marker); |
| if (flags & 0x1000) |
| printf("%*c DACL cannot be modified by inheritable ACEs\n",-level-4,marker); |
| if (flags & 0x2000) |
| printf("%*c SACL cannot be modified by inheritable ACEs\n",-level-4,marker); |
| if (flags & 0x8000) |
| printf("%*c self relative descriptor\n",-level-4,marker); |
| if (flags & 0x43eb) |
| printf("%*c unknown flags 0x%x present\n",-level-4,marker, |
| flags & 0x43eb); |
| printf("%*cOff USID 0x%x\n",-level-4,marker,(int)get4l(attr,4)); |
| printf("%*cOff GSID 0x%x\n",-level-4,marker,(int)get4l(attr,8)); |
| printf("%*cOff SACL 0x%x\n",-level-4,marker,(int)get4l(attr,12)); |
| printf("%*cOff DACL 0x%x\n",-level-4,marker,(int)get4l(attr,16)); |
| } |
| |
| void showace(const char *attr, int off, int isdir, int level) |
| { |
| int flags; |
| u32 rights; |
| char marker; |
| |
| if (opt_b) |
| marker = '#'; |
| else |
| marker = ' '; |
| printf("%*ctype %d\n",-level,marker,attr[off]); |
| switch (attr[off]) { |
| case 0 : |
| printf("%*cAccess allowed\n",-level-4,marker); |
| break; |
| case 1 : |
| printf("%*cAccess denied\n",-level-4,marker); |
| break; |
| case 2 : |
| printf("%*cSystem audit\n",-level-4,marker); |
| break; |
| default : |
| printf("%*cunknown\n",-level-4,marker); |
| break; |
| } |
| flags = attr[off+1] & 255; |
| printf("%*cflags 0x%x\n",-level,marker,flags); |
| if (flags & 1) |
| printf("%*cObject inherits ACE\n",-level-4,marker); |
| if (flags & 2) |
| printf("%*cContainer inherits ACE\n",-level-4,marker); |
| if (flags & 4) |
| printf("%*cDon\'t propagate inherits ACE\n",-level-4,marker); |
| if (flags & 8) |
| printf("%*cInherit only ACE\n",-level-4,marker); |
| if (flags & 0x10) |
| printf("%*cACE was inherited\n",-level-4,marker); |
| if (flags & 0x40) |
| printf("%*cAudit on success\n",-level-4,marker); |
| if (flags & 0x80) |
| printf("%*cAudit on failure\n",-level-4,marker); |
| |
| printf("%*cSize 0x%x\n",-level,marker,get2l(attr,off+2)); |
| |
| rights = get4l(attr,off+4); |
| printf("%*cAcc rgts 0x%lx\n",-level,marker,(long)rights); |
| printf("%*cObj specific acc rgts 0x%lx\n",-level-4,marker,(long)rights & 65535); |
| if (isdir) /* a directory */ { |
| if (rights & 0x01) |
| printf("%*cList directory\n",-level-8,marker); |
| if (rights & 0x02) |
| printf("%*cAdd file\n",-level-8,marker); |
| if (rights & 0x04) |
| printf("%*cAdd subdirectory\n",-level-8,marker); |
| if (rights & 0x08) |
| printf("%*cRead EA\n",-level-8,marker); |
| if (rights & 0x10) |
| printf("%*cWrite EA\n",-level-8,marker); |
| if (rights & 0x20) |
| printf("%*cTraverse\n",-level-8,marker); |
| if (rights & 0x40) |
| printf("%*cDelete child\n",-level-8,marker); |
| if (rights & 0x80) |
| printf("%*cRead attributes\n",-level-8,marker); |
| if (rights & 0x100) |
| printf("%*cWrite attributes\n",-level-8,marker); |
| } |
| else { |
| /* see FILE_READ_DATA etc in winnt.h */ |
| if (rights & 0x01) |
| printf("%*cRead data\n",-level-8,marker); |
| if (rights & 0x02) |
| printf("%*cWrite data\n",-level-8,marker); |
| if (rights & 0x04) |
| printf("%*cAppend data\n",-level-8,marker); |
| if (rights & 0x08) |
| printf("%*cRead EA\n",-level-8,marker); |
| if (rights & 0x10) |
| printf("%*cWrite EA\n",-level-8,marker); |
| if (rights & 0x20) |
| printf("%*cExecute\n",-level-8,marker); |
| if (rights & 0x80) |
| printf("%*cRead attributes\n",-level-8,marker); |
| if (rights & 0x100) |
| printf("%*cWrite attributes\n",-level-8,marker); |
| } |
| printf("%*cstandard acc rgts 0x%lx\n",-level-4,marker,(long)(rights >> 16) & 127); |
| if (rights & 0x10000) |
| printf("%*cDelete\n",-level-8,marker); |
| if (rights & 0x20000) |
| printf("%*cRead control\n",-level-8,marker); |
| if (rights & 0x40000) |
| printf("%*cWrite DAC\n",-level-8,marker); |
| if (rights & 0x80000) |
| printf("%*cWrite owner\n",-level-8,marker); |
| if (rights & 0x100000) |
| printf("%*cSynchronize\n",-level-8,marker); |
| if (rights & 0x800000) |
| printf("%*cCan access security ACL\n",-level-4,marker); |
| if (rights & 0x10000000) |
| printf("%*cGeneric all\n",-level-4,marker); |
| if (rights & 0x20000000) |
| printf("%*cGeneric execute\n",-level-4,marker); |
| if (rights & 0x40000000) |
| printf("%*cGeneric write\n",-level-4,marker); |
| if (rights & 0x80000000) |
| printf("%*cGeneric read\n",-level-4,marker); |
| |
| printf("%*cSID at 0x%x\n",-level,marker,off+8); |
| showsid(attr,off+8,"",level+4); |
| printf("%*cSummary :",-level,marker); |
| if (attr[off] == 0) |
| printf(" grant"); |
| if (attr[off] == 1) |
| printf(" deny"); |
| if (rights & le32_to_cpu(FILE_GREAD | FILE_GWRITE | FILE_GEXEC)) { |
| printf(" "); |
| if (rights & le32_to_cpu(FILE_GREAD)) |
| printf("r"); |
| if (rights & le32_to_cpu(FILE_GWRITE)) |
| printf("w"); |
| if (rights & le32_to_cpu(FILE_GEXEC)) |
| printf("x"); |
| } else |
| printf(" none"); |
| if (flags & 11) |
| printf(" inherited"); |
| if (!(flags & 8)) { |
| int sz; |
| |
| printf(" applied"); |
| sz = attr[off+9]*4 + 8; |
| if (!memcmp(&attr[off+8],&attr[get4l(attr,4)],sz)) |
| printf(" to owner"); |
| if (!memcmp(&attr[off+8],&attr[get4l(attr,8)],sz)) |
| printf(" to group"); |
| } |
| printf("\n"); |
| |
| } |
| |
| void showacl(const char *attr, int off, int isdir, int level) |
| { |
| int i; |
| int cnt; |
| int size; |
| int x; |
| char marker; |
| |
| if (opt_b) |
| marker = '#'; |
| else |
| marker = ' '; |
| size = get2l(attr,off+2); |
| printf("%*crevision %d\n",-level,marker,attr[off]); |
| printf("%*cACL size %d\n",-level,marker,size); |
| cnt = get2l(attr,off+4); |
| printf("%*cACE cnt %d\n",-level,marker,cnt); |
| x = 8; |
| for (i=0; (i<cnt) && (x < size); i++) { |
| printf("%*cACE %d at 0x%x\n",-level,marker,i + 1,off+x); |
| showace(attr,off + x,isdir,level+4); |
| x += get2l(attr,off + x + 2); |
| } |
| } |
| |
| void showdacl(const char *attr, int isdir, int level) |
| { |
| int off; |
| char marker; |
| |
| if (opt_b) |
| marker = '#'; |
| else |
| marker = ' '; |
| off = get4l(attr,16); |
| if (off) { |
| if (level) |
| printf("%*c",-level,marker); |
| printf("DACL\n"); |
| showacl(attr,off,isdir,level+4); |
| } else { |
| if (level) |
| printf("%*c",-level,marker); |
| printf("No DACL\n"); |
| } |
| } |
| |
| void showsacl(const char *attr, int isdir, int level) |
| { |
| int off; |
| char marker; |
| |
| if (opt_b) |
| marker = '#'; |
| else |
| marker = ' '; |
| off = get4l(attr,12); |
| if (off) { |
| if (level) |
| printf("%*c",-level,marker); |
| printf("SACL\n"); |
| showacl(attr,off,isdir,level+4); |
| } |
| else { |
| if (level) |
| printf("%*c",-level,marker); |
| printf("No SACL\n"); |
| } |
| } |
| |
| void showall(const char *attr, int level) |
| { |
| BOOL isdir; |
| |
| isdir = guess_dir(attr); |
| showheader(attr,level); |
| showusid(attr,level); |
| showgsid(attr,level); |
| showdacl(attr,isdir,level); |
| showsacl(attr,isdir,level); |
| } |
| |
| #if POSIXACLS |
| /* |
| * Display a Posix descriptor |
| */ |
| |
| void showposix(const struct POSIX_SECURITY *pxdesc) |
| { |
| char txperm[4]; |
| const char *txtag; |
| const char *txtype; |
| const struct POSIX_ACL *acl; |
| const struct POSIX_ACE *pxace; |
| int acccnt; |
| int defcnt; |
| int firstdef; |
| int perms; |
| u16 tag; |
| s32 id; |
| int k,l; |
| |
| if (pxdesc) { |
| acccnt = pxdesc->acccnt; |
| defcnt = pxdesc->defcnt; |
| firstdef = pxdesc->firstdef; |
| acl = &pxdesc->acl; |
| printf("Posix descriptor :\n"); |
| printf(" acccnt %d\n",acccnt); |
| printf(" defcnt %d\n",defcnt); |
| printf(" firstdef %d\n",firstdef); |
| printf(" mode : 0%03o\n",(int)pxdesc->mode); |
| printf(" tagsset : 0x%02x\n",(int)pxdesc->tagsset); |
| printf("Posix ACL :\n"); |
| printf(" version %d\n",(int)acl->version); |
| printf(" flags 0x%02x\n",(int)acl->flags); |
| for (k=0; k<(acccnt + defcnt); k++) { |
| if (k < acccnt) |
| l = k; |
| else |
| l = firstdef + k - acccnt; |
| pxace = &acl->ace[l]; |
| tag = pxace->tag; |
| perms = pxace->perms; |
| if (tag == POSIX_ACL_SPECIAL) { |
| txperm[0] = (perms & S_ISVTX ? 's' : '-'); |
| txperm[1] = (perms & S_ISUID ? 'u' : '-'); |
| txperm[2] = (perms & S_ISGID ? 'g' : '-'); |
| } else { |
| txperm[0] = (perms & 4 ? 'r' : '-'); |
| txperm[1] = (perms & 2 ? 'w' : '-'); |
| txperm[2] = (perms & 1 ? 'x' : '-'); |
| } |
| txperm[3] = 0; |
| if (k >= acccnt) |
| txtype = "default"; |
| else |
| txtype = "access "; |
| switch (tag) { |
| case POSIX_ACL_USER : |
| txtag = "USER "; |
| break; |
| case POSIX_ACL_USER_OBJ : |
| txtag = "USR-O"; |
| break; |
| case POSIX_ACL_GROUP : |
| txtag = "GROUP"; |
| break; |
| case POSIX_ACL_GROUP_OBJ : |
| txtag = "GRP-O"; |
| break; |
| case POSIX_ACL_MASK : |
| txtag = "MASK "; |
| break; |
| case POSIX_ACL_OTHER : |
| txtag = "OTHER"; |
| break; |
| case POSIX_ACL_SPECIAL : |
| txtag = "SPECL"; |
| break; |
| default : |
| txtag = "UNKWN"; |
| break; |
| } |
| id = pxace->id; |
| printf("ace %d : %s %s %4ld perms 0%03o %s\n", |
| l,txtype,txtag,(long)id, |
| perms,txperm); |
| } |
| } else |
| printf("** NULL ACL\n"); |
| } |
| |
| #endif /* POSIXACLS */ |
| |
| #if defined(WIN32) | defined(STSC) |
| |
| #else |
| |
| /* |
| * Relay to get usid as defined during mounting |
| */ |
| |
| const SID *relay_find_usid(const struct MAPPING *usermapping __attribute__((unused)), |
| uid_t uid, SID *defusid) |
| { |
| return (ntfs_get_usid(ntfs_context,uid,(char*)defusid) ? |
| defusid : (SID*)NULL); |
| } |
| |
| /* |
| * Relay to get gsid as defined during mounting |
| */ |
| |
| const SID *relay_find_gsid(const struct MAPPING *groupmapping __attribute__((unused)), |
| uid_t gid, SID *defgsid) |
| { |
| return (ntfs_get_usid(ntfs_context,gid,(char*)defgsid) ? |
| defgsid : (SID*)NULL); |
| } |
| |
| /* |
| * Relay to get uid as defined during mounting |
| */ |
| |
| uid_t relay_find_user(const struct MAPPING *mapping __attribute__((unused)), |
| const SID *usid) |
| { |
| int uid; |
| |
| uid = ntfs_get_user(ntfs_context,(const char*)usid); |
| return (uid < 0 ? 0 : uid); |
| } |
| |
| /* |
| * Relay to get gid as defined during mounting |
| */ |
| |
| gid_t relay_find_group(const struct MAPPING *mapping __attribute__((unused)), |
| const SID *gsid) |
| { |
| int gid; |
| |
| gid = ntfs_get_group(ntfs_context,(const char*)gsid); |
| return (gid < 0 ? 0 : gid); |
| } |
| |
| #endif |
| |
| #if defined(WIN32) | defined(STSC) |
| |
| /* |
| * Dummy get uid from user name, out of a Linux environment |
| */ |
| |
| struct passwd *getpwnam(const char *user) |
| { |
| ntfs_log_error("Cannot interpret id \"%s\"", user); |
| ntfs_log_error("please use numeric uids in UserMapping file\n"); |
| return ((struct passwd*)NULL); |
| } |
| |
| /* |
| * Dummy get gid from group name, out of a Linux environment |
| */ |
| |
| struct group *getgrnam(const char *group) |
| { |
| ntfs_log_error("Cannot interpret id \"%s\"", group); |
| ntfs_log_error("please use numeric gids in UserMapping file\n"); |
| return ((struct group*)NULL); |
| } |
| |
| #endif /* defined(WIN32) | defined(STSC) */ |
| |
| #if POSIXACLS |
| |
| struct POSIX_SECURITY *linux_permissions_posix(const char *attr, BOOL isdir) |
| { |
| const SECURITY_DESCRIPTOR_RELATIVE *phead; |
| #if OWNERFROMACL |
| const SID *osid; |
| #endif |
| const SID *usid; |
| const SID *gsid; |
| struct POSIX_SECURITY *posix_desc; |
| |
| phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
| gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; |
| #if OWNERFROMACL |
| osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
| usid = ntfs_acl_owner((const char*)attr); |
| #if SELFTESTS & !USESTUBS |
| if (!opt_t && !ntfs_same_sid(usid,osid)) |
| printf("== Linux owner is different from Windows owner\n"); |
| #else |
| if (!ntfs_same_sid(usid,osid)) |
| printf("== Linux owner is different from Windows owner\n"); |
| #endif |
| #else |
| usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
| #endif |
| posix_desc = ntfs_build_permissions_posix(context.mapping, |
| (const char*)attr, usid, gsid, isdir); |
| if (!posix_desc) { |
| printf("** Failed to build a Posix descriptor\n"); |
| errors++; |
| } |
| return (posix_desc); |
| } |
| |
| #endif /* POSIXACLS */ |
| |
| int linux_permissions(const char *attr, BOOL isdir) |
| { |
| const SECURITY_DESCRIPTOR_RELATIVE *phead; |
| #if OWNERFROMACL |
| const SID *osid; |
| #endif |
| const SID *usid; |
| const SID *gsid; |
| int perm; |
| |
| phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
| gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; |
| #if OWNERFROMACL |
| osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
| usid = ntfs_acl_owner((const char*)attr); |
| #if SELFTESTS & !USESTUBS |
| if (!opt_t && !ntfs_same_sid(usid,osid)) |
| printf("== Linux owner is different from Windows owner\n"); |
| #else |
| if (!ntfs_same_sid(usid,osid)) |
| printf("== Linux owner is different from Windows owner\n"); |
| #endif |
| #else |
| usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
| #endif |
| perm = ntfs_build_permissions((const char*)attr, usid, gsid, isdir); |
| if (perm < 0) { |
| printf("** Failed to build permissions\n"); |
| errors++; |
| } |
| return (perm); |
| } |
| |
| uid_t linux_owner(const char *attr) |
| { |
| const SID *usid; |
| uid_t uid; |
| |
| #if OWNERFROMACL |
| usid = ntfs_acl_owner((const char*)attr); |
| #else |
| const SECURITY_DESCRIPTOR_RELATIVE *phead; |
| |
| phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
| usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
| #endif |
| #if defined(WIN32) | defined(STSC) |
| uid = ntfs_find_user(context.mapping[MAPUSERS],usid); |
| #else |
| if (mappingtype == MAPEXTERN) |
| uid = relay_find_user(context.mapping[MAPUSERS],usid); |
| else |
| uid = ntfs_find_user(context.mapping[MAPUSERS],usid); |
| #endif |
| return (uid); |
| } |
| |
| gid_t linux_group(const char *attr) |
| { |
| const SECURITY_DESCRIPTOR_RELATIVE *phead; |
| const SID *gsid; |
| gid_t gid; |
| |
| phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
| gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; |
| #if defined(WIN32) | defined(STSC) |
| gid = ntfs_find_group(context.mapping[MAPGROUPS],gsid); |
| #else |
| if (mappingtype == MAPEXTERN) |
| gid = relay_find_group(context.mapping[MAPGROUPS],gsid); |
| else |
| gid = ntfs_find_group(context.mapping[MAPGROUPS],gsid); |
| #endif |
| return (gid); |
| } |
| |
| void newblock(s32 key) |
| { |
| struct SECURITY_DATA *psecurdata; |
| int i; |
| |
| if ((key > 0) && (key < MAXSECURID) && !securdata[key >> SECBLKSZ]) { |
| securdata[key >> SECBLKSZ] = |
| (struct SECURITY_DATA*)malloc((1 << SECBLKSZ)*sizeof(struct SECURITY_DATA)); |
| if (securdata[key >> SECBLKSZ]) |
| for (i=0; i<(1 << SECBLKSZ); i++) { |
| psecurdata = &securdata[key >> SECBLKSZ][i]; |
| psecurdata->filecount = 0; |
| psecurdata->mode = 0; |
| psecurdata->flags = 0; |
| psecurdata->attr = (char*)NULL; |
| } |
| } |
| } |
| |
| void freeblocks(void) |
| { |
| int i,j; |
| struct SECURITY_DATA *psecurdata; |
| |
| for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
| if (securdata[i]) { |
| for (j=0; j<(1 << SECBLKSZ); j++) { |
| psecurdata = &securdata[i][j]; |
| if (psecurdata->attr) |
| free(psecurdata->attr); |
| } |
| free(securdata[i]); |
| } |
| } |
| |
| /* |
| * Basic read from a user mapping file (Win32) |
| */ |
| |
| int basicread(void *fileid, char *buf, size_t size, |
| off_t pos __attribute__((unused))) |
| { |
| return (read(*(int*)fileid, buf, size)); |
| } |
| |
| #if SELFTESTS & !USESTUBS |
| |
| /* |
| * Read a dummy mapping file for tests |
| */ |
| |
| int dummyread(void *fileid __attribute__((unused)), |
| char *buf, size_t size, off_t pos) |
| { |
| size_t sz; |
| |
| if (pos >= (off_t)(sizeof(dummymapping) - 1)) |
| sz = 0; |
| else |
| if ((size + pos) >= (sizeof(dummymapping) - 1)) |
| sz = sizeof(dummymapping) - 1 - pos; |
| else |
| sz = size; |
| if (sz > 0) |
| memcpy(buf,&dummymapping[pos],sz); |
| return (sz); |
| } |
| |
| #endif /* POSIXACLS & SELFTESTS & !USESTUBS */ |
| |
| /* |
| * Apply default single user mapping |
| * returns zero if successful |
| */ |
| |
| static int do_default_mapping(struct MAPPING *mapping[], |
| const SID *usid) |
| { |
| struct MAPPING *usermapping; |
| struct MAPPING *groupmapping; |
| SID *sid; |
| int sidsz; |
| int res; |
| |
| res = -1; |
| sidsz = ntfs_sid_size(usid); |
| #if USESTUBS |
| sid = (SID*)stdmalloc(sidsz); /* will be freed within the library */ |
| #else |
| sid = (SID*)ntfs_malloc(sidsz); |
| #endif |
| if (sid) { |
| memcpy(sid,usid,sidsz); |
| #if USESTUBS |
| usermapping = (struct MAPPING*)stdmalloc(sizeof(struct MAPPING)); |
| #else |
| usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING)); |
| #endif |
| if (usermapping) { |
| #if USESTUBS |
| groupmapping = (struct MAPPING*)stdmalloc(sizeof(struct MAPPING)); |
| #else |
| groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING)); |
| #endif |
| if (groupmapping) { |
| usermapping->sid = sid; |
| usermapping->xid = 0; |
| usermapping->next = (struct MAPPING*)NULL; |
| groupmapping->sid = sid; |
| groupmapping->xid = 0; |
| groupmapping->next = (struct MAPPING*)NULL; |
| mapping[MAPUSERS] = usermapping; |
| mapping[MAPGROUPS] = groupmapping; |
| res = 0; |
| } |
| } |
| } |
| return (res); |
| } |
| |
| /* |
| * Build the user mapping |
| * - according to a mapping file if defined (or default present), |
| * - or try default single user mapping if possible |
| * |
| * The mapping is specific to a mounted device |
| * No locking done, mounting assumed non multithreaded |
| * |
| * returns zero if mapping is successful |
| * (failure should not be interpreted as an error) |
| */ |
| |
| int local_build_mapping(struct MAPPING *mapping[], const char *usermap_path) |
| { |
| #ifdef WIN32 |
| char mapfile[sizeof(MAPDIR) + sizeof(MAPFILE) + 6]; |
| char currpath[261]; |
| #else |
| char *mapfile; |
| char *p; |
| #endif |
| int fd; |
| struct MAPLIST *item; |
| struct MAPLIST *firstitem = (struct MAPLIST*)NULL; |
| struct MAPPING *usermapping; |
| struct MAPPING *groupmapping; |
| static struct { |
| u8 revision; |
| u8 levels; |
| be16 highbase; |
| be32 lowbase; |
| le32 level1; |
| le32 level2; |
| le32 level3; |
| le32 level4; |
| le32 level5; |
| } defmap = { |
| 1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5), |
| const_cpu_to_le32(21), |
| const_cpu_to_le32(DEFSECAUTH1), const_cpu_to_le32(DEFSECAUTH2), |
| const_cpu_to_le32(DEFSECAUTH3), const_cpu_to_le32(DEFSECBASE) |
| } ; |
| |
| /* be sure not to map anything until done */ |
| mapping[MAPUSERS] = (struct MAPPING*)NULL; |
| mapping[MAPGROUPS] = (struct MAPPING*)NULL; |
| |
| if (usermap_path) { |
| #ifdef WIN32 |
| /* TODO : check whether the device can store acls */ |
| strcpy(mapfile,"x:\\" MAPDIR "\\" MAPFILE); |
| if (((const le16*)usermap_path)[1] == ':') |
| mapfile[0] = usermap_path[0]; |
| else { |
| GetModuleFileName(NULL, currpath, 261); |
| mapfile[0] = currpath[0]; |
| } |
| fd = open(mapfile,O_RDONLY); |
| #else |
| fd = 0; |
| mapfile = (char*)malloc(MAXFILENAME); |
| if (mapfile) { |
| /* build a full path to locate the mapping file */ |
| if ((usermap_path[0] != '/') |
| && getcwd(mapfile,MAXFILENAME)) { |
| strcat(mapfile,"/"); |
| strcat(mapfile,usermap_path); |
| } else |
| strcpy(mapfile,usermap_path); |
| p = strrchr(mapfile,'/'); |
| if (p) |
| do { |
| strcpy(p,"/" MAPDIR "/" MAPFILE); |
| fd = open(mapfile,O_RDONLY); |
| if (fd <= 0) { |
| *p = 0; |
| p = strrchr(mapfile,'/'); |
| if (p == mapfile) |
| p = (char*)NULL; |
| } |
| } while ((fd <= 0) && p); |
| free(mapfile); |
| if (!p) { |
| printf("** Could not find the user mapping file\n"); |
| if (usermap_path[0] != '/') |
| printf(" Retry with full path of file\n"); |
| errors++; |
| } |
| } |
| #endif |
| if (fd > 0) { |
| firstitem = ntfs_read_mapping(basicread, (void*)&fd); |
| close(fd); |
| } |
| } else { |
| #if SELFTESTS & !USESTUBS |
| firstitem = ntfs_read_mapping(dummyread, (void*)NULL); |
| #endif |
| } |
| |
| if (firstitem) { |
| usermapping = ntfs_do_user_mapping(firstitem); |
| groupmapping = ntfs_do_group_mapping(firstitem); |
| if (usermapping && groupmapping) { |
| mapping[MAPUSERS] = usermapping; |
| mapping[MAPGROUPS] = groupmapping; |
| } else |
| ntfs_log_error("There were no valid user or no valid group\n"); |
| /* now we can free the memory copy of input text */ |
| /* and rely on internal representation */ |
| while (firstitem) { |
| item = firstitem->next; |
| #if USESTUBS |
| stdfree(firstitem); /* allocated within library */ |
| #else |
| free(firstitem); |
| #endif |
| firstitem = item; |
| } |
| } else { |
| do_default_mapping(mapping,(const SID*)&defmap); |
| } |
| if (mapping[MAPUSERS]) |
| mappingtype = MAPLOCAL; |
| return (!mapping[MAPUSERS]); |
| } |
| |
| /* |
| * Get an hexadecimal number (source with MSB first) |
| */ |
| |
| u32 getmsbhex(const char *text) |
| { |
| u32 v; |
| int b; |
| BOOL ok; |
| |
| v = 0; |
| ok = TRUE; |
| do { |
| b = *text++; |
| if ((b >= '0') && (b <= '9')) |
| v = (v << 4) + b - '0'; |
| else |
| if ((b >= 'a') && (b <= 'f')) |
| v = (v << 4) + b - 'a' + 10; |
| else |
| if ((b >= 'A') && (b <= 'F')) |
| v = (v << 4) + b - 'A' + 10; |
| else ok = FALSE; |
| } while (ok); |
| return (v); |
| } |
| |
| |
| /* |
| * Get an hexadecimal number (source with LSB first) |
| * An odd number of digits might yield a strange result |
| */ |
| |
| u32 getlsbhex(const char *text) |
| { |
| u32 v; |
| int b; |
| BOOL ok; |
| int pos; |
| |
| v = 0; |
| ok = TRUE; |
| pos = 0; |
| do { |
| b = *text++; |
| if ((b >= '0') && (b <= '9')) |
| v |= (u32)(b - '0') << (pos ^ 4); |
| else |
| if ((b >= 'a') && (b <= 'f')) |
| v |= (u32)(b - 'a' + 10) << (pos ^ 4); |
| else |
| if ((b >= 'A') && (b <= 'F')) |
| v |= (u32)(b - 'A' + 10) << (pos ^ 4); |
| else ok = FALSE; |
| pos += 4; |
| } while (ok); |
| return (v); |
| } |
| |
| |
| /* |
| * Check whether a line looks like an hex dump |
| */ |
| |
| BOOL ishexdump(const char *line, int first, int lth) |
| { |
| BOOL ok; |
| int i; |
| int b; |
| |
| ok = (first >= 0) && (lth >= (first + 16)); |
| for (i=0; ((first+i)<lth) && ok; i++) { |
| b = line[first + i]; |
| if ((i == 6) |
| || (i == 7) |
| || (i == 16) |
| || (i == 25) |
| || (i == 34) |
| || (i == 43)) |
| ok = (b == ' ') || (b == '\n'); |
| else |
| ok = ((b >= '0') && (b <= '9')) |
| || ((b >= 'a') && (b <= 'f')) |
| || ((b >= 'A') && (b <= 'F')); |
| } |
| return (ok); |
| } |
| |
| |
| /* |
| * Display security descriptors from a file |
| * This is typically to convert a verbose output to a very verbose one |
| */ |
| |
| void showhex(FILE *fd) |
| { |
| static char attr[MAXATTRSZ]; |
| char line[MAXLINE+1]; |
| #if POSIXACLS |
| struct POSIX_SECURITY *pxdesc; |
| #endif |
| int lth; |
| int first; |
| unsigned int pos; |
| u32 v; |
| int c; |
| int isdir; |
| int mode; |
| unsigned int off; |
| int i; |
| le32 *pattr; |
| BOOL isdump; |
| BOOL done; |
| |
| pos = 0; |
| off = 0; |
| done = FALSE; |
| do { |
| /* input a (partial) line without displaying */ |
| lth = 0; |
| first = -1; |
| do { |
| c = getc(fd); |
| if ((c != ' ') && (first < 0)) |
| first = lth; |
| if (c == EOF) |
| done = TRUE; |
| else |
| if (c != '\r') |
| line[lth++] = c; |
| } while (!done && (c != '\n') && (lth < MAXLINE)); |
| /* check whether this looks like an hexadecimal dump */ |
| isdump = ishexdump(line, first, lth); |
| if (isdump) off = getmsbhex(&line[first]); |
| /* line is not an hexadecimal dump */ |
| /* display what we have in store */ |
| if ((!isdump || !off) && pos && ntfs_valid_descr((char*)attr,pos)) { |
| printf(" Computed hash : 0x%08lx\n", |
| (unsigned long)hash((le32*)attr, |
| ntfs_attr_size(attr))); |
| isdir = guess_dir(attr); |
| printf(" Estimated type : %s\n",(isdir ? "directory" : "file")); |
| showheader(attr,4); |
| showusid(attr,4); |
| showgsid(attr,4); |
| showdacl(attr,isdir,4); |
| showsacl(attr,isdir,4); |
| showownership(attr); |
| mode = linux_permissions(attr,isdir); |
| printf("Interpreted Unix mode 0%03o\n",mode); |
| #if POSIXACLS |
| /* |
| * Posix display not possible when user |
| * mapping is not available (option -h) |
| */ |
| if (mappingtype != MAPNONE) { |
| pxdesc = linux_permissions_posix(attr,isdir); |
| if (pxdesc) { |
| showposix(pxdesc); |
| free(pxdesc); |
| } |
| } |
| #endif |
| pos = 0; |
| } |
| if (isdump && !off) |
| pos = off; |
| /* line looks like an hexadecimal dump */ |
| /* decode it into attribute */ |
| if (isdump && (off == pos)) { |
| for (i=first+8; i<lth; i+=9) { |
| pattr = (le32*)&attr[pos]; |
| v = getlsbhex(&line[i]); |
| *pattr = cpu_to_le32(v); |
| pos += 4; |
| } |
| } |
| /* display (full) current line */ |
| if (lth) printf("! "); |
| for (i=0; i<lth; i++) { |
| c = line[i]; |
| putchar(c); |
| } |
| while (!done && (c != '\n')) { |
| c = getc(fd); |
| if (c == EOF) |
| done = TRUE; |
| else |
| putchar(c); |
| } |
| } while (!done); |
| } |
| |
| BOOL applyattr(const char *fullname, const char *attr, |
| BOOL withattr, int attrib, s32 key) |
| { |
| struct SECURITY_DATA *psecurdata; |
| const char *curattr; |
| char *newattr; |
| int selection; |
| BOOL bad; |
| BOOL badattrib; |
| BOOL err; |
| #ifdef WIN32 |
| HANDLE htoken; |
| TOKEN_PRIVILEGES tkp; |
| #endif |
| |
| err = FALSE; |
| psecurdata = (struct SECURITY_DATA*)NULL; |
| curattr = (const char*)NULL; |
| newattr = (char*)NULL; |
| if ((key > 0) && (key < MAXSECURID)) { |
| if (!securdata[key >> SECBLKSZ]) |
| newblock(key); |
| if (securdata[key >> SECBLKSZ]) { |
| psecurdata = &securdata[key >> SECBLKSZ] |
| [key & ((1 << SECBLKSZ) - 1)]; |
| } |
| } |
| |
| /* If we have a usable attrib value. Try applying */ |
| badattrib = FALSE; |
| if (opt_e && (attrib != INVALID_FILE_ATTRIBUTES)) { |
| #ifdef WIN32 |
| badattrib = !SetFileAttributesW((LPCWSTR)fullname, attrib); |
| #else |
| badattrib = !ntfs_set_file_attributes(ntfs_context, fullname, attrib); |
| #endif |
| if (badattrib) { |
| printf("** Could not set Windows attrib of "); |
| printname(stdout,fullname); |
| printf(" to 0x%x\n", attrib); |
| printerror(stdout); |
| warnings++; |
| } |
| } |
| |
| if (withattr) { |
| if (psecurdata) { |
| newattr = (char*)malloc(ntfs_attr_size(attr)); |
| if (newattr) { |
| memcpy(newattr,attr,ntfs_attr_size(attr)); |
| psecurdata->attr = newattr; |
| } |
| } |
| curattr = attr; |
| } else |
| /* |
| * No explicit attr in backup, use attr defined |
| * previously for the same id |
| */ |
| if (psecurdata) |
| curattr = psecurdata->attr; |
| |
| |
| if (curattr) { |
| #ifdef WIN32 |
| selection = OWNER_SECURITY_INFORMATION |
| | GROUP_SECURITY_INFORMATION |
| | DACL_SECURITY_INFORMATION; |
| if (OpenProcessToken(GetCurrentProcess(), |
| TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &htoken)) { |
| if (LookupPrivilegeValue(NULL, SE_SECURITY_NAME, |
| &tkp.Privileges[0].Luid)) { |
| tkp.PrivilegeCount = 1; |
| tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; |
| if (AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0)) { |
| selection |= SACL_SECURITY_INFORMATION; |
| } |
| } |
| } |
| /* const missing from stupid prototype */ |
| bad = !SetFileSecurityW((LPCWSTR)fullname, |
| selection, (PSECURITY_DESCRIPTOR)(LONG_PTR)curattr); |
| if (bad) |
| switch (GetLastError()) { |
| case 1307 : |
| case 1314 : |
| printf("** Could not set owner or SACL of "); |
| printname(stdout,fullname); |
| printf(", retrying with no owner or SACL setting\n"); |
| warnings++; |
| /* const missing from stupid prototype */ |
| bad = !SetFileSecurityW((LPCWSTR)fullname, |
| selection & ~OWNER_SECURITY_INFORMATION |
| & ~SACL_SECURITY_INFORMATION, |
| (PSECURITY_DESCRIPTOR) |
| (LONG_PTR)curattr); |
| break; |
| default : |
| break; |
| } |
| /* Release privileges once we are done*/ |
| if (selection ^ SACL_SECURITY_INFORMATION) { |
| tkp.Privileges[0].Attributes = 0; |
| AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0); |
| } |
| #else |
| selection = OWNER_SECURITY_INFORMATION |
| | GROUP_SECURITY_INFORMATION |
| | DACL_SECURITY_INFORMATION |
| | SACL_SECURITY_INFORMATION; |
| bad = !ntfs_set_file_security(ntfs_context,fullname, |
| selection, (const char*)curattr); |
| #endif |
| if (bad) { |
| printf("** Could not set the ACL of "); |
| printname(stdout,fullname); |
| printf("\n"); |
| printerror(stdout); |
| err = TRUE; |
| } else |
| if (opt_v) { |
| if (opt_e && !badattrib) |
| printf("ACL and attrib have been applied to "); |
| else |
| printf("ACL has been applied to "); |
| printname(stdout,fullname); |
| printf("\n"); |
| |
| } |
| } else { |
| printf("** There was no valid ACL for "); |
| printname(stdout,fullname); |
| printf("\n"); |
| err = TRUE; |
| } |
| return (!err); |
| } |
| |
| /* |
| * Restore security descriptors from a file |
| */ |
| |
| BOOL restore(FILE *fd) |
| { |
| static char attr[MAXATTRSZ]; |
| char line[MAXFILENAME+25]; |
| char fullname[MAXFILENAME+25]; |
| SECURITY_DESCRIPTOR_RELATIVE *phead; |
| int lth; |
| int first; |
| unsigned int pos; |
| int c; |
| int isdir; |
| int mode; |
| s32 key; |
| BOOL isdump; |
| unsigned int off; |
| u32 v; |
| u32 oldhash; |
| int i; |
| int count; |
| int attrib; |
| le32 *pattr; |
| BOOL withattr; |
| BOOL done; |
| |
| pos = 0; |
| off = 0; |
| done = FALSE; |
| withattr = FALSE; |
| oldhash = 0; |
| key = 0; |
| errors = 0; |
| count = 0; |
| fullname[0] = 0; |
| attrib = INVALID_FILE_ATTRIBUTES; |
| do { |
| /* input a (partial) line without processing */ |
| lth = 0; |
| first = -1; |
| do { |
| c = getc(fd); |
| if ((c != ' ') && (first < 0)) |
| first = lth; |
| if (c == EOF) |
| done = TRUE; |
| else |
| if (c != '\r') |
| line[lth++] = c; |
| } while (!done && (c != '\n') && (lth < (MAXFILENAME + 24))); |
| /* check whether this looks like an hexadecimal dump */ |
| isdump = ishexdump(line, first, lth); |
| if (isdump) off = getmsbhex(&line[first]); |
| /* line is not an hexadecimal dump */ |
| /* apply what we have in store */ |
| if ((!isdump || !off) && pos && ntfs_valid_descr((char*)attr,pos)) { |
| withattr = TRUE; |
| if (opt_v >= 2) { |
| printf(" Computed hash : 0x%08lx\n", |
| (unsigned long)hash((le32*)attr, |
| ntfs_attr_size(attr))); |
| isdir = guess_dir(attr); |
| printf(" Estimated type : %s\n",(isdir ? "directory" : "file")); |
| showheader(attr,4); |
| showusid(attr,4); |
| showgsid(attr,4); |
| showdacl(attr,isdir,4); |
| showsacl(attr,isdir,4); |
| mode = linux_permissions(attr,isdir); |
| showownership(attr); |
| printf("Interpreted Unix mode 0%03o\n",mode); |
| } |
| pos = 0; |
| } |
| if (isdump && !off) |
| pos = off; |
| /* line looks like an hexadecimal dump */ |
| /* decode it into attribute */ |
| if (isdump && (off == pos)) { |
| for (i=first+8; i<lth; i+=9) { |
| pattr = (le32*)&attr[pos]; |
| v = getlsbhex(&line[i]); |
| *pattr = cpu_to_le32(v); |
| pos += 4; |
| } |
| } |
| /* display (full) current line unless dump or verbose */ |
| if (!isdump || opt_v) { |
| if(lth) printf("! "); |
| for (i=0; i<lth; i++) { |
| c = line[i]; |
| putchar(c); |
| } |
| } |
| while (!done && (c != '\n')) { |
| c = getc(fd); |
| if (c == EOF) |
| done = TRUE; |
| else |
| if (!isdump || opt_v) |
| putchar(c); |
| } |
| |
| line[lth] = 0; |
| while ((lth > 0) |
| && ((line[lth-1] == '\n') || (line[lth-1] == '\r'))) |
| line[--lth] = 0; |
| if (!strncmp(line,"Computed hash : 0x",18)) |
| oldhash = getmsbhex(&line[18]); |
| if (!strncmp(line,"Security key : 0x",17)) |
| key = getmsbhex(&line[17]); |
| if (!strncmp(line,"Windows attrib : 0x",19)) |
| attrib = getmsbhex(&line[19]); |
| if (done |
| || !strncmp(line,"File ",5) |
| || !strncmp(line,"Directory ",10)) { |
| /* |
| * New file or directory (or end of file) : |
| * apply attribute just collected |
| * or apply attribute defined from current key |
| */ |
| |
| if (withattr |
| && oldhash |
| && (hash((const le32*)attr,ntfs_attr_size(attr)) != oldhash)) { |
| printf("** ACL rejected, its hash is not as expected\n"); |
| errors++; |
| } else |
| if (fullname[0]) { |
| phead = (SECURITY_DESCRIPTOR_RELATIVE*)attr; |
| /* set the request for auto-inheritance */ |
| if (phead->control & SE_DACL_AUTO_INHERITED) |
| phead->control |= SE_DACL_AUTO_INHERIT_REQ; |
| if (!applyattr(fullname,attr,withattr, |
| attrib,key)) |
| errors++; |
| else |
| count++; |
| } |
| /* save current file or directory name */ |
| withattr = FALSE; |
| key = 0; |
| oldhash = 0; |
| attrib = INVALID_FILE_ATTRIBUTES; |
| if (!done) { |
| #ifdef WIN32 |
| if (!strncmp(line,"File ",5)) |
| makeutf16(fullname,&line[5]); |
| else |
| makeutf16(fullname,&line[10]); |
| #else |
| if (!strncmp(line,"File ",5)) |
| strcpy(fullname,&line[5]); |
| else |
| strcpy(fullname,&line[10]); |
| #endif |
| } |
| } |
| } while (!done); |
| printf("%d ACLs have been applied\n",count); |
| return (FALSE); |
| } |
| |
| /* |
| * Open the security API in rw mode for an ACL restoration |
| */ |
| |
| #ifdef WIN32 |
| #else |
| BOOL dorestore(const char *volume, FILE *fd) |
| { |
| BOOL err; |
| |
| err = FALSE; |
| if (!getuid()) { |
| if (open_security_api()) { |
| if (open_volume(volume,NTFS_MNT_NONE)) { |
| if (restore(fd)) err = TRUE; |
| close_volume(volume); |
| } else { |
| fprintf(stderr,"Could not open volume %s\n",volume); |
| printerror(stderr); |
| err = TRUE; |
| } |
| close_security_api(); |
| } else { |
| fprintf(stderr,"Could not open security API\n"); |
| printerror(stderr); |
| err = TRUE; |
| } |
| } else { |
| fprintf(stderr,"Restore is only possible as root\n"); |
| err = TRUE; |
| } |
| return (err); |
| } |
| #endif /* WIN32 */ |
| |
| #if POSIXACLS & SELFTESTS & !USESTUBS |
| |
| /* |
| * Merge Posix ACL rights into an u32 (self test only) |
| * |
| * Result format : -----rwxrwxrwxrwxrwx---rwxrwxrwx |
| * U1 U2 G1 G2 M o g w |
| * |
| * Only two users (U1, U2) and two groups (G1, G2) taken into account |
| */ |
| u32 merge_rights(const struct POSIX_SECURITY *pxdesc, BOOL def) |
| { |
| const struct POSIX_ACE *pxace; |
| int i; |
| int users; |
| int groups; |
| int first; |
| int last; |
| u32 rights; |
| |
| rights = 0; |
| users = 0; |
| groups = 0; |
| if (def) { |
| first = pxdesc->firstdef; |
| last = pxdesc->firstdef + pxdesc->defcnt - 1; |
| } else { |
| first = 0; |
| last = pxdesc->acccnt - 1; |
| } |
| pxace = pxdesc->acl.ace; |
| for (i=first; i<=last; i++) { |
| switch (pxace[i].tag) { |
| case POSIX_ACL_USER_OBJ : |
| rights |= (pxace[i].perms & 7) << 6; |
| break; |
| case POSIX_ACL_USER : |
| if (users < 2) |
| rights |= ((u32)pxace[i].perms & 7) << (24 - 3*users); |
| users++; |
| break; |
| case POSIX_ACL_GROUP_OBJ : |
| rights |= (pxace[i].perms & 7) << 3; |
| break; |
| case POSIX_ACL_GROUP : |
| if (groups < 2) |
| rights |= ((u32)pxace[i].perms & 7) << (18 - 3*groups); |
| groups++; |
| break; |
| case POSIX_ACL_MASK : |
| rights |= ((u32)pxace[i].perms & 7) << 12; |
| break; |
| case POSIX_ACL_OTHER : |
| rights |= (pxace[i].perms & 7); |
| break; |
| default : |
| break; |
| } |
| } |
| return (rights); |
| } |
| |
| void tryposix(struct POSIX_SECURITY *pxdesc) |
| { |
| le32 owner_sid[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ |
| { |
| const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), |
| const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), |
| const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), |
| const_cpu_to_le32(1016) |
| } ; |
| le32 group_sid[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ |
| { |
| const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), |
| const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), |
| const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), |
| const_cpu_to_le32(513) |
| } ; |
| |
| char *attr; |
| BOOL isdir; |
| mode_t mode; |
| struct POSIX_SECURITY *newpxdesc; |
| struct POSIX_SECURITY *oldpxdesc; |
| static char *oldattr = (char*)NULL; |
| |
| isdir = FALSE; |
| if (oldattr) { |
| oldpxdesc = linux_permissions_posix(oldattr, isdir); |
| newpxdesc = ntfs_merge_descr_posix(pxdesc, oldpxdesc); |
| if (!newpxdesc) |
| newpxdesc = pxdesc; |
| free(oldpxdesc); |
| if (opt_v) { |
| printf("merged descriptors :\n"); |
| showposix(newpxdesc); |
| } |
| } else |
| newpxdesc = pxdesc; |
| attr = ntfs_build_descr_posix(context.mapping,newpxdesc, |
| isdir,(SID*)owner_sid,(SID*)group_sid); |
| if (attr && ntfs_valid_descr(attr, ntfs_attr_size(attr))) { |
| if (opt_v) |
| hexdump(attr,ntfs_attr_size(attr),8); |
| if (opt_v >= 2) { |
| showheader(attr,4); |
| showusid(attr,4); |
| showgsid(attr,4); |
| showdacl(attr,isdir,4); |
| showsacl(attr,isdir,4); |
| mode = linux_permissions(attr,isdir); |
| printf("Interpreted Unix mode 0%03o\n",mode); |
| printf("Interpreted back Posix descriptor :\n"); |
| newpxdesc = linux_permissions_posix(attr,isdir); |
| showposix(newpxdesc); |
| free(newpxdesc); |
| } |
| if (oldattr) free(oldattr); |
| oldattr = attr; |
| } |
| } |
| |
| static BOOL same_posix(struct POSIX_SECURITY *pxdesc1, |
| struct POSIX_SECURITY *pxdesc2) |
| { |
| BOOL same; |
| int i; |
| |
| same = pxdesc1 |
| && pxdesc2 |
| && (pxdesc1->mode == pxdesc2->mode) |
| && (pxdesc1->acccnt == pxdesc2->acccnt) |
| && (pxdesc1->defcnt == pxdesc2->defcnt) |
| && (pxdesc1->firstdef == pxdesc2->firstdef) |
| && (pxdesc1->tagsset == pxdesc2->tagsset) |
| && (pxdesc1->acl.version == pxdesc2->acl.version) |
| && (pxdesc1->acl.flags == pxdesc2->acl.flags); |
| i = 0; |
| while (same && (i < pxdesc1->acccnt)) { |
| same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag) |
| && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms) |
| && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id); |
| i++; |
| } |
| i = pxdesc1->firstdef; |
| while (same && (i < pxdesc1->firstdef + pxdesc1->defcnt)) { |
| same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag) |
| && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms) |
| && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id); |
| i++; |
| } |
| return (same); |
| } |
| |
| #endif /* POSIXACLS & SELFTESTS & !USESTUBS */ |
| |
| #if SELFTESTS & !USESTUBS |
| |
| /* |
| * Build a dummy security descriptor |
| * returns descriptor in allocated memory, must free() after use |
| */ |
| |
| static char *build_dummy_descr(BOOL isdir __attribute__((unused)), |
| const SID *usid, const SID *gsid, |
| int cnt, |
| /* seq of int allow, SID *sid, int flags, u32 mask */ |
| ...) |
| { |
| char *attr; |
| int attrsz; |
| SECURITY_DESCRIPTOR_RELATIVE *pnhead; |
| ACL *pacl; |
| ACCESS_ALLOWED_ACE *pace; |
| va_list ap; |
| const SID *sid; |
| u32 umask; |
| le32 mask; |
| int flags; |
| BOOL allow; |
| int pos; |
| int usidsz; |
| int gsidsz; |
| int sidsz; |
| int aclsz; |
| int i; |
| |
| if (usid) |
| usidsz = ntfs_sid_size(usid); |
| else |
| usidsz = 0; |
| if (gsid) |
| gsidsz = ntfs_sid_size(gsid); |
| else |
| gsidsz = 0; |
| |
| |
| /* allocate enough space for the new security attribute */ |
| attrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE) /* header */ |
| + usidsz + gsidsz /* usid and gsid */ |
| + sizeof(ACL) /* acl header */ |
| + cnt*40; |
| |
| attr = (char*)ntfs_malloc(attrsz); |
| if (attr) { |
| /* build the main header part */ |
| pnhead = (SECURITY_DESCRIPTOR_RELATIVE*) attr; |
| pnhead->revision = SECURITY_DESCRIPTOR_REVISION; |
| pnhead->alignment = 0; |
| /* |
| * The flag SE_DACL_PROTECTED prevents the ACL |
| * to be changed in an inheritance after creation |
| */ |
| pnhead->control = SE_DACL_PRESENT | SE_DACL_PROTECTED |
| | SE_SELF_RELATIVE; |
| /* |
| * Windows prefers ACL first, do the same to |
| * get the same hash value and avoid duplication |
| */ |
| /* build the ACL header */ |
| pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE); |
| pacl = (ACL*)&attr[pos]; |
| pacl->revision = ACL_REVISION; |
| pacl->alignment1 = 0; |
| pacl->size = const_cpu_to_le16(0); /* fixed later */ |
| pacl->ace_count = cpu_to_le16(cnt); |
| pacl->alignment2 = const_cpu_to_le16(0); |
| |
| /* enter the ACEs */ |
| |
| pos += sizeof(ACL); |
| aclsz = sizeof(ACL); |
| va_start(ap,cnt); |
| for (i=0; i<cnt; i++) { |
| pace = (ACCESS_ALLOWED_ACE*)&attr[pos]; |
| allow = va_arg(ap,int); |
| sid = va_arg(ap,SID*); |
| flags = va_arg(ap,int); |
| umask = va_arg(ap,u32); |
| mask = cpu_to_le32(umask); |
| sidsz = ntfs_sid_size(sid); |
| pace->type = (allow ? ACCESS_ALLOWED_ACE_TYPE : ACCESS_DENIED_ACE_TYPE); |
| pace->flags = flags; |
| pace->size = cpu_to_le16(sidsz + 8); |
| pace->mask = mask; |
| memcpy(&pace->sid,sid,sidsz); |
| aclsz += sidsz + 8; |
| pos += sidsz + 8; |
| } |
| va_end(ap); |
| |
| /* append usid and gsid if defined */ |
| /* positions of ACL, USID and GSID into header */ |
| pnhead->owner = const_cpu_to_le32(0); |
| pnhead->group = const_cpu_to_le32(0); |
| if (usid) { |
| memcpy(&attr[pos], usid, usidsz); |
| pnhead->owner = cpu_to_le32(pos); |
| } |
| if (gsid) { |
| memcpy(&attr[pos + usidsz], gsid, gsidsz); |
| pnhead->group = cpu_to_le32(pos + usidsz); |
| } |
| /* positions of DACL and SACL into header */ |
| pnhead->sacl = const_cpu_to_le32(0); |
| if (cnt) { |
| pacl->size = cpu_to_le16(aclsz); |
| pnhead->dacl = |
| const_cpu_to_le32(sizeof( |
| SECURITY_DESCRIPTOR_RELATIVE)); |
| } else |
| pnhead->dacl = const_cpu_to_le32(0); |
| if (!ntfs_valid_descr(attr,pos+usidsz+gsidsz)) { |
| printf("** Bad sample descriptor\n"); |
| free(attr); |
| attr = (char*)NULL; |
| errors++; |
| } |
| } else |
| errno = ENOMEM; |
| return (attr); |
| } |
| |
| /* |
| * Check a few samples with special conditions |
| */ |
| |
| void check_samples() |
| { |
| char *descr = (char*)NULL; |
| BOOL isdir = FALSE; |
| mode_t perms; |
| mode_t expect = 0; |
| int cnt; |
| u32 expectacc; |
| u32 expectdef; |
| #if POSIXACLS |
| u32 accrights; |
| u32 defrights; |
| mode_t mixmode; |
| struct POSIX_SECURITY *pxdesc; |
| struct POSIX_SECURITY *pxsample; |
| const char *txsample; |
| #endif |
| le32 owner1[] = /* S-1-5-21-1833069642-4243175381-1340018762-1003 */ |
| { |
| const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), |
| const_cpu_to_le32(21), const_cpu_to_le32(1833069642), |
| const_cpu_to_le32(4243175381), const_cpu_to_le32(1340018762), |
| const_cpu_to_le32(1003) |
| } ; |
| le32 group1[] = /* S-1-5-21-1833069642-4243175381-1340018762-513 */ |
| { |
| const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), |
| const_cpu_to_le32(21), const_cpu_to_le32(1833069642), |
| const_cpu_to_le32(4243175381), const_cpu_to_le32(1340018762), |
| const_cpu_to_le32(513) |
| } ; |
| le32 group2[] = /* S-1-5-21-1607551490-981732888-1819828000-513 */ |
| { |
| const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), |
| const_cpu_to_le32(21), const_cpu_to_le32(1607551490), |
| const_cpu_to_le32(981732888), const_cpu_to_le32(1819828000), |
| const_cpu_to_le32(513) |
| } ; |
| le32 owner3[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ |
| { |
| const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), |
| const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), |
| const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), |
| const_cpu_to_le32(1016) |
| } ; |
| le32 group3[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ |
| { |
| const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), |
| const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), |
| const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), |
| const_cpu_to_le32(513) |
| } ; |
| |
| #if POSIXACLS |
| struct { |
| struct POSIX_SECURITY head; |
| struct POSIX_ACE ace[4]; |
| } sampletry1 = |
| { |
| { 0645, 4, 0, 4, 0x35, |
| { POSIX_VERSION, 0, 0 } |
| }, |
| { |
| { 1, 6, -1 }, |
| { 4, 5, -1 }, |
| { 16, 4, -1 }, |
| { 32, 5, -1 } |
| } |
| } ; |
| |
| struct { |
| struct POSIX_SECURITY head; |
| struct POSIX_ACE ace[6]; |
| } sampletry3 = |
| { |
| { 0100, 6, 0, 6, 0x3f, |
| { POSIX_VERSION, 0, 0 } |
| }, |
| { |
| { 1, 1, -1 }, |
| { 2, 3, 1000 }, |
| { 4, 1, -1 }, |
| { 8, 3, 1002 }, |
| { 16, 0, -1 }, |
| { 32, 0, -1 } |
| } |
| } ; |
| |
| struct { |
| struct POSIX_SECURITY head; |
| struct POSIX_ACE ace[8]; |
| } sampletry4 = |
| { |
| { 0140, 8, 0, 8, 0x3f, |
| { POSIX_VERSION, 0, 0 } |
| }, |
| { |
| { 1, 1, -1 }, |
| { 2, 3, 516 }, |
| { 2, 6, 1000 }, |
| { 4, 1, -1 }, |
| { 8, 6, 500 }, |
| { 8, 3, 1002 }, |
| { 16, 4, -1 }, |
| { 32, 0, -1 } |
| } |
| } ; |
| |
| struct { |
| struct POSIX_SECURITY head; |
| struct POSIX_ACE ace[6]; |
| } sampletry5 = |
| { |
| { 0454, 6, 0, 6, 0x3f, |
| { POSIX_VERSION, 0, 0 } |
| }, |
| { |
| { 1, 4, -1 }, |
| { 2, 5, 516 }, |
| { 4, 4, -1 }, |
| { 8, 6, 500 }, |
| { 16, 5, -1 }, |
| { 32, 4, -1 } |
| } |
| } ; |
| |
| struct { |
| struct POSIX_SECURITY head; |
| struct POSIX_ACE ace[8]; |
| } sampletry6 = |
| { |
| { 0332, 8, 0, 8, 0x3f, |
| { POSIX_VERSION, 0, 0 } |
| }, |
| { |
| { 1, 3, -1 }, |
| { 2, 1, 0 }, |
| { 2, 2, 1000 }, |
| { 4, 6, -1 }, |
| { 8, 4, 0 }, |
| { 8, 5, 1002 }, |
| { 16, 3, -1 }, |
| { 32, 2, -1 } |
| } |
| } ; |
| |
| struct { |
| struct POSIX_SECURITY head; |
| struct POSIX_ACE ace[4]; |
| } sampletry8 = |
| { |
| { 0677, 4, 0, 4, 0x35, |
| { POSIX_VERSION, 0, 0 } |
| }, |
| { |
| { 1, 6, -1 }, |
| { 4, 7, -1 }, |
| { 16, 7, -1 }, |
| { 32, 7, -1 } |
| } |
| } ; |
| |
| #endif /* POSIXACLS */ |
| |
| |
| #if POSIXACLS |
| for (cnt=1; cnt<=8; cnt++) { |
| switch (cnt) { |
| case 1 : |
| pxsample = &sampletry1.head; |
| txsample = "sampletry1-a"; |
| isdir = FALSE; |
| descr = ntfs_build_descr_posix(context.mapping,&sampletry1.head, |
| isdir, (const SID*)owner3, (const SID*)group3); |
| break; |
| case 2 : |
| pxsample = &sampletry1.head; |
| txsample = "sampletry1-b"; |
| isdir = FALSE; |
| descr = ntfs_build_descr_posix(context.mapping,&sampletry1.head, |
| isdir, (const SID*)adminsid, (const SID*)group3); |
| break; |
| case 3 : |
| isdir = FALSE; |
| pxsample = &sampletry3.head; |
| txsample = "sampletry3"; |
| descr = ntfs_build_descr_posix(context.mapping,pxsample, |
| isdir, (const SID*)group3, (const SID*)group3); |
| break; |
| case 4 : |
| isdir = FALSE; |
| pxsample = &sampletry4.head; |
| txsample = "sampletry4"; |
| descr = ntfs_build_descr_posix(context.mapping,pxsample, |
| isdir, (const SID*)owner3, (const SID*)group3); |
| break; |
| case 5 : |
| isdir = FALSE; |
| pxsample = &sampletry5.head; |
| txsample = "sampletry5"; |
| descr = ntfs_build_descr_posix(context.mapping,pxsample, |
| isdir, (const SID*)owner3, (const SID*)group3); |
| break; |
| case 6 : |
| isdir = FALSE; |
| pxsample = &sampletry6.head; |
| txsample = "sampletry6-a"; |
| descr = ntfs_build_descr_posix(context.mapping,pxsample, |
| isdir, (const SID*)owner3, (const SID*)group3); |
| break; |
| case 7 : |
| isdir = FALSE; |
| pxsample = &sampletry6.head; |
| txsample = "sampletry6-b"; |
| descr = ntfs_build_descr_posix(context.mapping,pxsample, |
| isdir, (const SID*)adminsid, (const SID*)adminsid); |
| break; |
| case 8 : |
| pxsample = &sampletry8.head; |
| txsample = "sampletry8"; |
| isdir = FALSE; |
| descr = ntfs_build_descr_posix(context.mapping,&sampletry8.head, |
| isdir, (const SID*)owner3, (const SID*)group3); |
| break; |
| default : |
| pxsample = (struct POSIX_SECURITY*)NULL; |
| txsample = (const char*)NULL; |
| } |
| /* check we get original back */ |
| if (descr) |
| pxdesc = linux_permissions_posix(descr, isdir); |
| else |
| pxdesc = (struct POSIX_SECURITY*)NULL; |
| if (!descr || !pxdesc || !same_posix(pxsample,pxdesc)) { |
| printf("** Error in %s\n",txsample); |
| showposix(pxsample); |
| showall(descr,0); |
| showposix(pxdesc); |
| errors++; |
| } |
| free(descr); |
| free(pxdesc); |
| } |
| |
| #endif /* POSIXACLS */ |
| |
| |
| /* |
| * Check a few samples built by Windows, |
| * which cannot be generated by Linux |
| */ |
| |
| for (cnt=1; cnt<=10; cnt++) { |
| switch(cnt) { |
| case 1 : /* hp/tmp */ |
| isdir = TRUE; |
| descr = build_dummy_descr(isdir, |
| (const SID*)owner1, (const SID*)group1, |
| 1, |
| (int)TRUE, worldsid, (int)0x3, (u32)0x1f01ff); |
| expectacc = expect = 0777; |
| expectdef = 0; |
| break; |
| case 2 : /* swsetup */ |
| isdir = TRUE; |
| descr = build_dummy_descr(isdir, adminsid, (const SID*)group2, |
| 2, |
| (int)TRUE, worldsid, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, worldsid, (int)0xb, (u32)0x1f01ff); |
| expectacc = expect = 0777; |
| expectdef = 0777; |
| break; |
| case 3 : /* Dr Watson */ |
| isdir = TRUE; |
| descr = build_dummy_descr(isdir, (const SID*)owner3, (const SID*)group3, |
| 0); |
| expectacc = expect = 0700; |
| expectdef = 0; |
| break; |
| case 4 : |
| isdir = FALSE; |
| descr = build_dummy_descr(isdir, |
| (const SID*)owner3, (const SID*)group3, |
| 4, |
| (int)TRUE, (const SID*)owner3, 0, |
| le32_to_cpu(FILE_READ_DATA | OWNER_RIGHTS), |
| (int)TRUE, (const SID*)group3, 0, |
| le32_to_cpu(FILE_WRITE_DATA), |
| (int)TRUE, (const SID*)group2, 0, |
| le32_to_cpu(FILE_WRITE_DATA | FILE_READ_DATA), |
| (int)TRUE, (const SID*)worldsid, 0, |
| le32_to_cpu(FILE_EXECUTE)); |
| expect = 0731; |
| expectacc = 07070731; |
| expectdef = 0; |
| break; |
| case 5 : /* Vista/JP */ |
| isdir = TRUE; |
| descr = build_dummy_descr(isdir, systemsid, systemsid, |
| 6, |
| (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, owner1, (int)0xb, (u32)0x10000000, |
| (int)TRUE, systemsid, (int)0xb, (u32)0x10000000, |
| (int)TRUE, adminsid, (int)0xb, (u32)0x10000000); |
| expectacc = expect = 0700; |
| expectdef = 0700; |
| break; |
| case 6 : /* Vista/JP2 */ |
| isdir = TRUE; |
| descr = build_dummy_descr(isdir, systemsid, systemsid, |
| 7, |
| (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, owner1, (int)0xb, (u32)0x1f01ff, |
| (int)TRUE, systemsid, (int)0xb, (u32)0x1f01ff, |
| (int)TRUE, adminsid, (int)0xb, (u32)0x1f01ff, |
| (int)TRUE, owner3, (int)0x3, (u32)0x1200a9); |
| expectacc = 0500070700; |
| expectdef = 0700; |
| expect = 0700; |
| break; |
| case 7 : /* WinXP/JP */ |
| isdir = TRUE; |
| descr = build_dummy_descr(isdir, adminsid, systemsid, |
| 6, |
| (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, owner1, (int)0xb, (u32)0x10000000, |
| (int)TRUE, systemsid, (int)0xb, (u32)0x10000000, |
| (int)TRUE, adminsid, (int)0xb, (u32)0x10000000); |
| expectacc = expect = 0700; |
| expectdef = 0700; |
| break; |
| case 8 : /* WinXP/JP2 */ |
| isdir = TRUE; |
| descr = build_dummy_descr(isdir, adminsid, systemsid, |
| 6, |
| (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, |
| (int)TRUE, owner1, (int)0xb, (u32)0x10000000, |
| (int)TRUE, systemsid, (int)0xb, (u32)0x10000000, |
| (int)TRUE, adminsid, (int)0xb, (u32)0x10000000); |
| expectacc = expect = 0700; |
| expectdef = 0700; |
| break; |
| case 9 : /* Win8/bin */ |
| isdir = TRUE; |
| descr = build_dummy_descr(isdir, |
| (const SID*)owner3, (const SID*)owner3, |
| 6, |
| (int)TRUE, authsid, (int)0x3, (u32)0x1f01ff, |
| (int)TRUE, adminsid, (int)0x13, (u32)0x1f01ff, |
| (int)TRUE, systemsid, (int)0x13, (u32)0x1f01ff, |
| (int)TRUE, localsid, (int)0x13, (u32)0x1200a9, |
| (int)TRUE, authsid, (int)0x10, (u32)0x1301bf, |
| (int)TRUE, authsid, (int)0x1b, (u32)0xe0010000); |
| expectacc = expect = 0777; |
| expectdef = 0777; |
| break; |
| case 10 : /* Win8/bin/linem.exe */ |
| isdir = FALSE; |
| descr = build_dummy_descr(isdir, |
| (const SID*)owner3, (const SID*)owner3, |
| 4, |
| (int)TRUE, authsid, (int)0x10, (u32)0x1f01ff, |
| (int)TRUE, adminsid, (int)0x10, (u32)0x1f01ff, |
| (int)TRUE, systemsid, (int)0x10, (u32)0x1ff, |
| (int)TRUE, localsid, (int)0x10, (u32)0x1200a9); |
| expectacc = expect = 0777; |
| expectdef = 0; |
| break; |
| default : |
| expectacc = expectdef = 0; |
| break; |
| } |
| if (descr) { |
| perms = linux_permissions(descr, isdir); |
| if (perms != expect) { |
| printf("** Error in sample %d, perms 0%03o expected 0%03o\n", |
| cnt,perms,expect); |
| showall(descr,0); |
| errors++; |
| } else { |
| #if POSIXACLS |
| pxdesc = linux_permissions_posix(descr, isdir); |
| if (pxdesc) { |
| accrights = merge_rights(pxdesc,FALSE); |
| defrights = merge_rights(pxdesc,TRUE); |
| if (!(pxdesc->tagsset & ~(POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER))) |
| mixmode = expect; |
| else |
| mixmode = (expect & 07707) | ((accrights >> 9) & 070); |
| if ((pxdesc->mode != mixmode) |
| || (accrights != expectacc) |
| || (defrights != expectdef)) { |
| printf("** Error in sample %d : mode %03o expected 0%03o\n", |
| cnt,pxdesc->mode,mixmode); |
| printf(" Posix access rights 0%03lo expected 0%03lo\n", |
| (long)accrights,(long)expectacc); |
| printf(" default rights 0%03lo expected 0%03lo\n", |
| (long)defrights,(long)expectdef); |
| showall(descr,0); |
| showposix(pxdesc); |
| exit(1); |
| } |
| free(pxdesc); |
| } |
| #endif |
| } |
| free(descr); |
| } |
| } |
| } |
| |
| |
| /* |
| * Check whether any basic permission setting is interpreted |
| * back exactly as set |
| */ |
| |
| void basictest(int kind, BOOL isdir, const SID *owner, const SID *group) |
| { |
| char *attr; |
| mode_t perm; |
| mode_t gotback; |
| u32 count; |
| u32 acecount; |
| u32 globhash; |
| const SECURITY_DESCRIPTOR_RELATIVE *phead; |
| const ACL *pacl; |
| enum { ERRNO, |
| ERRMA, ERRPA, /* error converting mode or Posix ACL to NTFS */ |
| ERRAM, ERRAP, /* error converting NTFS to mode or Posix ACL */ |
| } err; |
| u32 expectcnt[] = { |
| 27800, 31896, |
| 24064, 28160, |
| 24064, 28160, |
| 24064, 28160, |
| 24904, 29000 |
| } ; |
| u32 expecthash[] = { |
| 0x8f80865b, 0x7bc7960, |
| 0x8fd9ecfe, 0xddd4db0, |
| 0xa8b07400, 0xa189c20, |
| 0xc5689a00, 0xb6c09000, |
| 0xb040e509, 0x4f4db7f7 |
| } ; |
| #if POSIXACLS |
| struct POSIX_SECURITY *pxdesc; |
| char *pxattr; |
| u32 pxcount; |
| u32 pxacecount; |
| u32 pxglobhash; |
| #endif |
| |
| count = 0; |
| acecount = 0; |
| globhash = 0; |
| #if POSIXACLS |
| pxcount = 0; |
| pxacecount = 0; |
| pxglobhash = 0; |
| #endif |
| for (perm=0; (perm<=07777) && (errors < 10); perm++) { |
| err = ERRNO; |
| /* file owned by plain user and group */ |
| attr = ntfs_build_descr(perm,isdir,owner,(const SID*)group); |
| if (attr && ntfs_valid_descr(attr, ntfs_attr_size(attr))) { |
| phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
| pacl = (const ACL*)&attr[le32_to_cpu(phead->dacl)]; |
| acecount += le16_to_cpu(pacl->ace_count); |
| globhash += hash((const le32*)attr,ntfs_attr_size(attr)); |
| count++; |
| #if POSIXACLS |
| /* |
| * Build a NTFS ACL from a mode, and |
| * decode to a Posix ACL, expecting to |
| * get the original mode back. |
| */ |
| pxdesc = linux_permissions_posix(attr, isdir); |
| if (!pxdesc || (pxdesc->mode != perm)) { |
| err = ERRAP; |
| if (pxdesc) |
| gotback = pxdesc->mode; |
| else |
| gotback = 0; |
| } else { |
| /* |
| * Build a NTFS ACL from the Posix ACL, expecting to |
| * get exactly the same NTFS ACL, then decode to a |
| * mode, expecting to get the original mode back. |
| */ |
| pxattr = ntfs_build_descr_posix(context.mapping, |
| pxdesc,isdir,owner, |
| (const SID*)group); |
| if (pxattr && !memcmp(pxattr,attr, |
| ntfs_attr_size(attr))) { |
| phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
| pacl = (const ACL*)&attr[le32_to_cpu(phead->dacl)]; |
| pxacecount += le16_to_cpu(pacl->ace_count); |
| pxglobhash += hash((const le32*)attr,ntfs_attr_size(attr)); |
| pxcount++; |
| gotback = linux_permissions(pxattr, isdir); |
| if (gotback != perm) |
| err = ERRAM; |
| else |
| free(pxattr); |
| } else |
| err = ERRPA; |
| free(attr); |
| } |
| free(pxdesc); |
| #else |
| gotback = linux_permissions(attr, isdir); |
| if (gotback != perm) |
| err = ERRAM; |
| else |
| free(attr); |
| #endif /* POSIXACLS */ |
| } else |
| err = ERRMA; |
| |
| switch (err) { |
| case ERRMA : |
| printf("** no or wrong permission settings " |
| "for kind %d perm %03o\n",kind,perm); |
| if (attr && opt_v) |
| hexdump(attr,ntfs_attr_size(attr),8); |
| if (attr && (opt_v >= 2)) { |
| showheader(attr,4); |
| showusid(attr,4); |
| showgsid(attr,4); |
| showdacl(attr,isdir,4); |
| showsacl(attr,isdir,4); |
| } |
| errors++; |
| break; |
| case ERRPA : |
| printf("** no or wrong permission settings from PX " |
| "for kind %d perm %03o\n",kind,perm); |
| errors++; |
| break; |
| #if POSIXACLS |
| case ERRAM : |
| printf("** wrong permission settings, " |
| "kind %d perm 0%03o, gotback %03o\n", |
| kind, perm, gotback); |
| if (opt_v) |
| hexdump(pxattr,ntfs_attr_size(pxattr),8); |
| if (opt_v >= 2) { |
| showheader(pxattr,4); |
| showusid(pxattr,4); |
| showgsid(pxattr,4); |
| showdacl(pxattr,isdir,4); |
| showsacl(pxattr,isdir,4); |
| } |
| errors++; |
| break; |
| case ERRAP : |
| /* continued */ |
| #else |
| case ERRAM : |
| case ERRAP : |
| #endif /* POSIXACLS */ |
| printf("** wrong permission settings, " |
| "kind %d perm 0%03o, gotback %03o\n", |
| kind, perm, gotback); |
| if (opt_v) |
| hexdump(attr,ntfs_attr_size(attr),8); |
| if (opt_v >= 2) { |
| showheader(attr,4); |
| showusid(attr,4); |
| showgsid(attr,4); |
| showdacl(attr,isdir,4); |
| showsacl(attr,isdir,4); |
| } |
| errors++; |
| free(attr); |
| break; |
| default : |
| break; |
| } |
| } |
| printf("%lu ACLs built from mode, %lu ACE built, mean count %lu.%02lu\n", |
| (unsigned long)count,(unsigned long)acecount, |
| (unsigned long)acecount/count,acecount*100L/count%100L); |
| if (acecount != expectcnt[kind]) { |
| printf("** Error : ACE count %lu instead of %lu\n", |
| (unsigned long)acecount, |
| (unsigned long)expectcnt[kind]); |
| errors++; |
| } |
| if (globhash != expecthash[kind]) { |
| printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n", |
| (unsigned long)globhash, (unsigned long)expecthash[kind]); |
| errors++; |
| } |
| #if POSIXACLS |
| printf("%lu ACLs built from Posix ACLs, %lu ACE built, mean count %lu.%02lu\n", |
| (unsigned long)pxcount,(unsigned long)pxacecount, |
| (unsigned long)pxacecount/pxcount,pxacecount*100L/pxcount%100L); |
| if (pxacecount != expectcnt[kind]) { |
| printf("** Error : ACE count %lu instead of %lu\n", |
| (unsigned long)pxacecount, |
| (unsigned long)expectcnt[kind]); |
| errors++; |
| } |
| if (pxglobhash != expecthash[kind]) { |
| printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n", |
| (unsigned long)pxglobhash, (unsigned long)expecthash[kind]); |
| errors++; |
| } |
| #endif /* POSIXACLS */ |
| } |
| |
| #if POSIXACLS |
| |
| /* |
| * Check whether Posix ACL settings are interpreted |
| * back exactly as set |
| */ |
| |
| void posixtest(int kind, BOOL isdir, |
| const SID *owner, const SID *group) |
| { |
| struct POSIX_SECURITY *pxdesc; |
| struct { |
| struct POSIX_SECURITY pxdesc; |
| struct POSIX_ACE aces[10]; |
| } desc; |
| int ownobj; |
| int grpobj; |
| int usr; |
| int grp; |
| int wrld; |
| int mask; |
| int mindes, maxdes; |
| int minmsk, maxmsk; |
| char *pxattr; |
| u32 count; |
| u32 acecount; |
| u32 globhash; |
| const SECURITY_DESCRIPTOR_RELATIVE *phead; |
| const ACL *pacl; |
| struct POSIX_SECURITY *gotback; |
| enum { ERRNO, |
| ERRMA, ERRPA, /* error converting mode or Posix ACL to NTFS */ |
| ERRAM, ERRAP, /* error converting NTFS to mode or Posix ACL */ |
| } err; |
| u32 expectcnt[] = { |
| #ifdef STSC |
| 32400, 34992, |
| 25920, 28512, |
| 25920, 28512, |
| 25920, 28512, |
| 26460, 29052, |
| 0, 0, |
| 0, 0, |
| 0, 0, |
| 24516, 27108, |
| 20736, 23328, |
| 20736, 23328, |
| 20736, 23328, |
| 21060, 23652, |
| #else |
| 252720, 273456, |
| 199584, 220320, |
| 199584, 220320, |
| 199584, 220320, |
| 203904, 224640, |
| 0, 0, |
| 0, 0, |
| 0, 0, |
| 196452, 217188, |
| 165888, 186624, |
| 165888, 186624, |
| 165888, 186624, |
| 168480, 189216, |
| #endif |
| 0, 0, |
| 0, 0, |
| 0, 0, |
| 16368, 18672, |
| 0, 0, |
| 13824, 0, |
| 0, 0, |
| 14640, 0 |
| } ; |
| u32 expecthash[] = { |
| #ifdef STSC |
| 0xf9f82115, 0x40666647, |
| 0xde826d30, 0xa181b660, |
| 0x952d4500, 0x8ac49450, |
| 0xf80acee0, 0xbd9ec6c0, |
| 0xfe09b868, 0xde24e84d, |
| 0, 0, |
| 0, 0, |
| 0, 0, |
| 0x2381438d, 0x3ab42dc6, |
| 0x7cccf6f8, 0x108ad430, |
| 0x5e448840, 0x83ab6c40, |
| 0x9b037100, 0x8f7c3b40, |
| 0x04a359dc, 0xa4619609, |
| #else |
| 0x1808a6cd, 0xd82f7c60, |
| 0x5ad29e85, 0x518c7620, |
| 0x188ce270, 0x7e44e590, |
| 0x48a64800, 0x5bdf0030, |
| 0x1c64aec6, 0x8b0168fa, |
| 0, 0, |
| 0, 0, |
| 0, 0, |
| 0x169fb80e, 0x382d9a59, |
| 0xf9c28164, 0x1855d352, |
| 0xf9685700, 0x44d16700, |
| 0x587ebe90, 0xf7c51480, |
| 0x2cb1b518, 0x52408df6, |
| #endif |
| 0, 0, |
| 0, 0, |
| 0, 0, |
| 0x905f2e38, 0xd40c22f0, |
| 0, 0, |
| 0xdd76da00, 0, |
| 0, 0, |
| 0x718e34a0, 0 |
| }; |
| |
| count = 0; |
| acecount = 0; |
| globhash = 0; |
| /* fill headers */ |
| pxdesc = &desc.pxdesc; |
| pxdesc->mode = 0; |
| pxdesc->defcnt = 0; |
| if (kind & 32) { |
| pxdesc->acccnt = 4; |
| pxdesc->firstdef = 4; |
| pxdesc->tagsset = 0x35; |
| } else { |
| pxdesc->acccnt = 6;; |
| pxdesc->firstdef = 6; |
| pxdesc->tagsset = 0x3f; |
| } |
| pxdesc->acl.version = POSIX_VERSION; |
| pxdesc->acl.flags = 0; |
| pxdesc->acl.filler = 0; |
| /* prefill aces */ |
| pxdesc->acl.ace[0].tag = POSIX_ACL_USER_OBJ; |
| pxdesc->acl.ace[0].id = -1; |
| if (kind & 32) { |
| pxdesc->acl.ace[1].tag = POSIX_ACL_GROUP_OBJ; |
| pxdesc->acl.ace[1].id = -1; |
| pxdesc->acl.ace[2].tag = POSIX_ACL_MASK; |
| pxdesc->acl.ace[2].id = -1; |
| pxdesc->acl.ace[3].tag = POSIX_ACL_OTHER; |
| pxdesc->acl.ace[3].id = -1; |
| } else { |
| pxdesc->acl.ace[1].tag = POSIX_ACL_USER; |
| pxdesc->acl.ace[1].id = (kind & 16 ? 0 : 1000); |
| pxdesc->acl.ace[2].tag = POSIX_ACL_GROUP_OBJ; |
| pxdesc->acl.ace[2].id = -1; |
| pxdesc->acl.ace[3].tag = POSIX_ACL_GROUP; |
| pxdesc->acl.ace[3].id = (kind & 16 ? 0 : 1002); |
| pxdesc->acl.ace[4].tag = POSIX_ACL_MASK; |
| pxdesc->acl.ace[4].id = -1; |
| pxdesc->acl.ace[5].tag = POSIX_ACL_OTHER; |
| pxdesc->acl.ace[5].id = -1; |
| } |
| |
| mindes = 3; |
| maxdes = (kind & 32 ? mindes : 6); |
| #ifdef STSC |
| minmsk = (kind & 32 ? 0 : 3); |
| maxmsk = (kind & 32 ? 7 : 3); |
| #else |
| minmsk = 0; |
| maxmsk = 7; |
| #endif |
| for (mask=minmsk; mask<=maxmsk; mask++) |
| for (ownobj=1; ownobj<7; ownobj++) |
| for (grpobj=1; grpobj<7; grpobj++) |
| for (wrld=0; wrld<8; wrld++) |
| for (usr=mindes; usr<=maxdes; usr++) |
| if (usr != 4) |
| for (grp=mindes; grp<=maxdes; grp++) |
| if (grp != 4) { |
| pxdesc->mode = (ownobj << 6) | (mask << 3) | wrld; |
| |
| pxdesc->acl.ace[0].perms = ownobj; |
| if (kind & 32) { |
| pxdesc->acl.ace[1].perms = grpobj; |
| pxdesc->acl.ace[2].perms = mask; |
| pxdesc->acl.ace[3].perms = wrld; |
| } else { |
| pxdesc->acl.ace[1].perms = usr; |
| pxdesc->acl.ace[2].perms = grpobj; |
| pxdesc->acl.ace[3].perms = grp; |
| pxdesc->acl.ace[4].perms = mask; |
| pxdesc->acl.ace[5].perms = wrld; |
| } |
| |
| err = ERRNO; |
| gotback = (struct POSIX_SECURITY*)NULL; |
| pxattr = ntfs_build_descr_posix(context.mapping, |
| pxdesc,isdir,owner,group); |
| if (pxattr && ntfs_valid_descr(pxattr, ntfs_attr_size(pxattr))) { |
| phead = (const SECURITY_DESCRIPTOR_RELATIVE*)pxattr; |
| pacl = (const ACL*)&pxattr[le32_to_cpu(phead->dacl)]; |
| acecount += le16_to_cpu(pacl->ace_count); |
| globhash += hash((const le32*)pxattr,ntfs_attr_size(pxattr)); |
| count++; |
| gotback = linux_permissions_posix(pxattr, isdir); |
| if (gotback) { |
| if (ntfs_valid_posix(gotback)) { |
| if (!same_posix(pxdesc,gotback)) { |
| printf("Non matching got back Posix ACL\n"); |
| printf("input ACL\n"); |
| showposix(pxdesc); |
| printf("NTFS owner\n"); |
| showusid(pxattr,4); |
| printf("NTFS group\n"); |
| showgsid(pxattr,4); |
| printf("NTFS DACL\n"); |
| showdacl(pxattr,isdir,4); |
| printf("gotback ACL\n"); |
| showposix(gotback); |
| errors++; |
| exit(1); |
| } |
| } else { |
| printf("Got back an invalid Posix ACL\n"); |
| errors++; |
| } |
| free(gotback); |
| } else { |
| printf("Could not get Posix ACL back\n"); |
| errors++; |
| } |
| |
| } else { |
| printf("NTFS ACL incorrect or not build\n"); |
| printf("input ACL\n"); |
| showposix(pxdesc); |
| printf("NTFS DACL\n"); |
| if (pxattr) |
| showdacl(pxattr,isdir,4); |
| else |
| printf(" (none)\n"); |
| if (gotback) { |
| printf("gotback ACL\n"); |
| showposix(gotback); |
| } else |
| printf("no gotback ACL\n"); |
| errors++; |
| } |
| if (pxattr) |
| free(pxattr); |
| } |
| printf("%lu ACLs built from Posix ACLs, %lu ACE built, mean count %lu.%02lu\n", |
| (unsigned long)count,(unsigned long)acecount, |
| (unsigned long)acecount/count,acecount*100L/count%100L); |
| if (acecount != expectcnt[kind]) { |
| printf("** Error ! expected ACE count %lu\n", |
| (unsigned long)expectcnt[kind]); |
| errors++; |
| } |
| if (globhash != expecthash[kind]) { |
| printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n", |
| (unsigned long)globhash, (unsigned long)expecthash[kind]); |
| errors++; |
| } |
| } |
| |
| #endif /* POSIXACLS */ |
| |
| void selftests(void) |
| { |
| le32 owner_sid[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ |
| { |
| const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), |
| const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), |
| const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), |
| const_cpu_to_le32(1016) |
| } ; |
| le32 group_sid[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ |
| { |
| const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), |
| const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), |
| const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), |
| const_cpu_to_le32(513) |
| } ; |
| #if POSIXACLS |
| #ifdef STSC |
| unsigned char kindlist[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
| 16, 17, 18, 20, 22, 24, |
| 32, 33, 36, 40 } ; |
| #else |
| unsigned char kindlist[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
| 16, 17, 18, 20, 22, 24, 19, 21, 23, 25, |
| 32, 33, 36, 40 } ; |
| #endif |
| unsigned int k; |
| #endif /* POSIXACLS */ |
| int kind; |
| const SID *owner; |
| const SID *group; |
| BOOL isdir; |
| |
| #if POSIXACLS |
| local_build_mapping(context.mapping, (const char*)NULL); |
| #endif |
| /* first check samples */ |
| mappingtype = MAPDUMMY; |
| check_samples(); |
| if (errors) exit(1); |
| /* |
| * kind is oring of : |
| * 1 : directory |
| * 2 : owner is root |
| * 4 : group is root |
| * 8 : group is owner |
| * 16 : root is designated user/group |
| * 32 : mask present with no designated user/group |
| */ |
| for (kind=0; (kind<10) && (errors<10); kind++) { |
| isdir = kind & 1; |
| if (kind & 8) |
| owner = (const SID*)group_sid; |
| else |
| owner = (kind & 2 ? adminsid : (const SID*)owner_sid); |
| group = (kind & 4 ? adminsid : (const SID*)group_sid); |
| basictest(kind, isdir, owner, group); |
| } |
| #if POSIXACLS |
| for (k=0; (k<sizeof(kindlist)) && (errors<10); k++) { |
| kind = kindlist[k]; |
| isdir = kind & 1; |
| if (kind & 8) |
| owner = (const SID*)group_sid; |
| else |
| owner = (kind & 2 ? adminsid : (const SID*)owner_sid); |
| group = (kind & 4 ? adminsid : (const SID*)group_sid); |
| posixtest(kind, isdir, owner, group); |
| } |
| ntfs_free_mapping(context.mapping); |
| #endif |
| if (errors >= 10) |
| printf("** too many errors, test aborted\n"); |
| } |
| #endif /* SELFTESTS & !USESTUBS */ |
| |
| #ifdef WIN32 |
| |
| /* |
| * Get the security descriptor of a file (Windows version) |
| */ |
| |
| unsigned int getfull(char *attr, const char *fullname) |
| { |
| static char part[MAXATTRSZ]; |
| BIGSID ownsid; |
| int xowner; |
| int ownersz; |
| u16 ownerfl; |
| ULONG attrsz; |
| ULONG partsz; |
| BOOL overflow; |
| HANDLE htoken; |
| TOKEN_PRIVILEGES tkp; |
| BOOL saclsuccess; |
| |
| attrsz = 0; |
| partsz = 0; |
| overflow = FALSE; |
| if (GetFileSecurityW((LPCWSTR)fullname,OWNER_SECURITY_INFORMATION, |
| (char*)part,MAXATTRSZ,&partsz)) { |
| xowner = get4l(part,4); |
| if (xowner) { |
| ownerfl = get2l(part,2); |
| ownersz = ntfs_sid_size((SID*)&part[xowner]); |
| if (ownersz <= (int)sizeof(BIGSID)) |
| memcpy(ownsid,&part[xowner],ownersz); |
| else |
| overflow = TRUE; |
| } else { |
| ownerfl = 0; |
| ownersz = 0; |
| } |
| /* |
| * SACL : just feed in or clean |
| * This requires the SE_SECURITY_NAME privilege |
| */ |
| saclsuccess = FALSE; |
| if (OpenProcessToken(GetCurrentProcess(), |
| TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &htoken)) { |
| if (LookupPrivilegeValue(NULL, SE_SECURITY_NAME, |
| &tkp.Privileges[0].Luid)) { |
| tkp.PrivilegeCount = 1; |
| tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; |
| if (AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0)) { |
| if (GetFileSecurityW((LPCWSTR)fullname, |
| SACL_SECURITY_INFORMATION, |
| (char*)attr,MAXATTRSZ,&attrsz)) { |
| saclsuccess = TRUE; |
| } |
| tkp.Privileges[0].Attributes = 0; |
| AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0); |
| } |
| } |
| } |
| if (!saclsuccess) { |
| attrsz = 20; |
| set4l(attr,0); |
| attr[0] = SECURITY_DESCRIPTOR_REVISION; |
| set4l(&attr[12],0); |
| if (opt_v >= 2) |
| printf(" No SACL\n"); |
| } |
| /* |
| * append DACL and merge its flags |
| */ |
| partsz = 0; |
| set4l(&attr[16],0); |
| if (GetFileSecurityW((LPCWSTR)fullname,DACL_SECURITY_INFORMATION, |
| (char*)part,MAXATTRSZ,&partsz)) { |
| if ((attrsz + partsz - 20) <= MAXATTRSZ) { |
| memcpy(&attr[attrsz],&part[20],partsz-20); |
| set4l(&attr[16],(partsz > 20 ? attrsz : 0)); |
| set2l(&attr[2],get2l(attr,2) | (get2l(part,2) |
| & const_le16_to_cpu(SE_DACL_PROTECTED |
| | SE_DACL_AUTO_INHERITED |
| | SE_DACL_PRESENT))); |
| attrsz += partsz - 20; |
| } else |
| overflow = TRUE; |
| } else |
| if (partsz > MAXATTRSZ) |
| overflow = TRUE; |
| else { |
| if (opt_b) |
| printf("# No discretionary access control list\n"); |
| else |
| printf(" No discretionary access control list\n"); |
| warnings++; |
| } |
| |
| /* |
| * append owner and merge its flag |
| */ |
| if (xowner && !overflow) { |
| memcpy(&attr[attrsz],ownsid,ownersz); |
| set4l(&attr[4],attrsz); |
| set2l(&attr[2],get2l(attr,2) |
| | (ownerfl & const_le16_to_cpu(SE_OWNER_DEFAULTED))); |
| attrsz += ownersz; |
| } else |
| set4l(&attr[4],0); |
| /* |
| * append group |
| */ |
| partsz = 0; |
| set4l(&attr[8],0); |
| if (GetFileSecurityW((LPCWSTR)fullname,GROUP_SECURITY_INFORMATION, |
| (char*)part,MAXATTRSZ,&partsz)) { |
| if ((attrsz + partsz - 20) <= MAXATTRSZ) { |
| memcpy(&attr[attrsz],&part[20],partsz-20); |
| set4l(&attr[8],(partsz > 20 ? attrsz : 0)); |
| set2l(&attr[2],get2l(attr,2) | (get2l(part,2) |
| & const_le16_to_cpu(SE_GROUP_DEFAULTED))); |
| attrsz += partsz - 20; |
| } else |
| overflow = TRUE; |
| } else |
| if (partsz > MAXATTRSZ) |
| overflow = TRUE; |
| else { |
| printf("** No group SID\n"); |
| warnings++; |
| } |
| set2l(&attr[2],get2l(attr,2) |
| | const_le16_to_cpu(SE_SELF_RELATIVE)); |
| if (overflow) { |
| printf("** Descriptor was too long (> %d)\n",MAXATTRSZ); |
| warnings++; |
| attrsz = 0; |
| } else |
| if (!ntfs_valid_descr((char*)attr,attrsz)) { |
| printf("** Descriptor for "); |
| printname(stdout,fullname); |
| printf(" is not valid\n"); |
| errors++; |
| attrsz = 0; |
| } |
| |
| } else { |
| printf("** Could not get owner of "); |
| printname(stdout,fullname); |
| printf(", partsz %d\n",partsz); |
| printerror(stdout); |
| warnings++; |
| attrsz = 0; |
| } |
| return (attrsz); |
| } |
| |
| /* |
| * Update a security descriptor (Windows version) |
| */ |
| |
| BOOL updatefull(const char *name, DWORD flags, char *attr) |
| { |
| BOOL bad; |
| |
| bad = !SetFileSecurityW((LPCWSTR)name, flags, attr); |
| if (bad |
| && (flags & OWNER_SECURITY_INFORMATION) |
| && (GetLastError() == 1307)) { |
| printf("** Could not set owner of "); |
| printname(stdout,name); |
| printf(", retrying with no owner setting\n"); |
| warnings++; |
| bad = !SetFileSecurityW((LPCWSTR)name, |
| flags & ~OWNER_SECURITY_INFORMATION, (char*)attr); |
| } |
| if (bad) { |
| printf("** Could not change attributes of "); |
| printname(stdout,name); |
| printf("\n"); |
| printerror(stdout); |
| errors++; |
| } |
| return (!bad); |
| } |
| |
| #else |
| |
| /* |
| * Get the security descriptor of a file (Linux version) |
| */ |
| |
| unsigned int getfull(char *attr, const char *fullname) |
| { |
| static char part[MAXATTRSZ]; |
| BIGSID ownsid; |
| int xowner; |
| int ownersz; |
| u16 ownerfl; |
| u32 attrsz; |
| u32 partsz; |
| BOOL overflow; |
| |
| attrsz = 0; |
| partsz = 0; |
| overflow = FALSE; |
| if (ntfs_get_file_security(ntfs_context,fullname, |
| OWNER_SECURITY_INFORMATION, |
| (char*)part,MAXATTRSZ,&partsz)) { |
| xowner = get4l(part,4); |
| if (xowner) { |
| ownerfl = get2l(part,2); |
| ownersz = ntfs_sid_size((SID*)&part[xowner]); |
| if (ownersz <= (int)sizeof(BIGSID)) |
| memcpy(ownsid,&part[xowner],ownersz); |
| else |
| overflow = TRUE; |
| } else { |
| ownerfl = 0; |
| ownersz = 0; |
| } |
| /* |
| * SACL : just feed in or clean |
| */ |
| if (!ntfs_get_file_security(ntfs_context,fullname, |
| SACL_SECURITY_INFORMATION, |
| (char*)attr,MAXATTRSZ,&attrsz)) { |
| attrsz = 20; |
| set4l(attr,0); |
| attr[0] = SECURITY_DESCRIPTOR_REVISION; |
| set4l(&attr[12],0); |
| if (opt_v >= 2) |
| printf(" No SACL\n"); |
| } |
| /* |
| * append DACL and merge its flags |
| */ |
| partsz = 0; |
| set4l(&attr[16],0); |
| if (ntfs_get_file_security(ntfs_context,fullname, |
| DACL_SECURITY_INFORMATION, |
| (char*)part,MAXATTRSZ,&partsz)) { |
| if ((attrsz + partsz - 20) <= MAXATTRSZ) { |
| memcpy(&attr[attrsz],&part[20],partsz-20); |
| set4l(&attr[16],(partsz > 20 ? attrsz : 0)); |
| set2l(&attr[2],get2l(attr,2) | (get2l(part,2) |
| & const_le16_to_cpu(SE_DACL_PROTECTED |
| | SE_DACL_AUTO_INHERITED |
| | SE_DACL_PRESENT))); |
| attrsz += partsz - 20; |
| } else |
| overflow = TRUE; |
| } else |
| if (partsz > MAXATTRSZ) |
| overflow = TRUE; |
| else { |
| if (opt_b) |
| printf("# No discretionary access control list\n"); |
| else |
| printf(" No discretionary access control list\n"); |
| warnings++; |
| } |
| |
| /* |
| * append owner and merge its flag |
| */ |
| if (xowner && !overflow) { |
| memcpy(&attr[attrsz],ownsid,ownersz); |
| set4l(&attr[4],attrsz); |
| set2l(&attr[2],get2l(attr,2) |
| | (ownerfl & const_le16_to_cpu(SE_OWNER_DEFAULTED))); |
| attrsz += ownersz; |
| } else |
| set4l(&attr[4],0); |
| /* |
| * append group |
| */ |
| partsz = 0; |
| set4l(&attr[8],0); |
| if (ntfs_get_file_security(ntfs_context,fullname, |
| GROUP_SECURITY_INFORMATION, |
| (char*)part,MAXATTRSZ,&partsz)) { |
| if ((attrsz + partsz - 20) <= MAXATTRSZ) { |
| memcpy(&attr[attrsz],&part[20],partsz-20); |
| set4l(&attr[8],(partsz > 20 ? attrsz : 0)); |
| set2l(&attr[2],get2l(attr,2) | (get2l(part,2) |
| & const_le16_to_cpu(SE_GROUP_DEFAULTED))); |
| attrsz += partsz - 20; |
| } else |
| overflow = TRUE; |
| } else |
| if (partsz > MAXATTRSZ) |
| overflow = TRUE; |
| else { |
| printf("** No group SID\n"); |
| warnings++; |
| } |
| if (overflow) { |
| printf("** Descriptor was too long (> %d)\n",MAXATTRSZ); |
| warnings++; |
| attrsz = 0; |
| } else |
| if (!ntfs_valid_descr((char*)attr,attrsz)) { |
| printf("** Descriptor for %s is not valid\n",fullname); |
| errors++; |
| attrsz = 0; |
| } |
| |
| } else { |
| printf("** Could not get owner of %s\n",fullname); |
| warnings++; |
| attrsz = 0; |
| } |
| return (attrsz); |
| } |
| |
| /* |
| * Update a security descriptor (Linux version) |
| */ |
| |
| BOOL updatefull(const char *name, DWORD flags, char *attr) |
| { |
| BOOL ok; |
| |
| ok = !ntfs_set_file_security(ntfs_context, name, flags, attr); |
| if (ok) { |
| printf("** Could not change attributes of %s\n",name); |
| printerror(stdout); |
| errors++; |
| } |
| return (ok); |
| } |
| |
| |
| #endif |
| |
| #if POSIXACLS |
| |
| /* |
| * Set all the parameters associated to a file |
| */ |
| |
| BOOL setfull_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc, |
| BOOL isdir) |
| { |
| static char attr[MAXATTRSZ]; |
| struct POSIX_SECURITY *oldpxdesc; |
| struct POSIX_SECURITY *newpxdesc; |
| const SECURITY_DESCRIPTOR_RELATIVE *phead; |
| char *newattr; |
| int err; |
| unsigned int attrsz; |
| int newattrsz; |
| const SID *usid; |
| const SID *gsid; |
| #if OWNERFROMACL |
| const SID *osid; |
| #endif |
| |
| printf("%s ",(isdir ? "Directory" : "File")); |
| printname(stdout,fullname); |
| if (pxdesc->acccnt) |
| printf("\n"); |
| else |
| printf(" mode 0%03o\n",pxdesc->mode); |
| |
| err = FALSE; |
| attrsz = getfull(attr, fullname); |
| if (attrsz) { |
| oldpxdesc = linux_permissions_posix(attr, isdir); |
| if (opt_v >= 2) { |
| printf("Posix equivalent of old ACL :\n"); |
| showposix(oldpxdesc); |
| } |
| if (oldpxdesc) { |
| if (!pxdesc->defcnt |
| && !(pxdesc->tagsset & |
| (POSIX_ACL_USER | POSIX_ACL_GROUP | POSIX_ACL_MASK))) { |
| if (!ntfs_merge_mode_posix(oldpxdesc,pxdesc->mode)) |
| newpxdesc = oldpxdesc; |
| else { |
| newpxdesc = (struct POSIX_SECURITY*)NULL; |
| free(oldpxdesc); |
| } |
| } else { |
| newpxdesc = ntfs_merge_descr_posix(pxdesc, oldpxdesc); |
| free(oldpxdesc); |
| } |
| if (opt_v) { |
| printf("New Posix ACL :\n"); |
| showposix(newpxdesc); |
| } |
| } else |
| newpxdesc = (struct POSIX_SECURITY*)NULL; |
| if (newpxdesc) { |
| phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
| gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; |
| #if OWNERFROMACL |
| osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
| usid = ntfs_acl_owner((const char*)attr); |
| if (!ntfs_same_sid(usid,osid)) |
| printf("== Windows owner might change\n"); |
| #else |
| usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
| #endif |
| newattr = ntfs_build_descr_posix(context.mapping, |
| newpxdesc,isdir,usid,gsid); |
| free(newpxdesc); |
| } else |
| newattr = (char*)NULL; |
| if (newattr) { |
| newattrsz = ntfs_attr_size(newattr); |
| if (opt_v) { |
| printf("New NTFS security descriptor\n"); |
| hexdump(newattr,newattrsz,4); |
| } |
| if (opt_v >= 2) { |
| printf("Expected hash : 0x%08lx\n", |
| (unsigned long)hash((le32*)newattr,ntfs_attr_size(newattr))); |
| showheader(newattr,0); |
| showusid(newattr,0); |
| showgsid(newattr,0); |
| showdacl(newattr,isdir,0); |
| showsacl(newattr,isdir,0); |
| } |
| |
| #ifdef WIN32 |
| /* |
| * avoid getting a set owner error on Windows |
| * owner should not be changed anyway |
| */ |
| if (!updatefull(fullname, |
| DACL_SECURITY_INFORMATION |
| | GROUP_SECURITY_INFORMATION |
| | OWNER_SECURITY_INFORMATION, |
| newattr)) |
| #else |
| if (!updatefull(fullname, |
| DACL_SECURITY_INFORMATION |
| | GROUP_SECURITY_INFORMATION |
| | OWNER_SECURITY_INFORMATION, |
| newattr)) |
| #endif |
| err = TRUE; |
| /* |
| { |
| struct POSIX_SECURITY *interp; |
| printf("Reinterpreted new Posix :\n"); |
| interp = linux_permissions_posix(newattr,isdir); |
| showposix(interp); |
| free(interp); |
| } |
| */ |
| free(newattr); |
| } else |
| err = TRUE; |
| } else |
| err = TRUE; |
| return (!err); |
| } |
| |
| #endif |
| |
| BOOL setfull(const char *fullname, int mode, BOOL isdir) |
| { |
| static char attr[MAXATTRSZ]; |
| const SECURITY_DESCRIPTOR_RELATIVE *phead; |
| char *newattr; |
| int err; |
| unsigned int attrsz; |
| int newattrsz; |
| const SID *usid; |
| const SID *gsid; |
| #if OWNERFROMACL |
| const SID *osid; |
| #endif |
| |
| printf("%s ",(isdir ? "Directory" : "File")); |
| printname(stdout,fullname); |
| printf(" mode 0%03o\n",mode); |
| attrsz = getfull(attr, fullname); |
| err = FALSE; |
| if (attrsz) { |
| phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; |
| gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; |
| #if OWNERFROMACL |
| osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
| usid = ntfs_acl_owner((const char*)attr); |
| if (!ntfs_same_sid(usid,osid)) |
| printf("== Windows owner might change\n"); |
| #else |
| usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; |
| #endif |
| newattr = ntfs_build_descr(mode,isdir,usid,gsid); |
| if (newattr) { |
| newattrsz = ntfs_attr_size(newattr); |
| if (opt_v) { |
| printf("Security descriptor\n"); |
| hexdump(newattr,newattrsz,4); |
| } |
| if (opt_v >= 2) { |
| printf("Expected hash : 0x%08lx\n", |
| (unsigned long)hash((le32*)newattr,ntfs_attr_size(newattr))); |
| showheader(newattr,0); |
| showusid(newattr,0); |
| showgsid(newattr,0); |
| showdacl(newattr,isdir,0); |
| showsacl(newattr,isdir,0); |
| } |
| |
| #ifdef WIN32 |
| /* |
| * avoid getting a set owner error on Windows |
| * owner should not be changed anyway |
| */ |
| if (!updatefull(fullname, |
| DACL_SECURITY_INFORMATION |
| | GROUP_SECURITY_INFORMATION |
| | OWNER_SECURITY_INFORMATION, |
| newattr)) |
| #else |
| if (!updatefull(fullname, |
| DACL_SECURITY_INFORMATION |
| | GROUP_SECURITY_INFORMATION |
| | OWNER_SECURITY_INFORMATION, |
| newattr)) |
| #endif |
| err = TRUE; |
| free(newattr); |
| } |
| |
| } else |
| err = TRUE; |
| return (err); |
| } |
| |
| BOOL proposal(const char *name, const char *attr) |
| { |
| char fullname[MAXFILENAME]; |
| int uoff, goff; |
| int i; |
| u64 uauth, gauth; |
| int ucnt, gcnt; |
| int uid, gid; |
| BOOL err; |
| #ifdef WIN32 |
| char driveletter; |
| #else |
| struct stat st; |
| char *p,*q; |
| #endif |
| |
| err = FALSE; |
| #ifdef WIN32 |
| uid = gid = 0; |
| #else |
| uid = getuid(); |
| gid = getgid(); |
| #endif |
| uoff = get4l(attr,4); |
| uauth = get6h(attr,uoff+2); |
| ucnt = attr[uoff+1] & 255; |
| goff = get4l(attr,8); |
| gauth = get6h(attr,goff+2); |
| gcnt = attr[goff+1] & 255; |
| |
| if ((ucnt == 5) && (gcnt == 5) |
| && (uauth == 5) && (gauth == 5) |
| && (get4l(attr,uoff+8) == 21) && (get4l(attr,goff+8) == 21)) { |
| printf("# User mapping proposal :\n"); |
| printf("# -------------------- cut here -------------------\n"); |
| if (uid) |
| printf("%d::",uid); |
| else |
| printf("user::"); |
| printf("S-%d-%llu",attr[uoff] & 255,uauth); |
| for (i=0; i<ucnt; i++) |
| printf("-%lu",get4l(attr,uoff+8+4*i)); |
| printf("\n"); |
| if (gid) |
| printf(":%d:",gid); |
| else |
| printf(":group:"); |
| printf("S-%d-%llu",attr[goff] & 255,gauth); |
| for (i=0; i<gcnt; i++) |
| printf("-%lu",get4l(attr,goff+8+4*i)); |
| printf("\n"); |
| /* generic rule, based on group */ |
| printf("::S-%d-%llu",attr[goff] & 255,gauth); |
| for (i=0; i<gcnt-1; i++) |
| printf("-%lu",get4l(attr,goff+8+4*i)); |
| printf("-10000\n"); |
| printf("# -------------------- cut here -------------------\n"); |
| if (!uid || !gid) { |
| printf("# Please replace \"user\" and \"group\" above by the uid\n"); |
| printf("# and gid of the Linux owner and group of "); |
| printname(stdout,name); |
| printf(", then\n"); |
| printf("# insert the modified lines into .NTFS-3G/UserMapping, with .NTFS-3G\n"); |
| } else |
| printf("# Insert the above lines into .NTFS-3G/UserMapping, with .NTFS-3G\n"); |
| #ifdef WIN32 |
| printf("# being a directory of the root of the NTFS file system.\n"); |
| |
| /* Get the drive letter to the file system */ |
| driveletter = 0; |
| if ((((name[0] >= 'a') && (name[0] <= 'z')) |
| || ((name[0] >= 'A') && (name[0] <= 'Z'))) |
| && (name[1] == ':')) |
| driveletter = name[0]; |
| else { |
| if (GetCurrentDirectoryA(MAXFILENAME, fullname) |
| && (fullname[1] == ':')) |
| driveletter = fullname[0]; |
| } |
| if (driveletter) { |
| printf("# Example : %c:\\.NTFS-3G\\UserMapping\n", |
| driveletter); |
| } |
| #else |
| printf("# being a hidden subdirectory of the root of the NTFS file system.\n"); |
| |
| /* Get the path to the root of the file system */ |
| if (name[0] != '/') { |
| p = getcwd(fullname,MAXFILENAME); |
| if (p) { |
| strcat(fullname,"/"); |
| strcat(fullname,name); |
| } |
| } else { |
| strcpy(fullname,name); |
| p = fullname; |
| } |
| if (p) { |
| /* go down the path to inode 5 (fails on symlinks) */ |
| do { |
| lstat(fullname,&st); |
| q = strrchr(p,'/'); |
| if (q && (st.st_ino != 5)) |
| *q = 0; |
| } while (strchr(p,'/') && (st.st_ino != 5)); |
| } |
| if (p && (st.st_ino == 5)) { |
| printf("# Example : "); |
| printname(stdout,p); |
| printf("/.NTFS-3G/UserMapping\n"); |
| } |
| #endif |
| } else { |
| printf("** Not possible : "); |
| printname(stdout,name); |
| printf(" was not created by a Windows user\n"); |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| #ifdef WIN32 |
| |
| /* |
| * Check whether a directory with reparse data is a junction |
| * or a symbolic link |
| */ |
| |
| BOOL islink(const char *filename) |
| { |
| WIN32_FIND_DATAW found; |
| HANDLE search; |
| BOOL link; |
| |
| link = FALSE; |
| search = FindFirstFileW((LPCWSTR)filename, &found); |
| if (search != INVALID_HANDLE_VALUE) { |
| link = (found.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) |
| || (found.dwReserved0 == IO_REPARSE_TAG_SYMLINK); |
| FindClose(search); |
| } |
| return (link); |
| } |
| |
| #if POSIXACLS |
| BOOL iterate(RECURSE call, const char *fullname, const struct POSIX_SECURITY *pxdesc) |
| #else |
| BOOL iterate(RECURSE call, const char *fullname, mode_t mode) |
| #endif |
| { |
| WIN32_FIND_DATAW found; |
| HANDLE search; |
| BOOL err; |
| unsigned int len; |
| char *filter; |
| char *inner; |
| |
| err = FALSE; |
| filter = (char*)malloc(MAXFILENAME); |
| inner = (char*)malloc(MAXFILENAME); |
| if (filter && inner) { |
| len = utf16len(fullname); |
| memcpy(filter, fullname, 2*len); |
| makeutf16(&filter[2*len],"\\*.*"); |
| search = FindFirstFileW((LPCWSTR)filter, &found); |
| if (search != INVALID_HANDLE_VALUE) { |
| do { |
| if (found.cFileName[0] != UNICODE('.')) { |
| memcpy(inner, fullname, 2*len); |
| inner[2*len] = '\\'; |
| inner[2*len+1] = 0; |
| memcpy(&inner[2*len+2],found.cFileName, |
| 2*utf16len((char*)found.cFileName)+2); |
| if (opt_v) |
| if (opt_b) |
| printf("#\n#\n"); |
| else |
| printf("\n\n"); |
| switch (call) { |
| case RECSHOW : |
| if (recurseshow(inner)) |
| err = TRUE; |
| break; |
| #if POSIXACLS |
| case RECSETPOSIX : |
| if (recurseset_posix(inner,pxdesc)) |
| err = TRUE; |
| break; |
| #else |
| case RECSET : |
| if (recurseset(inner,mode)) |
| err = TRUE; |
| break; |
| #endif |
| default : |
| err = TRUE; |
| } |
| } |
| } while (FindNextFileW(search, &found)); |
| FindClose(search); |
| } |
| free(filter); |
| free(inner); |
| } else { |
| printf("** Cannot process deeper : not enough memory\n"); |
| errors++; |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| |
| |
| /* |
| * Display all the parameters associated to a file (Windows version) |
| */ |
| |
| void showfull(const char *fullname, BOOL isdir) |
| { |
| static char attr[MAXATTRSZ]; |
| #if POSIXACLS |
| struct POSIX_SECURITY *pxdesc; |
| #endif |
| ULONG attrsz; |
| int mode; |
| uid_t uid; |
| gid_t gid; |
| int attrib; |
| int level; |
| |
| printf("%s ",(isdir ? "Directory" : "File")); |
| printname(stdout,fullname); |
| printf("\n"); |
| |
| /* get individual parameters, as when trying to get them */ |
| /* all, and one (typically SACL) is missing, we get none, */ |
| /* and concatenate them, to be able to compute the hash code */ |
| |
| attrsz = getfull(attr, fullname); |
| if (attrsz) { |
| if (opt_v || opt_b) { |
| hexdump(attr,attrsz,8); |
| printf("Computed hash : 0x%08lx\n", |
| (unsigned long)hash((le32*)attr,attrsz)); |
| } |
| if (opt_v && opt_b) { |
| printf("# %s ",(isdir ? "Directory" : "File")); |
| printname(stdout,fullname); |
| printf(" hash 0x%lx\n", |
| (unsigned long)hash((le32*)attr,attrsz)); |
| } |
| attrib = GetFileAttributesW((LPCWSTR)fullname); |
| if (attrib == INVALID_FILE_ATTRIBUTES) { |
| printf("** Could not get file attrib\n"); |
| errors++; |
| } else |
| printf("Windows attrib : 0x%x\n",attrib); |
| if (ntfs_valid_descr(attr,attrsz)) { |
| #if POSIXACLS |
| pxdesc = linux_permissions_posix(attr,isdir); |
| if (pxdesc) |
| mode = pxdesc->mode; |
| else |
| mode = 0; |
| #else |
| mode = linux_permissions(attr,isdir); |
| #endif |
| if (opt_v >= 2) { |
| level = (opt_b ? 4 : 0); |
| showheader(attr,level); |
| showusid(attr,level); |
| showgsid(attr,level); |
| showdacl(attr,isdir,level); |
| showsacl(attr,isdir,level); |
| } |
| uid = linux_owner(attr); |
| gid = linux_group(attr); |
| if (opt_b) { |
| showownership(attr); |
| printf("# Interpreted Unix owner %d, group %d, mode 0%03o\n", |
| (int)uid,(int)gid,mode); |
| } else { |
| showownership(attr); |
| printf("Interpreted Unix owner %d, group %d, mode 0%03o\n", |
| (int)uid,(int)gid,mode); |
| } |
| #if POSIXACLS |
| if (pxdesc) { |
| if (!opt_b |
| && (pxdesc->defcnt |
| || (pxdesc->tagsset |
| & (POSIX_ACL_USER |
| | POSIX_ACL_GROUP |
| | POSIX_ACL_MASK)))) |
| showposix(pxdesc); |
| free(pxdesc); |
| } |
| #endif |
| } else |
| if (opt_b) |
| printf("# Descriptor fails sanity check\n"); |
| else |
| printf("Descriptor fails sanity check\n"); |
| } |
| } |
| |
| BOOL recurseshow(const char *fullname) |
| { |
| int attrib; |
| int err; |
| BOOL isdir; |
| |
| err = FALSE; |
| attrib = GetFileAttributesW((LPCWSTR)fullname); |
| if (attrib != INVALID_FILE_ATTRIBUTES) { |
| isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; |
| showfull(fullname,isdir); |
| if (isdir |
| && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT) |
| && islink(fullname))) { |
| #if POSIXACLS |
| err = iterate(RECSHOW, fullname, (struct POSIX_SECURITY*)NULL); |
| #else |
| err = iterate(RECSHOW, fullname, 0); |
| #endif |
| } |
| } else { |
| printf("** Could not access "); |
| printname(stdout,fullname); |
| printf("\n"); |
| printerror(stdout); |
| errors++; |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| |
| BOOL singleshow(const char *fullname) |
| { |
| int attrib; |
| int err; |
| BOOL isdir; |
| |
| err = FALSE; |
| attrib = GetFileAttributesW((LPCWSTR)fullname); |
| if (attrib != INVALID_FILE_ATTRIBUTES) { |
| isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; |
| showfull(fullname,isdir); |
| } else { |
| printf("** Could not access "); |
| printname(stdout,fullname); |
| printf("\n"); |
| printerror(stdout); |
| errors++; |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| BOOL mapproposal(const char *fullname) |
| { |
| char attr[256]; |
| ULONG attrsz; |
| int attrib; |
| int err; |
| |
| err = FALSE; |
| attrsz = 0; |
| attrib = GetFileAttributesW((LPCWSTR)fullname); |
| if ((attrib != INVALID_FILE_ATTRIBUTES) |
| && GetFileSecurityW((LPCWSTR)fullname, |
| OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, |
| (char*)attr,256,&attrsz)) { |
| err = proposal(fullname,attr); |
| } else { |
| printf("** Could not access "); |
| printname(stdout,fullname); |
| printf("\n"); |
| printerror(stdout); |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| #if POSIXACLS |
| |
| BOOL recurseset_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc) |
| { |
| int attrib; |
| int err; |
| BOOL isdir; |
| |
| err = FALSE; |
| attrib = GetFileAttributesW((LPCWSTR)fullname); |
| if (attrib != INVALID_FILE_ATTRIBUTES) { |
| isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; |
| err = !setfull_posix(fullname,pxdesc,isdir); |
| if (err) { |
| printf("** Failed to update "); |
| printname(stdout,fullname); |
| printf("\n"); |
| errors++; |
| } else |
| if (isdir |
| && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT) |
| && islink(fullname))) |
| iterate(RECSETPOSIX, fullname, pxdesc); |
| } else { |
| err = GetLastError(); |
| printf("** Could not access "); |
| printname(stdout,fullname); |
| printf("\n"); |
| printerror(stdout); |
| err = TRUE; |
| errors++; |
| } |
| return (err); |
| } |
| |
| #else |
| |
| BOOL recurseset(const char *fullname, int mode) |
| { |
| int attrib; |
| int err; |
| BOOL isdir; |
| |
| err = FALSE; |
| attrib = GetFileAttributesW((LPCWSTR)fullname); |
| if (attrib != INVALID_FILE_ATTRIBUTES) { |
| isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; |
| setfull(fullname,mode,isdir); |
| if (isdir |
| && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT) |
| && islink(fullname))) |
| iterate(RECSETPOSIX, fullname, mode); |
| } else { |
| err = GetLastError(); |
| printf("** Could not access "); |
| printname(stdout,fullname); |
| printf("\n"); |
| printerror(stdout); |
| err = TRUE; |
| errors++; |
| } |
| return (err); |
| } |
| |
| #endif |
| |
| #if POSIXACLS |
| |
| BOOL singleset_posix(const char *path, const struct POSIX_SECURITY *pxdesc) |
| { |
| BOOL isdir; |
| BOOL err; |
| int attrib; |
| |
| err = FALSE; |
| attrib = GetFileAttributesW((LPCWSTR)path); |
| if (attrib != INVALID_FILE_ATTRIBUTES) { |
| isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY); |
| err = !setfull_posix(path,pxdesc,isdir); |
| if (err) { |
| printf("** Failed to update "); |
| printname(stdout,path); |
| printf("\n"); |
| errors++; |
| } |
| } else { |
| printf("** Could not access "); |
| printname(stdout,path); |
| printf("\n"); |
| printerror(stdout); |
| errors++; |
| err = TRUE; |
| } |
| return (!err); |
| } |
| |
| #endif |
| |
| BOOL singleset(const char *path, int mode) |
| { |
| BOOL isdir; |
| BOOL err; |
| int attrib; |
| |
| err = FALSE; |
| attrib = GetFileAttributesW((LPCWSTR)path); |
| if (attrib != INVALID_FILE_ATTRIBUTES) { |
| isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY); |
| setfull(path,mode,isdir); |
| } else { |
| printf("** Could not access "); |
| printname(stdout,path); |
| printf("\n"); |
| printerror(stdout); |
| errors++; |
| err = TRUE; |
| } |
| return (!err); |
| } |
| |
| #else |
| |
| /* |
| * Display all the parameters associated to a file (Linux version) |
| */ |
| |
| void showfull(const char *fullname, BOOL isdir) |
| { |
| static char attr[MAXATTRSZ]; |
| static char part[MAXATTRSZ]; |
| #if POSIXACLS |
| struct POSIX_SECURITY *pxdesc; |
| #endif |
| struct SECURITY_DATA *psecurdata; |
| char *newattr; |
| int securindex; |
| int mode; |
| int level; |
| int attrib; |
| u32 attrsz; |
| u32 partsz; |
| uid_t uid; |
| gid_t gid; |
| |
| if (opt_v || opt_b) |
| printf("%s %s\n",(isdir ? "Directory" : "File"),fullname); |
| |
| /* get individual parameters, as when trying to get them */ |
| /* all, and one (typically SACL) is missing, we get none */ |
| /* and concatenate them, to be able to compute the checksum */ |
| |
| partsz = 0; |
| securindex = ntfs_get_file_security(ntfs_context,fullname, |
| OWNER_SECURITY_INFORMATION, |
| (char*)part,MAXATTRSZ,&partsz); |
| |
| attrib = ntfs_get_file_attributes(ntfs_context, fullname); |
| if (attrib == INVALID_FILE_ATTRIBUTES) { |
| printf("** Could not get file attrib\n"); |
| errors++; |
| } |
| if ((securindex < 0) |
| || (securindex >= MAXSECURID) |
| || ((securindex > 0) |
| && ((!opt_r && !opt_b) |
| || !securdata[securindex >> SECBLKSZ] |
| || !securdata[securindex >> SECBLKSZ][securindex & ((1 << SECBLKSZ) - 1)].filecount))) |
| { |
| if (opt_v || opt_b) { |
| if ((securindex < -1) || (securindex >= MAXSECURID)) |
| printf("Security key : 0x%x out of range\n",securindex); |
| else |
| if (securindex == -1) |
| printf("Security key : none\n"); |
| else |
| printf("Security key : 0x%x\n",securindex); |
| } else { |
| printf("%s %s",(isdir ? "Directory" : "File"),fullname); |
| if ((securindex < -1) || (securindex >= MAXSECURID)) |
| printf(" : key 0x%x out of range\n",securindex); |
| else |
| if (securindex == -1) |
| printf(" : no key\n"); |
| else |
| printf(" : key 0x%x\n",securindex); |
| } |
| |
| attrsz = getfull(attr, fullname); |
| if (attrsz) { |
| psecurdata = (struct SECURITY_DATA*)NULL; |
| if ((securindex < MAXSECURID) && (securindex > 0)) { |
| if (!securdata[securindex >> SECBLKSZ]) |
| newblock(securindex); |
| if (securdata[securindex >> SECBLKSZ]) |
| psecurdata = &securdata[securindex >> SECBLKSZ] |
| [securindex & ((1 << SECBLKSZ) - 1)]; |
| } |
| if (opt_v && (opt_a || opt_b) && psecurdata) { |
| newattr = (char*)malloc(attrsz); |
| printf("# %s %s hash 0x%lx\n",(isdir ? "Directory" : "File"), |
| fullname, |
| (unsigned long)hash((le32*)attr,attrsz)); |
| if (newattr) { |
| memcpy(newattr,attr,attrsz); |
| psecurdata->attr = newattr; |
| } |
| } |
| if ((opt_v || opt_b) |
| && ((securindex >= MAXSECURID) |
| || (securindex <= 0) |
| || !psecurdata |
| || (!psecurdata->filecount |
| && !psecurdata->flags))) { |
| hexdump(attr,attrsz,8); |
| printf("Computed hash : 0x%08lx\n", |
| (unsigned long)hash((le32*)attr,attrsz)); |
| } |
| if (ntfs_valid_descr((char*)attr,attrsz)) { |
| #if POSIXACLS |
| pxdesc = linux_permissions_posix(attr,isdir); |
| if (pxdesc) |
| mode = pxdesc->mode; |
| else |
| mode = 0; |
| #else |
| mode = linux_permissions(attr,isdir); |
| #endif |
| attrib = ntfs_get_file_attributes(ntfs_context,fullname); |
| if (opt_v >= 2) { |
| level = (opt_b ? 4 : 0); |
| showheader(attr,level); |
| showusid(attr,level); |
| showgsid(attr,level); |
| showdacl(attr,isdir,level); |
| showsacl(attr,isdir,level); |
| } |
| if (attrib != INVALID_FILE_ATTRIBUTES) |
| printf("Windows attrib : 0x%x\n",attrib); |
| uid = linux_owner(attr); |
| gid = linux_group(attr); |
| if (opt_b) { |
| showownership(attr); |
| printf("# Interpreted Unix owner %d, group %d, mode 0%03o\n", |
| (int)uid,(int)gid,mode); |
| } else { |
| showownership(attr); |
| printf("Interpreted Unix owner %d, group %d, mode 0%03o\n", |
| (int)uid,(int)gid,mode); |
| } |
| #if POSIXACLS |
| if (pxdesc) { |
| if (!opt_b |
| && (pxdesc->defcnt |
| || (pxdesc->tagsset |
| & (POSIX_ACL_USER |
| | POSIX_ACL_GROUP |
| | POSIX_ACL_MASK)))) |
| showposix(pxdesc); |
| #if USESTUBS |
| stdfree(pxdesc); /* allocated within library */ |
| #else |
| free(pxdesc); |
| #endif |
| } |
| #endif |
| if ((opt_r || opt_b) && (securindex < MAXSECURID) |
| && (securindex > 0) && psecurdata) { |
| psecurdata->filecount++; |
| psecurdata->mode = mode; |
| } |
| } else { |
| printf("** Descriptor fails sanity check\n"); |
| errors++; |
| } |
| } |
| } else |
| if (securindex > 0) { |
| if (securdata[securindex >> SECBLKSZ]) { |
| psecurdata = &securdata[securindex >> SECBLKSZ] |
| [securindex & ((1 << SECBLKSZ) - 1)]; |
| psecurdata->filecount++; |
| if (opt_b || opt_r) { |
| if (!opt_b && !opt_v) |
| printf("%s %s\n",(isdir ? "Directory" : "File"),fullname); |
| printf("Security key : 0x%x mode %03o (already displayed)\n", |
| securindex,psecurdata->mode); |
| if (attrib != INVALID_FILE_ATTRIBUTES) |
| printf("Windows attrib : 0x%x\n",attrib); |
| } else { |
| printf("%s %s",(isdir ? "Directory" : "File"),fullname); |
| printf(" : key 0x%x\n",securindex); |
| } |
| if ((opt_a || opt_b) && opt_v |
| && psecurdata && psecurdata->attr) { |
| printf("# %s %s hash 0x%lx\n",(isdir ? "Directory" : "File"), |
| fullname, |
| (unsigned long)hash((le32*)psecurdata->attr, |
| ntfs_attr_size(psecurdata->attr))); |
| } |
| } |
| } else { |
| if (!opt_v && !opt_b) |
| printf("%s %s",(isdir ? "Directory" : "File"),fullname); |
| printf(" (Failed)\n"); |
| printf("** Could not get security data of %s, partsz %d\n", |
| fullname,partsz); |
| printerror(stdout); |
| errors++; |
| } |
| } |
| |
| BOOL recurseshow(const char *path) |
| { |
| struct CALLBACK dircontext; |
| struct LINK *current; |
| BOOL isdir; |
| BOOL err; |
| |
| err = FALSE; |
| dircontext.head = (struct LINK*)NULL; |
| dircontext.dir = path; |
| isdir = ntfs_read_directory(ntfs_context, path, |
| callback, &dircontext); |
| if (isdir) { |
| showfull(path,TRUE); |
| if (opt_v) { |
| if (opt_b) |
| printf("#\n#\n"); |
| else |
| printf("\n\n"); |
| } |
| while (dircontext.head) { |
| current = dircontext.head; |
| if (recurseshow(current->name)) err = TRUE; |
| dircontext.head = dircontext.head->next; |
| free(current); |
| } |
| } else |
| if (errno == ENOTDIR) { |
| showfull(path,FALSE); |
| if (opt_v) { |
| if (opt_b) |
| printf("#\n#\n"); |
| else |
| printf("\n\n"); |
| } |
| } else { |
| printf("** Could not access %s\n",path); |
| printerror(stdout); |
| errors++; |
| err = TRUE; |
| } |
| return (!err); |
| } |
| |
| |
| BOOL singleshow(const char *path) |
| { |
| BOOL isdir; |
| BOOL err; |
| |
| err = FALSE; |
| isdir = ntfs_read_directory(ntfs_context, path, |
| callback, (struct CALLBACK*)NULL); |
| if (isdir || (errno == ENOTDIR)) |
| showfull(path,isdir); |
| else { |
| printf("** Could not access %s\n",path); |
| printerror(stdout); |
| errors++; |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| #ifdef HAVE_SETXATTR |
| |
| static ssize_t ntfs_getxattr(const char *path, const char *name, void *value, size_t size) |
| { |
| #if defined(__APPLE__) || defined(__DARWIN__) |
| return getxattr(path, name, value, size, 0, 0); |
| #else |
| return getxattr(path, name, value, size); |
| #endif |
| } |
| |
| /* |
| * Display all the parameters associated to a mounted file |
| */ |
| |
| BOOL showmounted(const char *fullname) |
| { |
| |
| static char attr[MAXATTRSZ]; |
| struct stat st; |
| #if POSIXACLS |
| struct POSIX_SECURITY *pxdesc; |
| #endif |
| BOOL mapped; |
| int attrsz; |
| int mode; |
| uid_t uid; |
| gid_t gid; |
| u32 attrib; |
| int level; |
| BOOL isdir; |
| BOOL err; |
| |
| err = FALSE; |
| if (!stat(fullname,&st)) { |
| isdir = S_ISDIR(st.st_mode); |
| printf("%s ",(isdir ? "Directory" : "File")); |
| printname(stdout,fullname); |
| printf("\n"); |
| |
| attrsz = ntfs_getxattr(fullname,"system.ntfs_acl",attr,MAXATTRSZ); |
| if (attrsz > 0) { |
| if (opt_v) { |
| hexdump(attr,attrsz,8); |
| printf("Computed hash : 0x%08lx\n", |
| (unsigned long)hash((le32*)attr,attrsz)); |
| } |
| if (ntfs_getxattr(fullname,"system.ntfs_attrib",&attrib,4) != 4) { |
| printf("** Could not get file attrib\n"); |
| errors++; |
| } else |
| printf("Windows attrib : 0x%x\n",(int)attrib); |
| if (ntfs_valid_descr(attr,attrsz)) { |
| mapped = !local_build_mapping(context.mapping,fullname); |
| #if POSIXACLS |
| if (mapped) { |
| pxdesc = linux_permissions_posix(attr,isdir); |
| if (pxdesc) |
| mode = pxdesc->mode; |
| else |
| mode = 0; |
| } else { |
| pxdesc = (struct POSIX_SECURITY*)NULL; |
| mode = linux_permissions(attr,isdir); |
| printf("No user mapping : " |
| "cannot display the Posix ACL\n"); |
| } |
| #else |
| mode = linux_permissions(attr,isdir); |
| #endif |
| if (opt_v >= 2) { |
| level = (opt_b ? 4 : 0); |
| showheader(attr,level); |
| showusid(attr,level); |
| showgsid(attr,level); |
| showdacl(attr,isdir,level); |
| showsacl(attr,isdir,level); |
| } |
| showownership(attr); |
| if (mapped) { |
| uid = linux_owner(attr); |
| gid = linux_group(attr); |
| printf("Interpreted Unix owner %d, group %d, mode 0%03o\n", |
| (int)uid,(int)gid,mode); |
| } else { |
| printf("Interpreted Unix mode 0%03o (owner and group are unmapped)\n", |
| mode); |
| } |
| #if POSIXACLS |
| if (pxdesc) { |
| if ((pxdesc->defcnt |
| || (pxdesc->tagsset |
| & (POSIX_ACL_USER |
| | POSIX_ACL_GROUP |
| | POSIX_ACL_MASK)))) |
| showposix(pxdesc); |
| #if USESTUBS |
| stdfree(pxdesc); /* allocated within library */ |
| #else |
| free(pxdesc); |
| #endif |
| } |
| if (mapped) |
| ntfs_free_mapping(context.mapping); |
| #endif |
| } else { |
| printf("Descriptor fails sanity check\n"); |
| errors++; |
| } |
| } else { |
| printf("** Could not get the NTFS ACL, check whether file is on NTFS\n"); |
| errors++; |
| } |
| } else { |
| printf("%s not found\n",fullname); |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| BOOL processmounted(const char *fullname) |
| { |
| |
| static char attr[MAXATTRSZ]; |
| struct stat st; |
| int attrsz; |
| BOOL err; |
| |
| err = FALSE; |
| if (!opt_u) |
| err = showmounted(fullname); |
| else |
| if (!stat(fullname,&st)) { |
| attrsz = ntfs_getxattr(fullname,"system.ntfs_acl",attr,MAXATTRSZ); |
| if (attrsz > 0) { |
| if (opt_v) { |
| hexdump(attr,attrsz,8); |
| printf("Computed hash : 0x%08lx\n", |
| (unsigned long)hash((le32*)attr,attrsz)); |
| } |
| if (ntfs_valid_descr(attr,attrsz)) { |
| err = proposal(fullname, attr); |
| } else { |
| printf("*** Descriptor fails sanity check\n"); |
| errors++; |
| } |
| } else { |
| printf("** Could not get the NTFS ACL, check whether file is on NTFS\n"); |
| errors++; |
| } |
| } else { |
| printf("%s not found\n",fullname); |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| #else /* HAVE_SETXATTR */ |
| |
| BOOL processmounted(const char *fullname __attribute__((unused))) |
| { |
| fprintf(stderr,"Not possible on this configuration,\n"); |
| fprintf(stderr,"you have to use an unmounted partition\n"); |
| return (TRUE); |
| } |
| |
| #endif /* HAVE_SETXATTR */ |
| |
| #if POSIXACLS |
| |
| BOOL recurseset_posix(const char *path, const struct POSIX_SECURITY *pxdesc) |
| { |
| struct CALLBACK dircontext; |
| struct LINK *current; |
| BOOL isdir; |
| BOOL err; |
| |
| err = FALSE; |
| dircontext.head = (struct LINK*)NULL; |
| dircontext.dir = path; |
| isdir = ntfs_read_directory(ntfs_context, path, |
| callback, &dircontext); |
| if (isdir) { |
| err = !setfull_posix(path,pxdesc,TRUE); |
| if (err) { |
| printf("** Failed to update %s\n",path); |
| printerror(stdout); |
| errors++; |
| } else { |
| if (opt_b) |
| printf("#\n#\n"); |
| else |
| printf("\n\n"); |
| while (dircontext.head) { |
| current = dircontext.head; |
| recurseset_posix(current->name,pxdesc); |
| dircontext.head = dircontext.head->next; |
| free(current); |
| } |
| } |
| } else |
| if (errno == ENOTDIR) { |
| err = !setfull_posix(path,pxdesc,FALSE); |
| if (err) { |
| printf("** Failed to update %s\n",path); |
| printerror(stdout); |
| errors++; |
| } |
| } else { |
| printf("** Could not access %s\n",path); |
| printerror(stdout); |
| errors++; |
| err = TRUE; |
| } |
| return (!err); |
| } |
| |
| #else |
| |
| BOOL recurseset(const char *path, int mode) |
| { |
| struct CALLBACK dircontext; |
| struct LINK *current; |
| BOOL isdir; |
| BOOL err; |
| |
| err = FALSE; |
| dircontext.head = (struct LINK*)NULL; |
| dircontext.dir = path; |
| isdir = ntfs_read_directory(ntfs_context, path, |
| callback, &dircontext); |
| if (isdir) { |
| setfull(path,mode,TRUE); |
| if (opt_b) |
| printf("#\n#\n"); |
| else |
| printf("\n\n"); |
| while (dircontext.head) { |
| current = dircontext.head; |
| recurseset(current->name,mode); |
| dircontext.head = dircontext.head->next; |
| free(current); |
| } |
| } else |
| if (errno == ENOTDIR) |
| setfull(path,mode,FALSE); |
| else { |
| printf("** Could not access %s\n",path); |
| printerror(stdout); |
| errors++; |
| err = TRUE; |
| } |
| return (!err); |
| } |
| |
| #endif |
| |
| #if POSIXACLS |
| |
| BOOL singleset_posix(const char *path, const struct POSIX_SECURITY *pxdesc) |
| { |
| BOOL isdir; |
| BOOL err; |
| |
| err = FALSE; |
| isdir = ntfs_read_directory(ntfs_context, path, |
| callback, (struct CALLBACK*)NULL); |
| if (isdir || (errno == ENOTDIR)) { |
| err = !setfull_posix(path,pxdesc,isdir); |
| if (err) { |
| printf("** Failed to update %s\n",path); |
| printerror(stdout); |
| errors++; |
| } |
| } else { |
| printf("** Could not access %s\n",path); |
| printerror(stdout); |
| errors++; |
| err = TRUE; |
| } |
| return (!err); |
| } |
| |
| #endif |
| |
| BOOL singleset(const char *path, int mode) |
| { |
| BOOL isdir; |
| BOOL err; |
| |
| err = FALSE; |
| isdir = ntfs_read_directory(ntfs_context, path, |
| callback, (struct CALLBACK*)NULL); |
| if (isdir || (errno == ENOTDIR)) |
| setfull(path,mode,isdir); |
| else { |
| printf("** Could not access %s\n",path); |
| printerror(stdout); |
| errors++; |
| err = TRUE; |
| } |
| return (!err); |
| } |
| |
| int callback(struct CALLBACK *dircontext, char *ntfsname, |
| int length, int type, |
| long long pos __attribute__((unused)), u64 mft_ref __attribute__((unused)), |
| unsigned int dt_type __attribute__((unused))) |
| { |
| struct LINK *linkage; |
| char *name; |
| int newlth; |
| int size; |
| |
| size = utf8size(ntfsname,length); |
| if (dircontext |
| && (type != 2) /* 2 : dos name (8+3) */ |
| && (size > 0) /* chars convertible to utf8 */ |
| && ((length > 2) |
| || (ntfsname[0] != '.') |
| || (ntfsname[1] != '\0') |
| || ((ntfsname[2] || ntfsname[3]) |
| && ((ntfsname[2] != '.') || (ntfsname[3] != '\0'))))) { |
| linkage = (struct LINK*)malloc(sizeof(struct LINK) |
| + strlen(dircontext->dir) |
| + size + 2); |
| if (linkage) { |
| /* may find ".fuse_hidden*" files */ |
| /* recommendation is not to hide them, so that */ |
| /* the user has a clue to delete them */ |
| strcpy(linkage->name,dircontext->dir); |
| if (linkage->name[strlen(linkage->name) - 1] != '/') |
| strcat(linkage->name,"/"); |
| name = &linkage->name[strlen(linkage->name)]; |
| newlth = makeutf8(name,ntfsname,length); |
| name[newlth] = 0; |
| linkage->next = dircontext->head; |
| dircontext->head = linkage; |
| } |
| } |
| return (0); |
| } |
| |
| #endif |
| |
| #ifdef WIN32 |
| |
| /* |
| * Backup security descriptors in a directory tree (Windows mode) |
| */ |
| |
| BOOL backup(const char *root) |
| { |
| BOOL err; |
| time_t now; |
| const char *txtime; |
| |
| now = time((time_t*)NULL); |
| txtime = ctime(&now); |
| printf("#\n# Recursive ACL collection on %s#\n",txtime); |
| err = recurseshow(root); |
| return (err); |
| } |
| |
| #else |
| |
| /* |
| * Backup security descriptors in a directory tree (Linux mode) |
| */ |
| |
| BOOL backup(const char *volume, const char *root) |
| { |
| BOOL err; |
| int count; |
| int i,j; |
| time_t now; |
| const char *txtime; |
| |
| now = time((time_t*)NULL); |
| txtime = ctime(&now); |
| if (!getuid() && open_security_api()) { |
| if (open_volume(volume,NTFS_MNT_RDONLY)) { |
| printf("#\n# Recursive ACL collection on %s#\n",txtime); |
| err = recurseshow(root); |
| count = 0; |
| for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
| if (securdata[i]) |
| for (j=0; j<(1 << SECBLKSZ); j++) |
| if (securdata[i][j].filecount) { |
| count++; |
| } |
| printf("# %d security keys\n",count); |
| close_volume(volume); |
| } else { |
| fprintf(stderr,"Could not open volume %s\n",volume); |
| printerror(stdout); |
| err = TRUE; |
| } |
| close_security_api(); |
| } else { |
| if (getuid()) |
| fprintf(stderr,"This is only possible as root\n"); |
| else |
| fprintf(stderr,"Could not open security API\n"); |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| #endif |
| |
| #ifdef WIN32 |
| |
| /* |
| * List security descriptors in a directory tree (Windows mode) |
| */ |
| |
| BOOL listfiles(const char *root) |
| { |
| BOOL err; |
| |
| if (opt_r) { |
| printf("\nRecursive file check\n"); |
| err = recurseshow(root); |
| } else |
| err = singleshow(root); |
| return (err); |
| } |
| |
| #else |
| |
| /* |
| * List security descriptors in a directory tree (Linux mode) |
| */ |
| |
| BOOL listfiles(const char *volume, const char *root) |
| { |
| BOOL err; |
| int i,j; |
| int count; |
| |
| if (!getuid() && open_security_api()) { |
| if (open_volume(volume,NTFS_MNT_RDONLY)) { |
| if (opt_r) { |
| printf("\nRecursive file check\n"); |
| err = recurseshow(root); |
| printf("Summary\n"); |
| count = 0; |
| for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
| if (securdata[i]) |
| for (j=0; j<(1 << SECBLKSZ); j++) |
| if (securdata[i][j].filecount) { |
| printf("Key 0x%x : %d files, mode 0%03o\n", |
| i*(1 << SECBLKSZ)+j,securdata[i][j].filecount, |
| securdata[i][j].mode); |
| count++; |
| } |
| printf("%d security keys\n",count); |
| } else |
| err = singleshow(root); |
| close_volume(volume); |
| } else { |
| fprintf(stderr,"Could not open volume %s\n",volume); |
| printerror(stdout); |
| err = TRUE; |
| } |
| close_security_api(); |
| } else { |
| if (getuid()) |
| fprintf(stderr,"This is only possible as root\n"); |
| else |
| fprintf(stderr,"Could not open security API\n"); |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| BOOL mapproposal(const char *volume, const char *name) |
| { |
| BOOL err; |
| u32 attrsz; |
| int securindex; |
| char attr[256]; /* header (20) and a couple of SIDs (max 40 each) */ |
| |
| err = FALSE; |
| if (!getuid() && open_security_api()) { |
| if (open_volume(volume,NTFS_MNT_RDONLY)) { |
| |
| attrsz = 0; |
| securindex = ntfs_get_file_security(ntfs_context,name, |
| OWNER_SECURITY_INFORMATION |
| | GROUP_SECURITY_INFORMATION, |
| (char*)attr,MAXATTRSZ,&attrsz); |
| if (securindex) |
| err = proposal(name,attr); |
| else { |
| fprintf(stderr,"*** Could not get the ACL of %s\n", |
| name); |
| printerror(stdout); |
| errors++; |
| } |
| close_volume(volume); |
| } else { |
| fprintf(stderr,"Could not open volume %s\n",volume); |
| printerror(stdout); |
| err = TRUE; |
| } |
| close_security_api(); |
| } else { |
| if (getuid()) |
| fprintf(stderr,"This is only possible as root\n"); |
| else |
| fprintf(stderr,"Could not open security API\n"); |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| #endif |
| |
| #ifndef WIN32 |
| |
| /* |
| * Check whether a SDS entry is valid |
| */ |
| |
| BOOL valid_sds(const char *attr, unsigned int offset, |
| unsigned int entrysz, unsigned int size, u32 prevkey, |
| BOOL second) |
| { |
| BOOL unsane; |
| u32 comphash; |
| u32 key; |
| |
| unsane = FALSE; |
| if (!get4l(attr,0) && !get4l(attr,4)) { |
| printf("Entry at 0x%lx was deleted\n",(long)offset); |
| } else { |
| if ((ntfs_attr_size(&attr[20]) + 20) > entrysz) { |
| printf("** Entry is truncated (expected size %ld)\n", |
| (long)ntfs_attr_size(&attr[20] + 20)); |
| unsane = TRUE; |
| errors++; |
| } |
| if ((ntfs_attr_size(&attr[20]) + 20) < entrysz) { |
| printf("** Extra data appended to entry (expected size %ld)\n", |
| (long)ntfs_attr_size(&attr[20]) + 20); |
| warnings++; |
| } |
| if (!unsane && !ntfs_valid_descr((const char*)&attr[20],size)) { |
| printf("** General sanity check has failed\n"); |
| unsane = TRUE; |
| errors++; |
| } |
| if (!unsane) { |
| comphash = hash((const le32*)&attr[20],entrysz-20); |
| if ((u32)get4l(attr,0) == comphash) { |
| if (opt_v >= 2) |
| printf("Hash 0x%08lx (correct)\n", |
| (unsigned long)comphash); |
| } else { |
| printf("** hash 0x%08lx (computed : 0x%08lx)\n", |
| (unsigned long)get4l(attr,0), |
| (unsigned long)comphash); |
| unsane = TRUE; |
| errors++; |
| } |
| } |
| if (!unsane) { |
| if ((second ? get8l(attr,8) + 0x40000 : get8l(attr,8)) == offset) { |
| if (opt_v >= 2) |
| printf("Offset 0x%lx (correct)\n",(long)offset); |
| } else { |
| printf("** offset 0x%llx (expected : 0x%llx)\n", |
| (long long)get8l(attr,8), |
| (long long)(second ? get8l(attr,8) - 0x40000 : get8l(attr,8))); |
| // unsane = TRUE; |
| errors++; |
| } |
| } |
| if (!unsane) { |
| key = get4l(attr,4); |
| if (opt_v >= 2) |
| printf("Key 0x%x\n",(int)key); |
| if (key) { |
| if (key <= prevkey) { |
| printf("** Unordered key 0x%lx after 0x%lx\n", |
| (long)key,(long)prevkey); |
| unsane = TRUE; |
| errors++; |
| } |
| } |
| } |
| } |
| return (!unsane); |
| } |
| |
| /* |
| * Check whether a SDS entry is consistent with other known data |
| * and store current data for subsequent checks |
| */ |
| |
| int consist_sds(const char *attr, unsigned int offset, |
| unsigned int entrysz, BOOL second) |
| { |
| int errcnt; |
| u32 key; |
| u32 comphash; |
| struct SECURITY_DATA *psecurdata; |
| |
| errcnt = 0; |
| key = get4l(attr,4); |
| if ((key > 0) && (key < MAXSECURID)) { |
| printf("Valid entry at 0x%lx for key 0x%lx\n", |
| (long)offset,(long)key); |
| if (!securdata[key >> SECBLKSZ]) |
| newblock(key); |
| if (securdata[key >> SECBLKSZ]) { |
| psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)]; |
| comphash = hash((const le32*)&attr[20],entrysz-20); |
| if (psecurdata->flags & INSDS1) { |
| if (psecurdata->hash != comphash) { |
| printf("** Different hash values : $SDS-1 0x%08lx $SDS-2 0x%08lx\n", |
| (unsigned long)psecurdata->hash, |
| (unsigned long)comphash); |
| errcnt++; |
| errors++; |
| } |
| if (psecurdata->offset != get8l(attr,8)) { |
| printf("** Different offsets : $SDS-1 0x%llx $SDS-2 0x%llx\n", |
| (long long)psecurdata->offset,(long long)get8l(attr,8)); |
| errcnt++; |
| errors++; |
| } |
| if (psecurdata->length != get4l(attr,16)) { |
| printf("** Different lengths : $SDS-1 0x%lx $SDS-2 0x%lx\n", |
| (long)psecurdata->length,(long)get4l(attr,16)); |
| errcnt++; |
| errors++; |
| } |
| } else { |
| if (second) { |
| printf("** Entry was not present in $SDS-1\n"); |
| errcnt++; |
| errors++; |
| } |
| psecurdata->hash = comphash; |
| psecurdata->offset = get8l(attr,8); |
| psecurdata->length = get4l(attr,16); |
| } |
| psecurdata->flags |= (second ? INSDS2 : INSDS1); |
| } |
| } else |
| if (key || get4l(attr,0)) { |
| printf("** Security_id 0x%x out of bounds\n",key); |
| warnings++; |
| } |
| return (errcnt); |
| } |
| |
| |
| /* |
| * Auditing of $SDS (Linux only) |
| */ |
| |
| int audit_sds(BOOL second) |
| { |
| static char attr[MAXATTRSZ + 20]; |
| BOOL isdir; |
| BOOL done; |
| BOOL unsane; |
| u32 prevkey; |
| int errcnt; |
| int size; |
| unsigned int entrysz; |
| unsigned int entryalsz; |
| unsigned int offset; |
| int count; |
| int deleted; |
| int mode; |
| |
| if (second) |
| printf("\nAuditing $SDS-2\n"); |
| else |
| printf("\nAuditing $SDS-1\n"); |
| errcnt = 0; |
| offset = (second ? 0x40000 : 0); |
| count = 0; |
| deleted = 0; |
| done = FALSE; |
| prevkey = 0; |
| |
| /* get size of first record */ |
| |
| size = ntfs_read_sds(ntfs_context,(char*)attr,20,offset); |
| if (size != 20) { |
| if ((size < 0) && (errno == ENOTSUP)) |
| printf("** There is no $SDS-%d in this volume\n", |
| (second ? 2 : 1)); |
| else { |
| printf("** Could not open $SDS-%d, size %d\n", |
| (second ? 2 : 1),size); |
| errors++; |
| errcnt++; |
| } |
| } else |
| do { |
| entrysz = get4l(attr,16); |
| entryalsz = ((entrysz - 1) | 15) + 1; |
| if (entryalsz <= (MAXATTRSZ + 20)) { |
| /* read next header in anticipation, to get its size */ |
| size = ntfs_read_sds(ntfs_context, |
| (char*)&attr[20],entryalsz,offset + 20); |
| if (opt_v) |
| printf("\nAt offset 0x%lx got %lu bytes\n",(long)offset,(long)size); |
| } else { |
| printf("** Security attribute is too long (%ld bytes) - stopping\n", |
| (long)entryalsz); |
| errcnt++; |
| } |
| if ((entryalsz > (MAXATTRSZ + 20)) || (size < (int)(entrysz - 20))) |
| done = TRUE; |
| else { |
| if (opt_v) { |
| printf("Entry size %d bytes\n",entrysz); |
| hexdump(&attr[20],size,8); |
| } |
| |
| unsane = !valid_sds(attr,offset,entrysz, |
| size,prevkey,second); |
| if (!unsane) { |
| if (!get4l(attr,0) && !get4l(attr,4)) |
| deleted++; |
| else |
| count++; |
| errcnt += consist_sds(attr,offset, |
| entrysz, second); |
| if (opt_v >= 2) { |
| isdir = guess_dir(&attr[20]); |
| printf("Assuming %s descriptor\n",(isdir ? "directory" : "file")); |
| showheader(&attr[20],0); |
| showusid(&attr[20],0); |
| showgsid(&attr[20],0); |
| showdacl(&attr[20],isdir,0); |
| showsacl(&attr[20],isdir,0); |
| showownership(&attr[20]); |
| mode = linux_permissions( |
| &attr[20],isdir); |
| printf("Interpreted Unix mode 0%03o\n",mode); |
| } |
| prevkey = get4l(attr,4); |
| } |
| if (!unsane) { |
| memcpy(attr,&attr[entryalsz],20); |
| offset += entryalsz; |
| if (!get4l(attr,16) |
| || ((((offset - 1) | 0x3ffff) - offset + 1) < 20)) { |
| if (second) |
| offset = ((offset - 1) | 0x7ffff) + 0x40001; |
| else |
| offset = ((offset - 1) | 0x7ffff) + 1; |
| if (opt_v) |
| printf("Trying next SDS-%d block at offset 0x%lx\n", |
| (second ? 2 : 1), (long)offset); |
| size = ntfs_read_sds(ntfs_context, |
| (char*)attr,20,offset); |
| if (size != 20) { |
| if (opt_v) |
| printf("Assuming end of $SDS, got %d bytes\n",size); |
| done = TRUE; |
| } |
| } |
| } else { |
| printf("** Sanity check failed - stopping there\n"); |
| errcnt++; |
| errors++; |
| done = TRUE; |
| } |
| } |
| } while (!done); |
| if (count || deleted || errcnt) { |
| printf("%d valid and %d deleted entries in $SDS-%d\n", |
| count,deleted,(second ? 2 : 1)); |
| printf("%d errors in $SDS-%c\n",errcnt,(second ? '2' : '1')); |
| } |
| return (errcnt); |
| } |
| |
| /* |
| * Check whether a SII entry is sane |
| */ |
| |
| BOOL valid_sii(const char *entry, u32 prevkey) |
| { |
| BOOL valid; |
| u32 key; |
| |
| valid = TRUE; |
| key = get4l(entry,16); |
| if (key <= prevkey) { |
| printf("** Unordered key 0x%lx after 0x%lx\n", |
| (long)key,(long)prevkey); |
| valid = FALSE; |
| errors++; |
| } |
| prevkey = key; |
| if (get2l(entry,0) != 20) { |
| printf("** offset %d (instead of 20)\n",(int)get2l(entry,0)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get2l(entry,2) != 20) { |
| printf("** size %d (instead of 20)\n",(int)get2l(entry,2)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get4l(entry,4) != 0) { |
| printf("** fill1 %d (instead of 0)\n",(int)get4l(entry,4)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get2l(entry,12) & 1) { |
| if (get2l(entry,8) != 48) { |
| printf("** index size %d (instead of 48)\n",(int)get2l(entry,8)); |
| valid = FALSE; |
| errors++; |
| } |
| } else |
| if (get2l(entry,8) != 40) { |
| printf("** index size %d (instead of 40)\n",(int)get2l(entry,8)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get2l(entry,10) != 4) { |
| printf("** index key size %d (instead of 4)\n",(int)get2l(entry,10)); |
| valid = FALSE; |
| errors++; |
| } |
| if ((get2l(entry,12) & ~3) != 0) { |
| printf("** flags 0x%x (instead of < 4)\n",(int)get2l(entry,12)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get2l(entry,14) != 0) { |
| printf("** fill2 %d (instead of 0)\n",(int)get2l(entry,14)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get4l(entry,24) != key) { |
| printf("** key 0x%x (instead of 0x%x)\n", |
| (int)get4l(entry,24),(int)key); |
| valid = FALSE; |
| errors++; |
| } |
| return (valid); |
| } |
| |
| /* |
| * Check whether a SII entry is consistent with other known data |
| */ |
| |
| int consist_sii(const char *entry) |
| { |
| int errcnt; |
| u32 key; |
| struct SECURITY_DATA *psecurdata; |
| |
| errcnt = 0; |
| key = get4l(entry,16); |
| if ((key > 0) && (key < MAXSECURID)) { |
| printf("Valid entry for key 0x%lx\n",(long)key); |
| if (!securdata[key >> SECBLKSZ]) |
| newblock(key); |
| if (securdata[key >> SECBLKSZ]) { |
| psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)]; |
| psecurdata->flags |= INSII; |
| if (psecurdata->flags & (INSDS1 | INSDS2)) { |
| if ((u32)get4l(entry,20) != psecurdata->hash) { |
| printf("** hash 0x%x (instead of 0x%x)\n", |
| (unsigned int)get4l(entry,20), |
| (unsigned int)psecurdata->hash); |
| errors++; |
| } |
| if (get8l(entry,28) != psecurdata->offset) { |
| printf("** offset 0x%llx (instead of 0x%llx)\n", |
| (long long)get8l(entry,28), |
| (long long)psecurdata->offset); |
| errors++; |
| } |
| if (get4l(entry,36) != psecurdata->length) { |
| printf("** length 0x%lx (instead of %ld)\n", |
| (long)get4l(entry,36), |
| (long)psecurdata->length); |
| errors++; |
| } |
| } else { |
| printf("** Entry was not present in $SDS\n"); |
| errors++; |
| psecurdata->hash = get4l(entry,20); |
| psecurdata->offset = get8l(entry,28); |
| psecurdata->length = get4l(entry,36); |
| if (opt_v) { |
| printf(" hash 0x%x\n",(unsigned int)psecurdata->hash); |
| printf(" offset 0x%llx\n",(long long)psecurdata->offset); |
| printf(" length %ld\n",(long)psecurdata->length); |
| } |
| errcnt++; |
| } |
| } |
| } else { |
| printf("** Security_id 0x%x out of bounds\n",key); |
| warnings++; |
| } |
| return (errcnt); |
| } |
| |
| |
| /* |
| * Auditing of $SII (Linux only) |
| */ |
| |
| int audit_sii() |
| { |
| char *entry; |
| int errcnt; |
| u32 prevkey; |
| BOOL valid; |
| BOOL done; |
| int count; |
| |
| printf("\nAuditing $SII\n"); |
| errcnt = 0; |
| count = 0; |
| entry = (char*)NULL; |
| prevkey = 0; |
| done = FALSE; |
| do { |
| entry = (char*)ntfs_read_sii(ntfs_context,(void*)entry); |
| if (entry) { |
| valid = valid_sii(entry,prevkey); |
| if (valid) { |
| count++; |
| errcnt += consist_sii(entry); |
| prevkey = get4l(entry,16); |
| } else |
| errcnt++; |
| } else |
| if ((errno == ENOTSUP) && !prevkey) |
| printf("** There is no $SII in this volume\n"); |
| } while (entry && !done); |
| if (count || errcnt) { |
| printf("%d valid entries in $SII\n",count); |
| printf("%d errors in $SII\n",errcnt); |
| } |
| return (errcnt); |
| } |
| |
| /* |
| * Check whether a SII entry is sane |
| */ |
| |
| BOOL valid_sdh(const char *entry, u32 prevkey, u32 prevhash) |
| { |
| BOOL valid; |
| u32 key; |
| u32 currhash; |
| |
| valid = TRUE; |
| currhash = get4l(entry,16); |
| key = get4l(entry,20); |
| if ((currhash < prevhash) |
| || ((currhash == prevhash) && (key <= prevkey))) { |
| printf("** Unordered hash and key 0x%x 0x%x after 0x%x 0x%x\n", |
| (unsigned int)currhash,(unsigned int)key, |
| (unsigned int)prevhash,(unsigned int)prevkey); |
| valid = FALSE; |
| errors++; |
| } |
| if ((opt_v >= 2) && (currhash == prevhash)) |
| printf("Hash collision (not an error)\n"); |
| |
| if (get2l(entry,0) != 24) { |
| printf("** offset %d (instead of 24)\n",(int)get2l(entry,0)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get2l(entry,2) != 20) { |
| printf("** size %d (instead of 20)\n",(int)get2l(entry,2)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get4l(entry,4) != 0) { |
| printf("** fill1 %d (instead of 0)\n",(int)get4l(entry,4)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get2l(entry,12) & 1) { |
| if (get2l(entry,8) != 56) { |
| printf("** index size %d (instead of 56)\n",(int)get2l(entry,8)); |
| valid = FALSE; |
| errors++; |
| } |
| } else |
| if (get2l(entry,8) != 48) { |
| printf("** index size %d (instead of 48)\n",(int)get2l(entry,8)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get2l(entry,10) != 8) { |
| printf("** index key size %d (instead of 8)\n",(int)get2l(entry,10)); |
| valid = FALSE; |
| errors++; |
| } |
| if ((get2l(entry,12) & ~3) != 0) { |
| printf("** flags 0x%x (instead of < 4)\n",(int)get2l(entry,12)); |
| valid = FALSE; |
| errors++; |
| } |
| if (get2l(entry,14) != 0) { |
| printf("** fill2 %d (instead of 0)\n",(int)get2l(entry,14)); |
| valid = FALSE; |
| errors++; |
| } |
| if ((u32)get4l(entry,24) != currhash) { |
| printf("** hash 0x%x (instead of 0x%x)\n", |
| (unsigned int)get4l(entry,24),(unsigned int)currhash); |
| valid = FALSE; |
| errors++; |
| } |
| if (get4l(entry,28) != key) { |
| printf("** key 0x%x (instead of 0x%x)\n", |
| (int)get4l(entry,28),(int)key); |
| valid = FALSE; |
| errors++; |
| } |
| if (get4l(entry,44) |
| && (get4l(entry,44) != 0x490049)) { |
| printf("** fill3 0x%lx (instead of 0 or 0x490049)\n", |
| (long)get4l(entry,44)); |
| valid = FALSE; |
| errors++; |
| } |
| return (valid); |
| } |
| |
| /* |
| * Check whether a SDH entry is consistent with other known data |
| */ |
| |
| int consist_sdh(const char *entry) |
| { |
| int errcnt; |
| u32 key; |
| struct SECURITY_DATA *psecurdata; |
| |
| errcnt = 0; |
| key = get4l(entry,20); |
| if ((key > 0) && (key < MAXSECURID)) { |
| printf("Valid entry for key 0x%lx\n",(long)key); |
| if (!securdata[key >> SECBLKSZ]) |
| newblock(key); |
| if (securdata[key >> SECBLKSZ]) { |
| psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)]; |
| psecurdata->flags |= INSDH; |
| if (psecurdata->flags & (INSDS1 | INSDS2 | INSII)) { |
| if ((u32)get4l(entry,24) != psecurdata->hash) { |
| printf("** hash 0x%x (instead of 0x%x)\n", |
| (unsigned int)get4l(entry,24), |
| (unsigned int)psecurdata->hash); |
| errors++; |
| } |
| if (get8l(entry,32) != psecurdata->offset) { |
| printf("** offset 0x%llx (instead of 0x%llx)\n", |
| (long long)get8l(entry,32), |
| (long long)psecurdata->offset); |
| errors++; |
| } |
| if (get4l(entry,40) != psecurdata->length) { |
| printf("** length %ld (instead of %ld)\n", |
| (long)get4l(entry,40), |
| (long)psecurdata->length); |
| errors++; |
| } |
| } else { |
| printf("** Entry was not present in $SDS nor in $SII\n"); |
| errors++; |
| psecurdata->hash = get4l(entry,24); |
| psecurdata->offset = get8l(entry,32); |
| psecurdata->length = get4l(entry,40); |
| if (opt_v) { |
| printf(" offset 0x%llx\n",(long long)psecurdata->offset); |
| printf(" length %ld\n",(long)psecurdata->length); |
| } |
| errcnt++; |
| } |
| } |
| } else { |
| printf("** Security_id 0x%x out of bounds\n",key); |
| warnings++; |
| } |
| return (errcnt); |
| } |
| |
| /* |
| * Auditing of $SDH (Linux only) |
| */ |
| |
| int audit_sdh() |
| { |
| char *entry; |
| int errcnt; |
| int count; |
| u32 prevkey; |
| u32 prevhash; |
| BOOL valid; |
| BOOL done; |
| |
| printf("\nAuditing $SDH\n"); |
| count = 0; |
| errcnt = 0; |
| prevkey = 0; |
| prevhash = 0; |
| entry = (char*)NULL; |
| done = FALSE; |
| do { |
| entry = (char*)ntfs_read_sdh(ntfs_context,(void*)entry); |
| if (entry) { |
| valid = valid_sdh(entry,prevkey,prevhash); |
| if (valid) { |
| count++; |
| errcnt += consist_sdh(entry); |
| prevhash = get4l(entry,16); |
| prevkey = get4l(entry,20); |
| } else |
| errcnt++; |
| } else |
| if ((errno == ENOTSUP) && !prevkey) |
| printf("** There is no $SDH in this volume\n"); |
| } while (entry && !done); |
| if (count || errcnt) { |
| printf("%d valid entries in $SDH\n",count); |
| printf("%d errors in $SDH\n",errcnt); |
| } |
| return (errcnt); |
| } |
| |
| /* |
| * Audit summary |
| */ |
| |
| void audit_summary() |
| { |
| int count; |
| int flags; |
| int cnt; |
| int found; |
| int i,j; |
| |
| count = 0; |
| found = 0; |
| if (opt_r) printf("Summary of security key use :\n"); |
| for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
| if (securdata[i]) |
| for (j=0; j<(1 << SECBLKSZ); j++) { |
| flags = securdata[i][j].flags & (INSDS1 + INSDS2 + INSII + INSDH); |
| if (flags) found++; |
| if (flags |
| && (flags != (INSDS1 + INSDS2 + INSII + INSDH))) |
| { |
| if (!count && !opt_r) |
| printf("\n** Keys not present in all files :\n"); |
| cnt = securdata[i][j].filecount; |
| if (opt_r) |
| printf("Key 0x%x used by %d %s, not in", |
| i*(1 << SECBLKSZ)+j,cnt, |
| (cnt > 1 ? "files" : "file")); |
| else |
| printf("Key 0x%x not in", i*(1 << SECBLKSZ)+j); |
| if (!(flags & INSDS1)) |
| printf(" SDS-1"); |
| if (!(flags & INSDS2)) |
| printf(" SDS-2"); |
| if (!(flags & INSII)) |
| printf(" SII"); |
| if (!(flags & INSDH)) |
| printf(" SDH"); |
| printf("\n"); |
| count++; |
| } else { |
| cnt = securdata[i][j].filecount; |
| if (opt_r && cnt) |
| printf("Key 0x%x used by %d %s\n", |
| i*(1 << SECBLKSZ)+j,cnt, |
| (cnt > 1 ? "files" : "file")); |
| } |
| } |
| if (found) { |
| if (count) |
| printf("%d keys not present in all lists\n",count); |
| else |
| printf("All keys are present in all lists\n"); |
| } |
| } |
| |
| /* |
| * Auditing (Linux only) |
| */ |
| |
| BOOL audit(const char *volume) |
| { |
| BOOL err; |
| |
| err = FALSE; |
| if (!getuid() && open_security_api()) { |
| if (open_volume(volume,NTFS_MNT_RDONLY)) { |
| if (audit_sds(FALSE)) err = TRUE; |
| if (audit_sds(TRUE)) err = TRUE; |
| if (audit_sii()) err = TRUE; |
| if (audit_sdh()) err = TRUE; |
| if (opt_r) recurseshow("/"); |
| |
| audit_summary(); |
| close_volume(volume); |
| } |
| else { |
| fprintf(stderr,"Could not open volume %s\n",volume); |
| printerror(stdout); |
| err = TRUE; |
| } |
| close_security_api(); |
| } |
| else { |
| if (getuid()) |
| fprintf(stderr,"This is only possible as root\n"); |
| else fprintf(stderr,"Could not open security API\n"); |
| err = TRUE; |
| } |
| return (err); |
| } |
| |
| #endif |
| |
| #if POSIXACLS |
| |
| /* |
| * Encode a Posix ACL string |
| * [d:]{ugmo}:uid[:perms],... |
| */ |
| |
| struct POSIX_SECURITY *encode_posix_acl(const char *str) |
| { |
| int acccnt; |
| int defcnt; |
| int i,k,l; |
| int c; |
| s32 id; |
| u16 perms; |
| u16 apermsset; |
| u16 dpermsset; |
| u16 tag; |
| u16 tagsset; |
| mode_t mode; |
| BOOL defacl; |
| BOOL dmask; |
| BOOL amask; |
| const char *p; |
| struct POSIX_ACL *acl; |
| struct POSIX_SECURITY *pxdesc; |
| enum { PXBEGIN, PXTAG, PXTAG1, PXID, PXID1, PXID2, |
| PXPERM, PXPERM1, PXPERM2, PXOCT, PXNEXT, PXEND, PXERR |
| } state; |
| |
| /* raw evaluation of ACE count */ |
| p = str; |
| amask = FALSE; |
| dmask = FALSE; |
| if (*p == 'd') { |
| acccnt = 0; |
| defcnt = 1; |
| } else { |
| if ((*p >= '0') && (*p <= '7')) |
| acccnt = 0; |
| else |
| acccnt = 1; |
| defcnt = 0; |
| } |
| while (*p) |
| if (*p++ == ',') { |
| if (*p == 'd') { |
| defcnt++; |
| if (p[1] && (p[2] == 'm')) |
| dmask = TRUE; |
| } else { |
| acccnt++; |
| if (*p == 'm') |
| amask = TRUE; |
| } |
| } |
| /* account for an implicit mask if none defined */ |
| if (acccnt && !amask) |
| acccnt++; |
| if (defcnt && !dmask) |
| defcnt++; |
| pxdesc = (struct POSIX_SECURITY*)malloc(sizeof(struct POSIX_SECURITY) |
| + (acccnt + defcnt)*sizeof(struct POSIX_ACE)); |
| if (pxdesc) { |
| pxdesc->acccnt = acccnt; |
| pxdesc->firstdef = acccnt; |
| pxdesc->defcnt = defcnt; |
| acl = &pxdesc->acl; |
| p = str; |
| state = PXBEGIN; |
| id = 0; |
| defacl = FALSE; |
| mode = 0; |
| apermsset = 0; |
| dpermsset = 0; |
| tag = 0; |
| perms = 0; |
| k = l = 0; |
| c = *p++; |
| while ((state != PXEND) && (state != PXERR)) { |
| switch (state) { |
| case PXBEGIN : |
| if (c == 'd') { |
| defacl = TRUE; |
| state = PXTAG1; |
| break; |
| } else |
| if ((c >= '0') && (c <= '7')) { |
| mode = c - '0'; |
| state = PXOCT; |
| break; |
| } |
| defacl = FALSE; |
| /* fall through */ |
| case PXTAG : |
| switch (c) { |
| case 'u' : |
| tag = POSIX_ACL_USER; |
| state = PXID; |
| break; |
| case 'g' : |
| tag = POSIX_ACL_GROUP; |
| state = PXID; |
| break; |
| case 'o' : |
| tag = POSIX_ACL_OTHER; |
| state = PXID; |
| break; |
| case 'm' : |
| tag = POSIX_ACL_MASK; |
| state = PXID; |
| break; |
| default : |
| state = PXERR; |
| break; |
| } |
| break; |
| case PXTAG1 : |
| if (c == ':') |
| state = PXTAG; |
| else |
| state = PXERR; |
| break; |
| case PXID : |
| if (c == ':') { |
| if ((tag == POSIX_ACL_OTHER) |
| || (tag == POSIX_ACL_MASK)) |
| state = PXPERM; |
| else |
| state = PXID1; |
| } else |
| state = PXERR; |
| break; |
| case PXID1 : |
| if ((c >= '0') && (c <= '9')) { |
| id = c - '0'; |
| state = PXID2; |
| } else |
| if (c == ':') { |
| id = -1; |
| if (tag == POSIX_ACL_USER) |
| tag = POSIX_ACL_USER_OBJ; |
| if (tag == POSIX_ACL_GROUP) |
| tag = POSIX_ACL_GROUP_OBJ; |
| state = PXPERM1; |
| } else |
| state = PXERR; |
| break; |
| case PXID2 : |
| if ((c >= '0') && (c <= '9')) |
| id = 10*id + c - '0'; |
| else |
| if (c == ':') |
| state = PXPERM1; |
| else |
| state = PXERR; |
| break; |
| case PXPERM : |
| if (c == ':') { |
| id = -1; |
| state = PXPERM1; |
| } else |
| state = PXERR; |
| break; |
| case PXPERM1 : |
| if ((c >= '0') && (c <= '7')) { |
| perms = c - '0'; |
| state = PXNEXT; |
| break; |
| } |
| state = PXPERM2; |
| perms = 0; |
| /* fall through */ |
| case PXPERM2 : |
| switch (c) { |
| case 'r' : |
| perms |= POSIX_PERM_R; |
| break; |
| case 'w' : |
| perms |= POSIX_PERM_W; |
| break; |
| case 'x' : |
| perms |= POSIX_PERM_X; |
| break; |
| case ',' : |
| case '\0' : |
| if (defacl) { |
| i = acccnt + l++; |
| dpermsset |= perms; |
| } else { |
| i = k++; |
| apermsset |= perms; |
| } |
| acl->ace[i].tag = tag; |
| acl->ace[i].perms = perms; |
| acl->ace[i].id = id; |
| if (c == '\0') |
| state = PXEND; |
| else |
| state = PXBEGIN; |
| break; |
| } |
| break; |
| case PXNEXT : |
| if (!c || (c == ',')) { |
| if (defacl) { |
| i = acccnt + l++; |
| dpermsset |= perms; |
| } else { |
| i = k++; |
| apermsset |= perms; |
| } |
| acl->ace[i].tag = tag; |
| acl->ace[i].perms = perms; |
| acl->ace[i].id = id; |
| if (c == '\0') |
| state = PXEND; |
| else |
| state = PXBEGIN; |
| } else |
| state = PXERR; |
| break; |
| case PXOCT : |
| if ((c >= '0') && (c <= '7')) |
| mode = (mode << 3) + c - '0'; |
| else |
| if (c == '\0') |
| state = PXEND; |
| else |
| state = PXBEGIN; |
| break; |
| default : |
| break; |
| } |
| c = *p++; |
| } |
| /* insert default mask if none defined */ |
| if (acccnt && !amask) { |
| i = k++; |
| acl->ace[i].tag = POSIX_ACL_MASK; |
| acl->ace[i].perms = apermsset; |
| acl->ace[i].id = -1; |
| } |
| if (defcnt && !dmask) { |
| i = acccnt + l++; |
| acl->ace[i].tag = POSIX_ACL_MASK; |
| acl->ace[i].perms = dpermsset; |
| acl->ace[i].id = -1; |
| } |
| /* compute the mode and tagsset */ |
| tagsset = 0; |
| for (i=0; i<acccnt; i++) |
| tagsset |= acl->ace[i].tag; |
| switch (acl->ace[i].tag) { |
| case POSIX_ACL_USER_OBJ : |
| mode |= acl->ace[i].perms << 6; |
| break; |
| case POSIX_ACL_GROUP_OBJ : |
| mode |= acl->ace[i].perms << 3; |
| break; |
| case POSIX_ACL_OTHER : |
| mode |= acl->ace[i].perms; |
| break; |
| default : |
| break; |
| } |
| pxdesc->mode = mode; |
| pxdesc->tagsset = tagsset; |
| pxdesc->acl.version = POSIX_VERSION; |
| pxdesc->acl.flags = 0; |
| pxdesc->acl.filler = 0; |
| if (state != PXERR) |
| ntfs_sort_posix(pxdesc); |
| showposix(pxdesc); |
| if ((state == PXERR) |
| || (k != acccnt) |
| || (l != defcnt) |
| || !ntfs_valid_posix(pxdesc)) { |
| if (~pxdesc->tagsset |
| & (POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER)) |
| fprintf(stderr,"User, group or other permissions missing\n"); |
| else |
| fprintf(stderr,"Bad ACL description\n"); |
| free(pxdesc); |
| pxdesc = (struct POSIX_SECURITY*)NULL; |
| } else |
| if (opt_v >= 2) { |
| printf("Interpreted input description :\n"); |
| showposix(pxdesc); |
| } |
| } else |
| errno = ENOMEM; |
| return (pxdesc); |
| } |
| |
| #endif /* POSIXACLS */ |
| |
| |
| int getoptions(int argc, char *argv[]) |
| { |
| int xarg; |
| int narg; |
| const char *parg; |
| BOOL err; |
| |
| opt_a = FALSE; |
| opt_b = FALSE; |
| opt_e = FALSE; |
| opt_h = FALSE; |
| #if FORCEMASK |
| opt_m = FALSE; |
| #endif |
| opt_r = FALSE; |
| opt_s = FALSE; |
| #if SELFTESTS & !USESTUBS |
| opt_t = FALSE; |
| #endif |
| opt_u = FALSE; |
| opt_v = 0; |
| xarg = 1; |
| err = FALSE; |
| while ((xarg < argc) && (argv[xarg][0] == '-')) { |
| parg = argv[xarg++]; |
| while (*++parg) |
| switch (*parg) |
| { |
| #ifndef WIN32 |
| case 'a' : |
| opt_a = TRUE; |
| break; |
| #endif |
| case 'b' : |
| opt_b = TRUE; |
| break; |
| case 'e' : |
| opt_e = TRUE; |
| break; |
| case 'h' : |
| opt_h = TRUE; |
| break; |
| #if FORCEMASK |
| case 'm' : |
| opt_m = TRUE; |
| break; |
| #endif |
| case 'r' : |
| case 'R' : |
| opt_r = TRUE; |
| break; |
| case 's' : |
| opt_s = TRUE; |
| break; |
| #if SELFTESTS & !USESTUBS |
| case 't' : |
| opt_t = TRUE; |
| break; |
| #endif |
| case 'u' : |
| opt_u = TRUE; |
| break; |
| case 'v' : |
| opt_v++; |
| break; |
| default : |
| fprintf(stderr,"Invalid option -%c\n",*parg); |
| err = TRUE; |
| } |
| } |
| narg = argc - xarg; |
| #ifdef WIN32 |
| if ( ((opt_h || opt_s) && (narg > 1)) |
| || ((opt_r || opt_b || opt_u) && ((narg < 1) || (narg > 2))) |
| #if SELFTESTS & !USESTUBS |
| || (opt_t && (narg > 0)) |
| #endif |
| || (opt_e && !opt_s) |
| || (!opt_h && !opt_r && !opt_b && !opt_s |
| #if SELFTESTS & !USESTUBS |
| && !opt_t |
| #endif |
| && ((narg < 1) || (narg > 2)))) |
| |
| err = TRUE; |
| if (err) { |
| xarg = 0; |
| fprintf(stderr,"Usage:\n"); |
| #if SELFTESTS & !USESTUBS |
| fprintf(stderr," secaudit -t\n"); |
| fprintf(stderr," run self-tests\n"); |
| #endif |
| fprintf(stderr," secaudit -h [file]\n"); |
| fprintf(stderr," display security descriptors within file\n"); |
| fprintf(stderr," secaudit [-v] file\n"); |
| fprintf(stderr," display the security parameters of file\n"); |
| fprintf(stderr," secaudit -r[v] directory\n"); |
| fprintf(stderr," display the security parameters of files in directory\n"); |
| fprintf(stderr," secaudit -b[v] directory\n"); |
| fprintf(stderr," backup the security parameters of files in directory\n"); |
| fprintf(stderr," secaudit -s[ev] [backupfile]\n"); |
| fprintf(stderr," set the security parameters as indicated in backup file\n"); |
| fprintf(stderr," with -e also set extra parameters (Windows attrib)\n"); |
| fprintf(stderr," secaudit perms file\n"); |
| fprintf(stderr," set the security parameters of file to perms\n"); |
| fprintf(stderr," secaudit -r[v] perms directory\n"); |
| fprintf(stderr," set the security parameters of files in directory to perms\n"); |
| fprintf(stderr," secaudit -u file\n"); |
| fprintf(stderr," get a user mapping proposal applicable to file\n"); |
| #if POSIXACLS |
| fprintf(stderr," Note: perms can be an octal mode or a Posix ACL description\n"); |
| #else |
| fprintf(stderr," Note: perms is an octal mode\n"); |
| #endif |
| fprintf(stderr," -v is for verbose, -vv for very verbose\n"); |
| } |
| #else |
| if ( (opt_h && (narg > 1)) |
| || (opt_a && (narg != 1)) |
| || ((opt_r || opt_b || opt_s || opt_u) |
| && ((narg < 1) || (narg > 3))) |
| #if SELFTESTS & !USESTUBS |
| || (opt_t && (narg > 0)) |
| #endif |
| || (opt_e && !opt_s) |
| || (!opt_h && !opt_a && !opt_r && !opt_b && !opt_s && !opt_u |
| #if SELFTESTS & !USESTUBS |
| && !opt_t |
| #endif |
| #ifdef HAVE_SETXATTR |
| && ((narg < 1) || (narg > 3)))) |
| #else |
| && ((narg < 2) || (narg > 3)))) |
| #endif |
| err = TRUE; |
| if (err) { |
| xarg = 0; |
| fprintf(stderr,"Usage:\n"); |
| #if SELFTESTS & !USESTUBS |
| fprintf(stderr," secaudit -t\n"); |
| fprintf(stderr," run self-tests\n"); |
| #endif |
| fprintf(stderr," secaudit -h [file]\n"); |
| fprintf(stderr," display security descriptors within file\n"); |
| fprintf(stderr," secaudit -a[rv] volume\n"); |
| fprintf(stderr," audit the volume\n"); |
| fprintf(stderr," secaudit [-v] volume file\n"); |
| fprintf(stderr," display the security parameters of file\n"); |
| fprintf(stderr," secaudit -r[v] volume directory\n"); |
| fprintf(stderr," display the security parameters of files in directory\n"); |
| fprintf(stderr," secaudit -b[v] volume directory\n"); |
| fprintf(stderr," backup the security parameters of files in directory\n"); |
| fprintf(stderr," secaudit -s[ev] volume [backupfile]\n"); |
| fprintf(stderr," set the security parameters as indicated in backup file\n"); |
| fprintf(stderr," with -e also set extra parameters (Windows attrib)\n"); |
| fprintf(stderr," secaudit volume perms file\n"); |
| fprintf(stderr," set the security parameters of file to perms\n"); |
| fprintf(stderr," secaudit -r[v] volume perms directory\n"); |
| fprintf(stderr," set the security parameters of files in directory to perms\n"); |
| fprintf(stderr," secaudit -u volume file\n"); |
| fprintf(stderr," get a user mapping proposal applicable to file\n"); |
| #ifdef HAVE_SETXATTR |
| fprintf(stderr," special cases, do not require being root :\n"); |
| fprintf(stderr," secaudit -u mounted-file\n"); |
| fprintf(stderr," get a user mapping proposal applicable to mounted file\n"); |
| fprintf(stderr," secaudit [-v] mounted-file\n"); |
| fprintf(stderr," display the security parameters of a mounted file\n"); |
| #endif |
| #if POSIXACLS |
| fprintf(stderr," Note: perms can be an octal mode or a Posix ACL description\n"); |
| #else |
| fprintf(stderr," Note: perms is an octal mode\n"); |
| #endif |
| fprintf(stderr," -v is for verbose, -vv for very verbose\n"); |
| } |
| #endif |
| if ((sizeof(SID) != 12) && !err) { |
| fprintf(stderr,"Possible alignment problem, check your compiler options\n"); |
| err = TRUE; |
| xarg = 0; |
| } |
| return (xarg); |
| } |
| |
| /* |
| * Memory allocation with checks |
| */ |
| |
| #undef malloc |
| #undef calloc |
| #undef free |
| #undef isalloc |
| |
| void dumpalloc(const char *txt) |
| { |
| struct CHKALLOC *q; |
| |
| if (firstalloc) { |
| printf("alloc table at %s\n",txt); |
| for (q=firstalloc; q; q=q->next) |
| #ifdef __x86_64__ |
| printf("%08llx : %u bytes at %08llx allocated at %s line %d\n", |
| (long long)q,(unsigned int)q->size, |
| (long long)q->alloc,q->file,q->line); |
| #else |
| printf("%08lx : %u bytes at %08lx allocated at %s line %d\n", |
| (long)q,(unsigned int)q->size, |
| (long)q->alloc,q->file,q->line); |
| #endif |
| } |
| } |
| |
| void *chkmalloc(size_t size, const char *file, int line) |
| { |
| void *p; |
| struct CHKALLOC *q; |
| |
| p = (void*)malloc(size+1); |
| if (p) { |
| ((unsigned char*)p)[size] = 0xaa; |
| q = (struct CHKALLOC*)malloc(sizeof(struct CHKALLOC)); |
| if (q) { |
| q->next = firstalloc; |
| q->alloc = p; |
| q->size = size; |
| q->file = file; |
| q->line = line; |
| firstalloc = q; |
| } |
| } |
| return (p); |
| } |
| |
| void *chkcalloc(size_t cnt, size_t size, const char *file, int line) |
| { |
| return (chkmalloc(cnt*size,file,line)); |
| } |
| |
| void chkfree(void *p, const char *file, int line) |
| { |
| struct CHKALLOC *q; |
| struct CHKALLOC *r; |
| |
| if (p) { |
| if (firstalloc && (firstalloc->alloc == p)) { |
| r = firstalloc; |
| firstalloc = firstalloc->next; |
| } else { |
| q = firstalloc; |
| if (q) |
| while (q->next && (q->next->alloc != p)) |
| q = q->next; |
| if (q && q->next) { |
| r = q->next; |
| q->next = r->next; |
| } else { |
| r = (struct CHKALLOC*)NULL; |
| printf("** freeing unallocated memory in %s line %d\n",file,line); |
| if (!isatty(1)) |
| fprintf(stderr,"** freeing unallocated memory in %s line %d\n",file,line); |
| } |
| } |
| if (r) { |
| if (((unsigned char*)p)[r->size] != 0xaa) { |
| printf("** memory corruption, alloc in %s line %d release in %s %d\n", |
| r->file,r->line,file,line); |
| if (!isatty(1)) |
| fprintf(stderr,"** memory corruption, alloc in %s line %d release in %s %d\n", |
| r->file,r->line,file,line); |
| } |
| memset(p,0xaa,r->size); |
| free(r); |
| free(p); |
| } |
| } |
| } |
| |
| void *stdmalloc(size_t size) |
| { |
| return (malloc(size)); |
| } |
| |
| void stdfree(void *p) |
| { |
| free(p); |
| } |
| |
| BOOL chkisalloc(void *p, const char *file, int line) |
| { |
| struct CHKALLOC *q; |
| |
| if (p) { |
| q = firstalloc; |
| while (q && (q->alloc != p)) |
| q = q->next; |
| } else |
| q = (struct CHKALLOC*)NULL; |
| if (!p || !q) { |
| #ifdef __x86_64__ |
| printf("error in %s %d : 0x%llx not allocated\n",file,line, |
| (long long)p); |
| #else |
| printf("error in %s %d : 0x%lx not allocated\n",file,line, |
| (long)p); |
| #endif |
| } |
| return (p && q); |
| } |
| |
| |
| |
| |
| #ifdef WIN32 |
| |
| /* |
| * Windows version |
| */ |
| |
| main(argc,argv) |
| int argc; |
| char *argv[]; |
| { |
| FILE *fd; |
| int xarg; |
| int mode; |
| unsigned int size; |
| BOOL cmderr; |
| char *filename; |
| const char *p; |
| int i; |
| #if POSIXACLS |
| struct POSIX_SECURITY *pxdesc; |
| #endif |
| |
| printf("%s\n",BANNER); |
| cmderr = FALSE; |
| errors = 0; |
| warnings = 0; |
| xarg = getoptions(argc,argv); |
| if (xarg) { |
| for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
| securdata[i] = (struct SECURITY_DATA*)NULL; |
| #if POSIXACLS |
| context.mapping[MAPUSERS] = (struct MAPPING*)NULL; |
| context.mapping[MAPGROUPS] = (struct MAPPING*)NULL; |
| #endif |
| firstalloc = (struct CHKALLOC*)NULL; |
| mappingtype = MAPNONE; |
| switch (argc - xarg) { |
| case 0 : |
| if (opt_h) |
| showhex(stdin); |
| else |
| if (opt_s) |
| restore(stdin); |
| #if SELFTESTS & !USESTUBS |
| if (opt_t) |
| selftests(); |
| #endif |
| break; |
| case 1 : |
| if (opt_h || opt_s) { |
| fd = fopen(argv[xarg],"r"); |
| if (fd) { |
| if (opt_h) |
| showhex(fd); |
| else |
| restore(fd); |
| fclose(fd); |
| } else { |
| fprintf(stderr,"Could not open %s\n",argv[xarg]); |
| cmderr = TRUE; |
| } |
| } else { |
| size = utf16size(argv[xarg]); |
| if (size) { |
| filename = (char*)malloc(2*size + 2); |
| if (filename) { |
| makeutf16(filename,argv[xarg]); |
| if (opt_u) { |
| cmderr = mapproposal(filename); |
| } else { |
| #if POSIXACLS |
| if (local_build_mapping(context.mapping,filename)) { |
| printf("*** Could not get user mapping data\n"); |
| warnings++; |
| } |
| #endif |
| if (opt_b) |
| cmderr = backup(filename); |
| else { |
| if (opt_r) |
| cmderr = listfiles(filename); |
| else |
| cmderr = singleshow(filename); |
| } |
| #if POSIXACLS |
| ntfs_free_mapping(context.mapping); |
| #endif |
| } |
| free(filename); |
| } else { |
| fprintf(stderr,"No more memory\n"); |
| cmderr = TRUE; |
| } |
| } else { |
| fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg]); |
| cmderr = TRUE; |
| } |
| } |
| break; |
| case 2 : |
| mode = 0; |
| p = argv[xarg]; |
| #if POSIXACLS |
| pxdesc = encode_posix_acl(p); |
| if (pxdesc) { |
| size = utf16size(argv[xarg + 1]); |
| if (size) { |
| filename = (char*)malloc(2*size + 2); |
| if (filename) { |
| makeutf16(filename,argv[xarg + 1]); |
| if (local_build_mapping(context.mapping,filename)) { |
| printf("*** Could not get user mapping data\n"); |
| warnings++; |
| } |
| if (opt_r) { |
| for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
| securdata[i] = (struct SECURITY_DATA*)NULL; |
| recurseset_posix(filename,pxdesc); |
| } else |
| singleset_posix(filename,pxdesc); |
| ntfs_free_mapping(context.mapping); |
| free(filename); |
| } else { |
| fprintf(stderr,"No more memory\n"); |
| cmderr = TRUE; |
| } |
| chkfree(pxdesc,__FILE__,__LINE__); |
| } else { |
| fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg + 1]); |
| cmderr = TRUE; |
| } |
| } |
| #else |
| while ((*p >= '0') && (*p <= '7')) |
| mode = (mode << 3) + (*p++) - '0'; |
| if (*p) { |
| fprintf(stderr,"New mode should be given in octal\n"); |
| cmderr = TRUE; |
| } else { |
| size = utf16size(argv[xarg + 1]); |
| if (size) { |
| filename = (char*)malloc(2*size + 2); |
| if (filename) { |
| makeutf16(filename,argv[xarg + 1]); |
| #if POSIXACLS |
| if (local_build_mapping(&context,filename)) { |
| printf("*** Could not get user mapping data\n"); |
| warnings++; |
| } |
| #endif |
| if (opt_r) { |
| for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
| securdata[i] = (struct SECURITY_DATA*)NULL; |
| recurseset(filename,mode); |
| } else |
| singleset(filename,mode); |
| free(filename); |
| } else { |
| fprintf(stderr,"No more memory\n"); |
| cmderr = TRUE; |
| } |
| } else { |
| fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg + 1]); |
| cmderr = TRUE; |
| } |
| } |
| #endif |
| break; |
| #if FORCEMASK |
| case 3 : |
| mode = 0; |
| forcemsk = 0; |
| p = argv[xarg]; |
| while (*p) { |
| if ((*p >= '0') && (*p <= '9')) |
| forcemsk = (forcemsk << 4) + *p - '0'; |
| else forcemsk = (forcemsk << 4) + (*p & 7) + 9; |
| p++; |
| } |
| p = argv[xarg + 1]; |
| while ((*p >= '0') && (*p <= '7')) |
| mode = (mode << 3) + (*p++) - '0'; |
| if (*p) { |
| fprintf(stderr,"New mode should be given in octal\n"); |
| cmderr = TRUE; |
| } else { |
| if (opt_r) { |
| recurseset(argv[xarg + 2],mode); |
| } |
| else singleset(argv[xarg + 2],mode); |
| } |
| break; |
| #endif |
| } |
| if (warnings) |
| printf("** %u %s signalled\n",warnings, |
| (warnings > 1 ? "warnings were" : "warning was")); |
| if (errors) |
| printf("** %u %s found\n",errors, |
| (errors > 1 ? "errors were" : "error was")); |
| else |
| if (!cmderr) |
| printf("No errors were found\n"); |
| if (!isatty(1)) { |
| fflush(stdout); |
| if (warnings) |
| fprintf(stderr,"** %u %s signalled\n",warnings, |
| (warnings > 1 ? "warnings were" : "warning was")); |
| if (errors) |
| fprintf(stderr,"** %u %s found\n",errors, |
| (errors > 1 ? "errors were" : "error was")); |
| else |
| fprintf(stderr,"No errors were found\n"); |
| freeblocks(); |
| } |
| } |
| dumpalloc("termination"); |
| if (cmderr || errors) |
| exit(1); |
| return (0); |
| } |
| |
| #else |
| |
| /* |
| * Linux version |
| */ |
| |
| int main(int argc, char *argv[]) |
| { |
| FILE *fd; |
| const char *p; |
| int xarg; |
| BOOL cmderr; |
| int i; |
| #if POSIXACLS |
| struct POSIX_SECURITY *pxdesc; |
| #else |
| unsigned int mode; |
| #endif |
| |
| printf("%s\n",BANNER); |
| cmderr = FALSE; |
| errors = 0; |
| warnings = 0; |
| xarg = getoptions(argc,argv); |
| if (xarg) { |
| for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
| securdata[i] = (struct SECURITY_DATA*)NULL; |
| #if POSIXACLS |
| context.mapping[MAPUSERS] = (struct MAPPING*)NULL; |
| context.mapping[MAPGROUPS] = (struct MAPPING*)NULL; |
| #endif |
| firstalloc = (struct CHKALLOC*)NULL; |
| mappingtype = MAPNONE; |
| switch (argc - xarg) { |
| case 0 : |
| if (opt_h) |
| showhex(stdin); |
| #if SELFTESTS & !USESTUBS |
| if (opt_t) |
| selftests(); |
| #endif |
| break; |
| case 1 : |
| if (opt_a) |
| cmderr = audit(argv[xarg]); |
| else |
| if (opt_h) { |
| fd = fopen(argv[xarg],"rb"); |
| if (fd) { |
| showhex(fd); |
| fclose(fd); |
| } else { |
| fprintf(stderr,"Could not open %s\n",argv[xarg]); |
| cmderr = TRUE; |
| } |
| } else |
| if (opt_b) |
| cmderr = backup(argv[xarg],"/"); |
| else |
| if (opt_r) |
| cmderr = listfiles(argv[xarg],"/"); |
| else |
| if (opt_s) |
| cmderr = dorestore(argv[xarg],stdin); |
| else |
| cmderr = processmounted(argv[xarg]); |
| break; |
| case 2 : |
| if (opt_b) |
| cmderr = backup(argv[xarg],argv[xarg+1]); |
| else |
| if (opt_s) { |
| fd = fopen(argv[xarg+1],"rb"); |
| if (fd) { |
| if (dorestore(argv[xarg],fd)) |
| cmderr = TRUE; |
| fclose(fd); |
| } else { |
| fprintf(stderr,"Could not open %s\n",argv[xarg]); |
| cmderr = TRUE; |
| } |
| } else |
| if (opt_u) |
| cmderr = mapproposal(argv[xarg],argv[xarg+1]); |
| else |
| cmderr = listfiles(argv[xarg],argv[xarg+1]); |
| break; |
| case 3 : |
| p = argv[xarg+1]; |
| #if POSIXACLS |
| pxdesc = encode_posix_acl(p); |
| if (pxdesc) { |
| if (!getuid() && open_security_api()) { |
| if (open_volume(argv[xarg],NTFS_MNT_NONE)) { |
| if (opt_r) { |
| for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
| securdata[i] = (struct SECURITY_DATA*)NULL; |
| recurseset_posix(argv[xarg + 2],pxdesc); |
| } else |
| singleset_posix(argv[xarg + 2],pxdesc); |
| close_volume(argv[xarg]); |
| } else { |
| fprintf(stderr,"Could not open volume %s\n",argv[xarg]); |
| printerror(stderr); |
| cmderr = TRUE; |
| } |
| close_security_api(); |
| } else { |
| if (getuid()) |
| fprintf(stderr,"This is only possible as root\n"); |
| else |
| fprintf(stderr,"Could not open security API\n"); |
| cmderr = TRUE; |
| } |
| chkfree(pxdesc,__FILE__,__LINE__); |
| } else |
| cmderr = TRUE; |
| #else |
| mode = 0; |
| while ((*p >= '0') && (*p <= '7')) |
| mode = (mode << 3) + (*p++) - '0'; |
| if (*p) { |
| fprintf(stderr,"New mode should be given in octal\n"); |
| cmderr = TRUE; |
| } else |
| if (!getuid() && open_security_api()) { |
| if (open_volume(argv[xarg],NTFS_MNT_NONE)) { |
| if (opt_r) { |
| for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) |
| securdata[i] = (struct SECURITY_DATA*)NULL; |
| recurseset(argv[xarg + 2],mode); |
| } else |
| singleset(argv[xarg + 2],mode); |
| close_volume(argv[xarg]); |
| } else { |
| fprintf(stderr,"Could not open volume %s\n",argv[xarg]); |
| printerror(stderr); |
| cmderr = TRUE; |
| } |
| close_security_api(); |
| } else { |
| if (getuid()) |
| fprintf(stderr,"This is only possible as root\n"); |
| else |
| fprintf(stderr,"Could not open security API\n"); |
| cmderr = TRUE; |
| } |
| #endif |
| break; |
| } |
| if (warnings) |
| printf("** %u %s signalled\n",warnings, |
| (warnings > 1 ? "warnings were" : "warning was")); |
| if (errors) |
| printf("** %u %s found\n",errors, |
| (errors > 1 ? "errors were" : "error was")); |
| else |
| if (!cmderr) |
| printf("No errors were found\n"); |
| if (!isatty(1)) { |
| fflush(stdout); |
| if (warnings) |
| fprintf(stderr,"** %u %s signalled\n",warnings, |
| (warnings > 1 ? "warnings were" : "warning was")); |
| if (errors) |
| fprintf(stderr,"** %u %s found\n",errors, |
| (errors > 1 ? "errors were" : "error was")); |
| else |
| if (!cmderr) |
| fprintf(stderr,"No errors were found\n"); |
| } |
| freeblocks(); |
| } else |
| cmderr = TRUE; |
| dumpalloc("termination"); |
| if (cmderr || errors) |
| exit(1); |
| return (0); |
| } |
| |
| #endif |