"Fossies" - the Fresh Open Source Software Archive

Member "ntfs-3g_ntfsprogs-2017.3.23/ntfsprogs/ntfssecaudit.c" (23 Mar 2017, 157379 Bytes) of package /linux/misc/ntfs-3g_ntfsprogs-2017.3.23.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ntfssecaudit.c" see the Fossies "Dox" file reference documentation.

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