/* * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include #include #include #include /* * Simple Windows utility to remove all non-owner access to a given * file - suitable for NT/2000/XP only. */ /* * Access mask to represent any file access */ #define ANY_ACCESS (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE) /* * Print error message to stderr */ static void printLastError(const char* msg) { int len; char buf[128]; DWORD errval; buf[0] = '\0'; len = sizeof(buf); errval = GetLastError(); if (errval != 0) { int n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errval, 0, buf, len, NULL); if (n > 3) { /* Drop final '.', CR, LF */ if (buf[n - 1] == '\n') n--; if (buf[n - 1] == '\r') n--; if (buf[n - 1] == '.') n--; buf[n] = '\0'; } } if (strlen(buf) > 0) { fprintf(stderr, "revokeall %s: %s\n", msg, buf); } else { fprintf(stderr, "revokeall %s\n", msg); } } /* * Return a string that includes all the components of a given SID. * See here for a description of the SID components :- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/sid_components.asp */ static char *getTextualSid(SID* sid) { SID_IDENTIFIER_AUTHORITY* sia; DWORD i, count; DWORD len; char* name; /* * Get the identifier authority and the number of sub-authorities */ sia = GetSidIdentifierAuthority(sid); count = *GetSidSubAuthorityCount(sid); /* * Allocate buffer for the string - buffer is :- * S-SID_REVISION- + identifierAuthority- + subauthorities- + NULL */ len=(15 + 12 + (12 * count) + 1) * sizeof(char); name = (char*)malloc(len); if (name == NULL) { return NULL; } // S-SID_REVISION sprintf(name, "S-%lu-", SID_REVISION ); // Identifier authority if ((sia->Value[0] != 0) || (sia->Value[1] != 0)) { sprintf(name + strlen(name), "0x%02hx%02hx%02hx%02hx%02hx%02hx", (USHORT)sia->Value[0], (USHORT)sia->Value[1], (USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4], (USHORT)sia->Value[5]); } else { sprintf(name + strlen(name), "%lu", (ULONG)(sia->Value[5] ) + (ULONG)(sia->Value[4] << 8) + (ULONG)(sia->Value[3] << 16) + (ULONG)(sia->Value[2] << 24) ); } // finally, the sub-authorities for (i=0 ; i"); } if (LookupAccountSid(NULL, sid, name, &nameLen, domain, &domainLen, &use)) { int len = strlen(name) + strlen(domain) + 3; char* s = (char*)malloc(len); if (s != NULL) { strcpy(s, domain); strcat(s, "\\\\"); strcat(s, name); } return s; } else { return getTextualSid(sid); } } /* * Returns 1 if the specified file is on a file system that supports * persistent ACLs (On NTFS file systems returns true, on FAT32 file systems * returns false), otherwise 0. Returns -1 if error. */ static int isSecuritySupported(const char* path) { char* root; char* p; BOOL res; DWORD dwMaxComponentLength; DWORD dwFlags; char fsName[128]; DWORD fsNameLength; /* * Get root directory. For UNCs the slash after the share name is required. */ root = strdup(path); if (*root == '\\') { /* * \\server\share\file ==> \\server\share\ */ int slashskip = 3; p = root; while ((*p == '\\') && (slashskip > 0)) { char* p2; p++; p2 = strchr(p, '\\'); if ((p2 == NULL) || (*p2 != '\\')) { free(root); fprintf(stderr, "Malformed UNC"); return -1; } p = p2; slashskip--; } if (slashskip != 0) { free(root); fprintf(stderr, "Malformed UNC"); return -1; } p++; *p = '\0'; } else { p = strchr(root, '\\'); /* * Relative path so use current directory */ if (p == NULL) { free(root); root = malloc(255); if (GetCurrentDirectory(255, root) == 0) { printLastError("GetCurrentDirectory failed"); return -1; } p = strchr(root, '\\'); if (p == NULL) { fprintf(stderr, "GetCurrentDirectory doesn't include drive letter!!!!\n"); return -1; } } p++; *p = '\0'; } /* * Get the volume information - this gives us the file system file and * also tells us if the file system supports persistent ACLs. */ fsNameLength = sizeof(fsName)-1; res = GetVolumeInformation(root, NULL, // address of name of the volume, can be NULL 0, // length of volume name NULL, // address of volume serial number, can be NULL &dwMaxComponentLength, &dwFlags, fsName, fsNameLength); if (res == 0) { printLastError("GetVolumeInformation failed"); free(root); return -1; } free(root); return (dwFlags & FS_PERSISTENT_ACLS) ? 1 : 0; } /* * Returns the security descriptor for a file. */ static SECURITY_DESCRIPTOR* getFileSecurityDescriptor(const char* path) { SECURITY_DESCRIPTOR* sd; DWORD len = 0; SECURITY_INFORMATION info = OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; GetFileSecurity(path, info , 0, 0, &len); if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { printLastError("GetFileSecurity failed"); return NULL; } sd = (SECURITY_DESCRIPTOR *)malloc(len); if (sd == NULL) { fprintf(stderr, "Out of memory"); } else { if (!GetFileSecurity(path, info, sd, len, &len)) { printLastError("GetFileSecurity failed"); free(sd); return NULL; } } return sd; } /* * Revoke all access to the specific file */ static int revokeAll(const char* path) { SECURITY_DESCRIPTOR* sd; SID* owner; ACL *acl; BOOL defaulted, present; ACL_SIZE_INFORMATION acl_size_info; DWORD i, count; char* str; /* * Get security descriptor for file; From security descriptor get the * owner SID, and the DACL. */ sd = getFileSecurityDescriptor(path); if (sd == NULL) { return -1; /* error already reported */ } if (!GetSecurityDescriptorOwner(sd, &owner, &defaulted)) { printLastError("GetSecurityDescriptorOwner failed"); return -1; } str = getSIDString(owner); if (str != NULL) { printf("owner: %s\n", str); free(str); } if (!GetSecurityDescriptorDacl(sd, &present, &acl, &defaulted)) { printLastError("GetSecurityDescriptorDacl failed"); return -1; } if (!present) { fprintf(stderr, "Security descriptor does not contain a DACL"); return -1; } /* * If DACL is NULL there is no access to the file - we are done */ if (acl == NULL) { return 1; } /* * Iterate over the ACEs. For each "allow" type check that the SID * matches the owner - if not we remove the ACE from the ACL */ if (!GetAclInformation(acl, (void *) &acl_size_info, sizeof(acl_size_info), AclSizeInformation)) { printLastError("GetAclInformation failed"); return -1; } count = acl_size_info.AceCount; i = 0; while (count > 0) { void* ace; ACCESS_ALLOWED_ACE *access; SID* sid; BOOL deleted; if (!GetAce(acl, i, &ace)) { printLastError("GetAce failed"); return -1; } if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) { continue; } access = (ACCESS_ALLOWED_ACE *)ace; sid = (SID *) &access->SidStart; deleted = FALSE; if (!EqualSid(owner, sid)) { /* * If the ACE allows any access then the file then we * delete it. */ if (access->Mask & ANY_ACCESS) { str = getSIDString(sid); if (str != NULL) { printf("remove ALLOW %s\n", str); free(str); } if (DeleteAce(acl, i) == 0) { printLastError("DeleteAce failed"); return -1; } deleted = TRUE; } } if (!deleted) { str = getSIDString(sid); if (str != NULL) { printf("ALLOW %s (access mask=%x)\n", str, access->Mask); free(str); } /* onto the next ACE */ i++; } count--; } /* * No changes - only owner has access */ if (i == acl_size_info.AceCount) { printf("No changes.\n"); return 1; } /* * Create security descriptor and set its DACL to the version * that we just edited */ if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) { printLastError("InitializeSecurityDescriptor failed"); return -1; } if (!SetSecurityDescriptorDacl(sd, present, acl, defaulted)) { printLastError("SetSecurityDescriptorDacl failed"); return -1; } if (!SetFileSecurity(path, DACL_SECURITY_INFORMATION, sd)) { printLastError("SetFileSecurity failed"); return -1; } printf("File updated.\n"); return 1; } /* * Convert slashes in the pathname to backslashes if needed. */ static char* convert_path(const char* p) { int i = 0; char* path = strdup(p); while (p[i] != '\0') { if (p[i] == '/') { path[i] = '\\'; } i++; } return path; } /* * Usage: revokeall file */ int main( int argc, char *argv[]) { int rc; const char* path; if (argc != 2) { fprintf(stderr, "Usage: %s file\n", argv[0]); return -1; } path = convert_path(argv[1]); printf("Revoking all non-owner access to %s\n", path); rc = isSecuritySupported(path); if (rc != 1) { if (rc == 0) { printf("File security not supported on this file system\n"); } return rc; } else { return revokeAll(path); } }