Path: blob/master/test/jdk/sun/management/windows/exerevokeall.c
41149 views
/*1* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223#include <stdio.h>24#include <windows.h>25#include <malloc.h>26#include <string.h>2728/*29* Simple Windows utility to remove all non-owner access to a given file.30*/313233/*34* Access mask to represent any file access35*/36#define ANY_ACCESS (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE)373839/*40* Print error message to stderr41*/42static void printLastError(const char* msg) {43int len;44char buf[128];45DWORD errval;4647buf[0] = '\0';48len = sizeof(buf);4950errval = GetLastError();51if (errval != 0) {52int n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,53NULL, errval,540, buf, len, NULL);55if (n > 3) {56/* Drop final '.', CR, LF */57if (buf[n - 1] == '\n') n--;58if (buf[n - 1] == '\r') n--;59if (buf[n - 1] == '.') n--;60buf[n] = '\0';61}62}6364if (strlen(buf) > 0) {65fprintf(stderr, "revokeall %s: %s\n", msg, buf);66} else {67fprintf(stderr, "revokeall %s\n", msg);68}69}70717273/*74* Return a string that includes all the components of a given SID.75* See here for a description of the SID components :-76* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/sid_components.asp77*/78static char *getTextualSid(SID* sid) {79SID_IDENTIFIER_AUTHORITY* sia;80DWORD i, count;81DWORD len;82char* name;8384/*85* Get the identifier authority and the number of sub-authorities86*/87sia = GetSidIdentifierAuthority(sid);88count = *GetSidSubAuthorityCount(sid);8990/*91* Allocate buffer for the string - buffer is :-92* S-SID_REVISION- + identifierAuthority- + subauthorities- + NULL93*/94len=(15 + 12 + (12 * count) + 1) * sizeof(char);95name = (char*)malloc(len);96if (name == NULL) {97return NULL;98}99100// S-SID_REVISION101sprintf(name, "S-%lu-", SID_REVISION );102103// Identifier authority104if ((sia->Value[0] != 0) || (sia->Value[1] != 0))105{106sprintf(name + strlen(name), "0x%02hx%02hx%02hx%02hx%02hx%02hx",107(USHORT)sia->Value[0],108(USHORT)sia->Value[1],109(USHORT)sia->Value[2],110(USHORT)sia->Value[3],111(USHORT)sia->Value[4],112(USHORT)sia->Value[5]);113}114else115{116sprintf(name + strlen(name), "%lu",117(ULONG)(sia->Value[5] ) +118(ULONG)(sia->Value[4] << 8) +119(ULONG)(sia->Value[3] << 16) +120(ULONG)(sia->Value[2] << 24) );121}122123// finally, the sub-authorities124for (i=0 ; i<count; i++) {125sprintf(name + strlen(name), "-%lu",126*GetSidSubAuthority(sid, i) );127}128129return name;130}131132/*133* Returns a string to represent the given security identifier (SID).134* If the account is known to the local computer then the account135* domain is returned. The format will be \\name or domain\\name depending136* on if the computer belongs to a domain.137* If the account name is not known then the textual representation of138* SID is returned -- eg: S-1-5-21-2818032319-470147023-1036452850-13037.139*/140static char *getSIDString(SID* sid) {141char domain[255];142char name[255];143DWORD domainLen = sizeof(domain);144DWORD nameLen = sizeof(name);145SID_NAME_USE use;146147if(!IsValidSid(sid)) {148return strdup("<Invalid SID>");149}150151if (LookupAccountSid(NULL, sid, name, &nameLen, domain, &domainLen, &use)) {152size_t len = strlen(name) + strlen(domain) + 3;153char* s = (char*)malloc(len);154if (s != NULL) {155strcpy(s, domain);156strcat(s, "\\\\");157strcat(s, name);158}159return s;160} else {161return getTextualSid(sid);162}163}164165166167/*168* Returns 1 if the specified file is on a file system that supports169* persistent ACLs (On NTFS file systems returns true, on FAT32 file systems170* returns false), otherwise 0. Returns -1 if error.171*/172static int isSecuritySupported(const char* path) {173char* root;174char* p;175BOOL res;176DWORD dwMaxComponentLength;177DWORD dwFlags;178char fsName[128];179DWORD fsNameLength;180181/*182* Get root directory. For UNCs the slash after the share name is required.183*/184root = strdup(path);185if (*root == '\\') {186/*187* \\server\share\file ==> \\server\share\188*/189int slashskip = 3;190p = root;191while ((*p == '\\') && (slashskip > 0)) {192char* p2;193p++;194p2 = strchr(p, '\\');195if ((p2 == NULL) || (*p2 != '\\')) {196free(root);197fprintf(stderr, "Malformed UNC");198return -1;199}200p = p2;201slashskip--;202}203if (slashskip != 0) {204free(root);205fprintf(stderr, "Malformed UNC");206return -1;207}208p++;209*p = '\0';210211} else {212p = strchr(root, '\\');213214/*215* Relative path so use current directory216*/217if (p == NULL) {218free(root);219root = malloc(255);220if (GetCurrentDirectory(255, root) == 0) {221printLastError("GetCurrentDirectory failed");222return -1;223}224p = strchr(root, '\\');225if (p == NULL) {226fprintf(stderr, "GetCurrentDirectory doesn't include drive letter!!!!\n");227return -1;228}229}230p++;231*p = '\0';232}233234/*235* Get the volume information - this gives us the file system file and236* also tells us if the file system supports persistent ACLs.237*/238fsNameLength = sizeof(fsName)-1;239res = GetVolumeInformation(root,240NULL, // address of name of the volume, can be NULL2410, // length of volume name242NULL, // address of volume serial number, can be NULL243&dwMaxComponentLength,244&dwFlags,245fsName,246fsNameLength);247if (res == 0) {248printLastError("GetVolumeInformation failed");249free(root);250return -1;251}252253free(root);254return (dwFlags & FS_PERSISTENT_ACLS) ? 1 : 0;255}256257258/*259* Returns the security descriptor for a file.260*/261static SECURITY_DESCRIPTOR* getFileSecurityDescriptor(const char* path) {262SECURITY_DESCRIPTOR* sd;263DWORD len = 0;264SECURITY_INFORMATION info =265OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;266267GetFileSecurity(path, info , 0, 0, &len);268if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {269printLastError("GetFileSecurity failed");270return NULL;271}272sd = (SECURITY_DESCRIPTOR *)malloc(len);273if (sd == NULL) {274fprintf(stderr, "Out of memory");275} else {276if (!GetFileSecurity(path, info, sd, len, &len)) {277printLastError("GetFileSecurity failed");278free(sd);279return NULL;280}281}282return sd;283}284285286/*287* Revoke all access to the specific file288*/289static int revokeAll(const char* path) {290SECURITY_DESCRIPTOR* sd;291SID* owner;292ACL *acl;293BOOL defaulted, present;294ACL_SIZE_INFORMATION acl_size_info;295DWORD i, count;296char* str;297298/*299* Get security descriptor for file; From security descriptor get the300* owner SID, and the DACL.301*/302sd = getFileSecurityDescriptor(path);303if (sd == NULL) {304return -1; /* error already reported */305}306if (!GetSecurityDescriptorOwner(sd, &owner, &defaulted)) {307printLastError("GetSecurityDescriptorOwner failed");308return -1;309}310str = getSIDString(owner);311if (str != NULL) {312printf("owner: %s\n", str);313free(str);314}315if (!GetSecurityDescriptorDacl(sd, &present, &acl, &defaulted)) {316printLastError("GetSecurityDescriptorDacl failed");317return -1;318}319if (!present) {320fprintf(stderr, "Security descriptor does not contain a DACL");321return -1;322}323324/*325* If DACL is NULL there is no access to the file - we are done326*/327if (acl == NULL) {328return 1;329}330331/*332* Iterate over the ACEs. For each "allow" type check that the SID333* matches the owner - if not we remove the ACE from the ACL334*/335if (!GetAclInformation(acl, (void *) &acl_size_info, sizeof(acl_size_info),336AclSizeInformation)) {337printLastError("GetAclInformation failed");338return -1;339}340count = acl_size_info.AceCount;341i = 0;342while (count > 0) {343void* ace;344ACCESS_ALLOWED_ACE *access;345SID* sid;346BOOL deleted;347348if (!GetAce(acl, i, &ace)) {349printLastError("GetAce failed");350return -1;351}352if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {353i++;354count--;355continue;356}357access = (ACCESS_ALLOWED_ACE *)ace;358sid = (SID *) &access->SidStart;359360361deleted = FALSE;362if (!EqualSid(owner, sid)) {363/*364* If the ACE allows any access then the file then we365* delete it.366*/367if (access->Mask & ANY_ACCESS) {368str = getSIDString(sid);369if (str != NULL) {370printf("remove ALLOW %s\n", str);371free(str);372}373if (DeleteAce(acl, i) == 0) {374printLastError("DeleteAce failed");375return -1;376}377deleted = TRUE;378}379}380381if (!deleted) {382str = getSIDString(sid);383if (str != NULL) {384printf("ALLOW %s (access mask=%x)\n", str, access->Mask);385free(str);386}387388/* onto the next ACE */389i++;390}391count--;392}393394/*395* No changes - only owner has access396*/397if (i == acl_size_info.AceCount) {398printf("No changes.\n");399return 1;400}401402/*403* Create security descriptor and set its DACL to the version404* that we just edited405*/406if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {407printLastError("InitializeSecurityDescriptor failed");408return -1;409}410if (!SetSecurityDescriptorDacl(sd, present, acl, defaulted)) {411printLastError("SetSecurityDescriptorDacl failed");412return -1;413}414if (!SetFileSecurity(path, DACL_SECURITY_INFORMATION, sd)) {415printLastError("SetFileSecurity failed");416return -1;417}418419printf("File updated.\n");420421return 1;422}423424/*425* Convert slashes in the pathname to backslashes if needed.426*/427static char* convert_path(const char* p) {428int i = 0;429char* path = strdup(p);430while (p[i] != '\0') {431if (p[i] == '/') {432path[i] = '\\';433}434i++;435}436return path;437}438439/*440* Usage: revokeall file441*/442int main( int argc, char *argv[])443{444int rc;445const char* path;446447if (argc != 2) {448fprintf(stderr, "Usage: %s file\n", argv[0]);449return -1;450}451path = convert_path(argv[1]);452printf("Revoking all non-owner access to %s\n", path);453rc = isSecuritySupported(path);454if (rc != 1) {455if (rc == 0) {456printf("File security not supported on this file system\n");457}458return rc;459} else {460return revokeAll(path);461}462}463464465