test/jdk/sun/management/windows/revokeall.c
changeset 54987 2ffbc00d87ae
parent 54986 3b4ecc4180e0
child 54988 dd15cec077fc
equal deleted inserted replaced
54986:3b4ecc4180e0 54987:2ffbc00d87ae
     1 /*
       
     2  * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 #include <stdio.h>
       
    25 #include <windows.h>
       
    26 #include <malloc.h>
       
    27 #include <string.h>
       
    28 
       
    29 /*
       
    30  * Simple Windows utility to remove all non-owner access to a given
       
    31  * file - suitable for NT/2000/XP only.
       
    32  */
       
    33 
       
    34 
       
    35 /*
       
    36  * Access mask to represent any file access
       
    37  */
       
    38 #define ANY_ACCESS (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE)
       
    39 
       
    40 
       
    41 /*
       
    42  * Print error message to stderr
       
    43  */
       
    44 static void printLastError(const char* msg) {
       
    45     int len;
       
    46     char buf[128];
       
    47     DWORD errval;
       
    48 
       
    49     buf[0] = '\0';
       
    50     len = sizeof(buf);
       
    51 
       
    52     errval = GetLastError();
       
    53     if (errval != 0) {
       
    54         int n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
       
    55                               NULL, errval,
       
    56                               0, buf, len, NULL);
       
    57         if (n > 3) {
       
    58             /* Drop final '.', CR, LF */
       
    59             if (buf[n - 1] == '\n') n--;
       
    60             if (buf[n - 1] == '\r') n--;
       
    61             if (buf[n - 1] == '.') n--;
       
    62             buf[n] = '\0';
       
    63         }
       
    64     }
       
    65 
       
    66     if (strlen(buf) > 0) {
       
    67         fprintf(stderr, "revokeall %s: %s\n", msg, buf);
       
    68     } else {
       
    69         fprintf(stderr, "revokeall %s\n", msg);
       
    70     }
       
    71 }
       
    72 
       
    73 
       
    74 
       
    75 /*
       
    76  * Return a string that includes all the components of a given SID.
       
    77  * See here for a description of the SID components :-
       
    78  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/sid_components.asp
       
    79  */
       
    80 static char *getTextualSid(SID* sid) {
       
    81     SID_IDENTIFIER_AUTHORITY* sia;
       
    82     DWORD i, count;
       
    83     DWORD len;
       
    84     char* name;
       
    85 
       
    86     /*
       
    87      * Get the identifier authority and the number of sub-authorities
       
    88      */
       
    89     sia = GetSidIdentifierAuthority(sid);
       
    90     count = *GetSidSubAuthorityCount(sid);
       
    91 
       
    92     /*
       
    93      * Allocate buffer for the string - buffer is :-
       
    94      * S-SID_REVISION- + identifierAuthority- + subauthorities- + NULL
       
    95      */
       
    96     len=(15 + 12 + (12 * count) + 1) * sizeof(char);
       
    97     name = (char*)malloc(len);
       
    98     if (name == NULL) {
       
    99         return NULL;
       
   100     }
       
   101 
       
   102     // S-SID_REVISION
       
   103     sprintf(name, "S-%lu-", SID_REVISION );
       
   104 
       
   105     // Identifier authority
       
   106     if ((sia->Value[0] != 0) || (sia->Value[1] != 0))
       
   107     {
       
   108         sprintf(name + strlen(name), "0x%02hx%02hx%02hx%02hx%02hx%02hx",
       
   109                 (USHORT)sia->Value[0],
       
   110                 (USHORT)sia->Value[1],
       
   111                 (USHORT)sia->Value[2],
       
   112                 (USHORT)sia->Value[3],
       
   113                 (USHORT)sia->Value[4],
       
   114                 (USHORT)sia->Value[5]);
       
   115     }
       
   116     else
       
   117     {
       
   118         sprintf(name + strlen(name), "%lu",
       
   119                 (ULONG)(sia->Value[5]      )   +
       
   120                 (ULONG)(sia->Value[4] <<  8)   +
       
   121                 (ULONG)(sia->Value[3] << 16)   +
       
   122                 (ULONG)(sia->Value[2] << 24)   );
       
   123     }
       
   124 
       
   125     // finally, the sub-authorities
       
   126     for (i=0 ; i<count; i++) {
       
   127         sprintf(name + strlen(name), "-%lu",
       
   128                 *GetSidSubAuthority(sid, i) );
       
   129     }
       
   130 
       
   131     return name;
       
   132 }
       
   133 
       
   134 /*
       
   135  * Returns a string to represent the given security identifier (SID).
       
   136  * If the account is known to the local computer then the account
       
   137  * domain is returned. The format will be \\name or domain\\name depending
       
   138  * on if the computer belongs to a domain.
       
   139  * If the account name is not known then the textual representation of
       
   140  * SID is returned -- eg: S-1-5-21-2818032319-470147023-1036452850-13037.
       
   141  */
       
   142 static char *getSIDString(SID* sid) {
       
   143     char domain[255];
       
   144     char name[255];
       
   145     DWORD domainLen = sizeof(domain);
       
   146     DWORD nameLen = sizeof(name);
       
   147     SID_NAME_USE use;
       
   148 
       
   149     if(!IsValidSid(sid)) {
       
   150         return strdup("<Invalid SID>");
       
   151     }
       
   152 
       
   153     if (LookupAccountSid(NULL, sid, name, &nameLen, domain, &domainLen, &use)) {
       
   154         int len = strlen(name) + strlen(domain) + 3;
       
   155         char* s = (char*)malloc(len);
       
   156         if (s != NULL) {
       
   157             strcpy(s, domain);
       
   158             strcat(s, "\\\\");
       
   159             strcat(s, name);
       
   160         }
       
   161         return s;
       
   162     } else {
       
   163         return getTextualSid(sid);
       
   164     }
       
   165 }
       
   166 
       
   167 
       
   168 
       
   169 /*
       
   170  * Returns 1 if the specified file is on a file system that supports
       
   171  * persistent ACLs (On NTFS file systems returns true, on FAT32 file systems
       
   172  * returns false), otherwise 0. Returns -1 if error.
       
   173  */
       
   174 static int isSecuritySupported(const char* path) {
       
   175     char* root;
       
   176     char* p;
       
   177     BOOL res;
       
   178     DWORD dwMaxComponentLength;
       
   179     DWORD dwFlags;
       
   180     char fsName[128];
       
   181     DWORD fsNameLength;
       
   182 
       
   183     /*
       
   184      * Get root directory. For UNCs the slash after the share name is required.
       
   185      */
       
   186     root = strdup(path);
       
   187     if (*root == '\\') {
       
   188         /*
       
   189          * \\server\share\file ==> \\server\share\
       
   190          */
       
   191         int slashskip = 3;
       
   192         p = root;
       
   193         while ((*p == '\\') && (slashskip > 0)) {
       
   194             char* p2;
       
   195             p++;
       
   196             p2 = strchr(p, '\\');
       
   197             if ((p2 == NULL) || (*p2 != '\\')) {
       
   198                 free(root);
       
   199                 fprintf(stderr, "Malformed UNC");
       
   200                 return -1;
       
   201             }
       
   202             p = p2;
       
   203             slashskip--;
       
   204         }
       
   205         if (slashskip != 0) {
       
   206             free(root);
       
   207             fprintf(stderr, "Malformed UNC");
       
   208             return -1;
       
   209         }
       
   210         p++;
       
   211         *p = '\0';
       
   212 
       
   213     } else {
       
   214         p = strchr(root, '\\');
       
   215 
       
   216         /*
       
   217          * Relative path so use current directory
       
   218          */
       
   219         if (p == NULL) {
       
   220             free(root);
       
   221             root = malloc(255);
       
   222             if (GetCurrentDirectory(255, root) == 0) {
       
   223                 printLastError("GetCurrentDirectory failed");
       
   224                 return -1;
       
   225             }
       
   226             p = strchr(root, '\\');
       
   227             if (p == NULL) {
       
   228                 fprintf(stderr, "GetCurrentDirectory doesn't include drive letter!!!!\n");
       
   229                 return -1;
       
   230             }
       
   231         }
       
   232         p++;
       
   233         *p = '\0';
       
   234     }
       
   235 
       
   236     /*
       
   237      * Get the volume information - this gives us the file system file and
       
   238      * also tells us if the file system supports persistent ACLs.
       
   239      */
       
   240     fsNameLength = sizeof(fsName)-1;
       
   241     res = GetVolumeInformation(root,
       
   242                                NULL,        // address of name of the volume, can be NULL
       
   243                                0,           // length of volume name
       
   244                                NULL,        // address of volume serial number, can be NULL
       
   245                                &dwMaxComponentLength,
       
   246                                &dwFlags,
       
   247                                fsName,
       
   248                                fsNameLength);
       
   249     if (res == 0) {
       
   250         printLastError("GetVolumeInformation failed");
       
   251         free(root);
       
   252         return -1;
       
   253     }
       
   254 
       
   255     free(root);
       
   256     return (dwFlags & FS_PERSISTENT_ACLS) ? 1 : 0;
       
   257 }
       
   258 
       
   259 
       
   260 /*
       
   261  * Returns the security descriptor for a file.
       
   262  */
       
   263 static SECURITY_DESCRIPTOR* getFileSecurityDescriptor(const char* path) {
       
   264     SECURITY_DESCRIPTOR* sd;
       
   265     DWORD len = 0;
       
   266     SECURITY_INFORMATION info =
       
   267         OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
       
   268 
       
   269     GetFileSecurity(path, info , 0, 0, &len);
       
   270     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
       
   271         printLastError("GetFileSecurity failed");
       
   272         return NULL;
       
   273     }
       
   274     sd = (SECURITY_DESCRIPTOR *)malloc(len);
       
   275     if (sd == NULL) {
       
   276         fprintf(stderr, "Out of memory");
       
   277     } else {
       
   278         if (!GetFileSecurity(path, info, sd, len, &len)) {
       
   279             printLastError("GetFileSecurity failed");
       
   280             free(sd);
       
   281             return NULL;
       
   282         }
       
   283     }
       
   284     return sd;
       
   285 }
       
   286 
       
   287 
       
   288 /*
       
   289  * Revoke all access to the specific file
       
   290  */
       
   291 static int revokeAll(const char* path) {
       
   292     SECURITY_DESCRIPTOR* sd;
       
   293     SID* owner;
       
   294     ACL *acl;
       
   295     BOOL defaulted, present;
       
   296     ACL_SIZE_INFORMATION acl_size_info;
       
   297     DWORD i, count;
       
   298     char* str;
       
   299 
       
   300     /*
       
   301      * Get security descriptor for file; From security descriptor get the
       
   302      * owner SID, and the DACL.
       
   303      */
       
   304     sd = getFileSecurityDescriptor(path);
       
   305     if (sd == NULL) {
       
   306         return -1;      /* error already reported */
       
   307     }
       
   308     if (!GetSecurityDescriptorOwner(sd, &owner, &defaulted)) {
       
   309         printLastError("GetSecurityDescriptorOwner failed");
       
   310         return -1;
       
   311     }
       
   312     str = getSIDString(owner);
       
   313     if (str != NULL) {
       
   314         printf("owner: %s\n", str);
       
   315         free(str);
       
   316     }
       
   317     if (!GetSecurityDescriptorDacl(sd, &present, &acl, &defaulted)) {
       
   318         printLastError("GetSecurityDescriptorDacl failed");
       
   319         return -1;
       
   320     }
       
   321     if (!present) {
       
   322         fprintf(stderr, "Security descriptor does not contain a DACL");
       
   323         return -1;
       
   324     }
       
   325 
       
   326     /*
       
   327      * If DACL is NULL there is no access to the file - we are done
       
   328      */
       
   329     if (acl == NULL) {
       
   330         return 1;
       
   331     }
       
   332 
       
   333     /*
       
   334      * Iterate over the ACEs. For each "allow" type check that the SID
       
   335      * matches the owner - if not we remove the ACE from the ACL
       
   336      */
       
   337     if (!GetAclInformation(acl, (void *) &acl_size_info, sizeof(acl_size_info),
       
   338                                   AclSizeInformation)) {
       
   339         printLastError("GetAclInformation failed");
       
   340         return -1;
       
   341     }
       
   342     count = acl_size_info.AceCount;
       
   343     i = 0;
       
   344     while (count > 0) {
       
   345         void* ace;
       
   346         ACCESS_ALLOWED_ACE *access;
       
   347         SID* sid;
       
   348         BOOL deleted;
       
   349 
       
   350         if (!GetAce(acl, i, &ace)) {
       
   351             printLastError("GetAce failed");
       
   352             return -1;
       
   353         }
       
   354         if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
       
   355             continue;
       
   356         }
       
   357         access = (ACCESS_ALLOWED_ACE *)ace;
       
   358         sid = (SID *) &access->SidStart;
       
   359 
       
   360 
       
   361         deleted = FALSE;
       
   362         if (!EqualSid(owner, sid)) {
       
   363             /*
       
   364              * If the ACE allows any access then the file then we
       
   365              * delete it.
       
   366              */
       
   367             if (access->Mask & ANY_ACCESS) {
       
   368                 str = getSIDString(sid);
       
   369                 if (str != NULL) {
       
   370                     printf("remove ALLOW %s\n", str);
       
   371                     free(str);
       
   372                 }
       
   373                 if (DeleteAce(acl, i) == 0) {
       
   374                     printLastError("DeleteAce failed");
       
   375                     return -1;
       
   376                 }
       
   377                 deleted = TRUE;
       
   378             }
       
   379         }
       
   380 
       
   381         if (!deleted) {
       
   382             str = getSIDString(sid);
       
   383             if (str != NULL) {
       
   384                 printf("ALLOW %s (access mask=%x)\n", str, access->Mask);
       
   385                 free(str);
       
   386             }
       
   387 
       
   388             /* onto the next ACE */
       
   389             i++;
       
   390         }
       
   391         count--;
       
   392     }
       
   393 
       
   394     /*
       
   395      * No changes - only owner has access
       
   396      */
       
   397     if (i == acl_size_info.AceCount) {
       
   398         printf("No changes.\n");
       
   399         return 1;
       
   400     }
       
   401 
       
   402     /*
       
   403      * Create security descriptor and set its DACL to the version
       
   404      * that we just edited
       
   405      */
       
   406     if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
       
   407         printLastError("InitializeSecurityDescriptor failed");
       
   408         return -1;
       
   409     }
       
   410     if (!SetSecurityDescriptorDacl(sd, present, acl, defaulted)) {
       
   411         printLastError("SetSecurityDescriptorDacl failed");
       
   412         return -1;
       
   413     }
       
   414     if (!SetFileSecurity(path, DACL_SECURITY_INFORMATION, sd)) {
       
   415         printLastError("SetFileSecurity failed");
       
   416         return -1;
       
   417     }
       
   418 
       
   419     printf("File updated.\n");
       
   420 
       
   421     return 1;
       
   422 }
       
   423 
       
   424 /*
       
   425  * Convert slashes in the pathname to backslashes if needed.
       
   426  */
       
   427 static char* convert_path(const char* p) {
       
   428    int i = 0;
       
   429    char* path = strdup(p);
       
   430    while (p[i] != '\0') {
       
   431        if (p[i] == '/') {
       
   432            path[i] = '\\';
       
   433        }
       
   434        i++;
       
   435    }
       
   436    return path;
       
   437 }
       
   438 
       
   439 /*
       
   440  * Usage: revokeall file
       
   441  */
       
   442 int main( int argc, char *argv[])
       
   443 {
       
   444     int rc;
       
   445     const char* path;
       
   446 
       
   447     if (argc != 2) {
       
   448         fprintf(stderr, "Usage: %s file\n", argv[0]);
       
   449         return -1;
       
   450     }
       
   451     path = convert_path(argv[1]);
       
   452     printf("Revoking all non-owner access to %s\n", path);
       
   453     rc = isSecuritySupported(path);
       
   454     if (rc != 1) {
       
   455         if (rc == 0) {
       
   456             printf("File security not supported on this file system\n");
       
   457         }
       
   458         return rc;
       
   459     } else {
       
   460         return revokeAll(path);
       
   461     }
       
   462 }