0N/A/*
2362N/A * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A#include <windows.h>
0N/A#include <malloc.h>
0N/A#include <string.h>
0N/A
0N/A#include "jni.h"
0N/A#include "jni_util.h"
0N/A#include "sun_management_FileSystemImpl.h"
0N/A
0N/A/*
0N/A * Access mask to represent any file access
0N/A */
0N/A#define ANY_ACCESS (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE)
0N/A
0N/A/*
0N/A * Returns JNI_TRUE if the specified file is on a file system that supports
0N/A * persistent ACLs (On NTFS file systems returns true, on FAT32 file systems
0N/A * returns false).
0N/A */
0N/Astatic jboolean isSecuritySupported(JNIEnv* env, const char* path) {
0N/A char* root;
0N/A char* p;
0N/A BOOL res;
0N/A DWORD dwMaxComponentLength;
0N/A DWORD dwFlags;
0N/A char fsName[128];
0N/A DWORD fsNameLength;
0N/A
0N/A /*
0N/A * Get root directory. Assume that files are absolute paths. For UNCs
0N/A * the slash after the share name is required.
0N/A */
0N/A root = strdup(path);
0N/A if (*root == '\\') {
0N/A /*
0N/A * \\server\share\file ==> \\server\share\
0N/A */
0N/A int slashskip = 3;
0N/A p = root;
0N/A while ((*p == '\\') && (slashskip > 0)) {
0N/A char* p2;
0N/A p++;
0N/A p2 = strchr(p, '\\');
0N/A if ((p2 == NULL) || (*p2 != '\\')) {
0N/A free(root);
0N/A JNU_ThrowIOException(env, "Malformed UNC");
0N/A return JNI_FALSE;
0N/A }
0N/A p = p2;
0N/A slashskip--;
0N/A }
0N/A if (slashskip != 0) {
0N/A free(root);
0N/A JNU_ThrowIOException(env, "Malformed UNC");
0N/A return JNI_FALSE;
0N/A }
0N/A p++;
0N/A *p = '\0';
0N/A
0N/A } else {
0N/A p = strchr(root, '\\');
0N/A if (p == NULL) {
0N/A free(root);
0N/A JNU_ThrowIOException(env, "Absolute filename not specified");
0N/A return JNI_FALSE;
0N/A }
0N/A p++;
0N/A *p = '\0';
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Get the volume information - this gives us the file system file and
0N/A * also tells us if the file system supports persistent ACLs.
0N/A */
0N/A fsNameLength = sizeof(fsName)-1;
0N/A res = GetVolumeInformation(root,
0N/A NULL, // address of name of the volume, can be NULL
0N/A 0, // length of volume name
0N/A NULL, // address of volume serial number, can be NULL
0N/A &dwMaxComponentLength,
0N/A &dwFlags,
0N/A fsName,
0N/A fsNameLength);
0N/A if (res == 0) {
0N/A free(root);
0N/A JNU_ThrowIOExceptionWithLastError(env, "GetVolumeInformation failed");
0N/A return JNI_FALSE;
0N/A }
0N/A
0N/A free(root);
0N/A return (dwFlags & FS_PERSISTENT_ACLS) ? JNI_TRUE : JNI_FALSE;
0N/A}
0N/A
0N/A
0N/A/*
0N/A * Returns the security descriptor for a file.
0N/A */
0N/Astatic SECURITY_DESCRIPTOR* getFileSecurityDescriptor(JNIEnv* env, const char* path) {
0N/A SECURITY_DESCRIPTOR* sd;
0N/A DWORD len = 0;
0N/A SECURITY_INFORMATION info =
0N/A OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
0N/A
3901N/A GetFileSecurityA(path, info , 0, 0, &len);
0N/A if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "GetFileSecurity failed");
0N/A return NULL;
0N/A }
0N/A sd = (SECURITY_DESCRIPTOR *)malloc(len);
0N/A if (sd == NULL) {
0N/A JNU_ThrowOutOfMemoryError(env, 0);
0N/A } else {
3901N/A if (!(*GetFileSecurityA)(path, info, sd, len, &len)) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "GetFileSecurity failed");
0N/A free(sd);
0N/A return NULL;
0N/A }
0N/A }
0N/A return sd;
0N/A}
0N/A
0N/A/*
0N/A * Returns pointer to the SID identifying the owner of the specified
0N/A * file.
0N/A */
0N/Astatic SID* getFileOwner(JNIEnv* env, SECURITY_DESCRIPTOR* sd) {
0N/A SID* owner;
0N/A BOOL defaulted;
0N/A
3901N/A if (!GetSecurityDescriptorOwner(sd, &owner, &defaulted)) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "GetSecurityDescriptorOwner failed");
0N/A return NULL;
0N/A }
0N/A return owner;
0N/A}
0N/A
0N/A/*
0N/A * Returns pointer discretionary access-control list (ACL) from the security
0N/A * descriptor of the specified file.
0N/A */
0N/Astatic ACL* getFileDACL(JNIEnv* env, SECURITY_DESCRIPTOR* sd) {
0N/A ACL *acl;
0N/A int defaulted, present;
0N/A
3901N/A if (!GetSecurityDescriptorDacl(sd, &present, &acl, &defaulted)) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "GetSecurityDescriptorDacl failed");
0N/A return NULL;
0N/A }
0N/A if (!present) {
0N/A JNU_ThrowInternalError(env, "Security descriptor does not contain a DACL");
0N/A return NULL;
0N/A }
0N/A return acl;
0N/A}
0N/A
0N/A/*
0N/A * Returns JNI_TRUE if the specified owner is the only SID will access
0N/A * to the file.
0N/A */
0N/Astatic jboolean isAccessUserOnly(JNIEnv* env, SID* owner, ACL* acl) {
0N/A ACL_SIZE_INFORMATION acl_size_info;
0N/A DWORD i;
0N/A
0N/A /*
0N/A * If there's no DACL then there's no access to the file
0N/A */
0N/A if (acl == NULL) {
0N/A return JNI_TRUE;
0N/A }
0N/A
0N/A /*
0N/A * Get the ACE count
0N/A */
3901N/A if (!GetAclInformation(acl, (void *) &acl_size_info, sizeof(acl_size_info),
3901N/A AclSizeInformation)) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "GetAclInformation failed");
0N/A return JNI_FALSE;
0N/A }
0N/A
0N/A /*
0N/A * Iterate over the ACEs. For each "allow" type check that the SID
0N/A * matches the owner, and check that the access is read only.
0N/A */
0N/A for (i = 0; i < acl_size_info.AceCount; i++) {
0N/A void* ace;
0N/A ACCESS_ALLOWED_ACE *access;
0N/A SID* sid;
0N/A
3901N/A if (!GetAce(acl, i, &ace)) {
0N/A JNU_ThrowIOExceptionWithLastError(env, "GetAce failed");
0N/A return -1;
0N/A }
0N/A if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
0N/A continue;
0N/A }
0N/A access = (ACCESS_ALLOWED_ACE *)ace;
0N/A sid = (SID *) &access->SidStart;
0N/A if (!EqualSid(owner, sid)) {
0N/A /*
0N/A * If the ACE allows any access then the file is not secure.
0N/A */
0N/A if (access->Mask & ANY_ACCESS) {
0N/A return JNI_FALSE;
0N/A }
0N/A }
0N/A }
0N/A return JNI_TRUE;
0N/A}
0N/A
0N/A
0N/A/*
0N/A * Class: sun_management_FileSystemImpl
0N/A * Method: init0
0N/A * Signature: ()V
0N/A */
0N/AJNIEXPORT void JNICALL Java_sun_management_FileSystemImpl_init0
0N/A (JNIEnv *env, jclass ignored)
0N/A{
3901N/A /* nothing to do */
0N/A}
0N/A
0N/A/*
0N/A * Class: sun_management_FileSystemImpl
0N/A * Method: isSecuritySupported0
0N/A * Signature: (Ljava/lang/String;)Z
0N/A */
0N/AJNIEXPORT jboolean JNICALL Java_sun_management_FileSystemImpl_isSecuritySupported0
0N/A (JNIEnv *env, jclass ignored, jstring str)
0N/A{
0N/A jboolean res;
0N/A jboolean isCopy;
0N/A const char* path;
0N/A
0N/A path = JNU_GetStringPlatformChars(env, str, &isCopy);
0N/A if (path != NULL) {
0N/A res = isSecuritySupported(env, path);
0N/A if (isCopy) {
0N/A JNU_ReleaseStringPlatformChars(env, str, path);
0N/A }
0N/A return res;
0N/A } else {
0N/A /* exception thrown - doesn't matter what we return */
0N/A return JNI_TRUE;
0N/A }
0N/A}
0N/A
0N/A
0N/A/*
0N/A * Class: sun_management_FileSystemImpl
0N/A * Method: isAccessUserOnly0
0N/A * Signature: (Ljava/lang/String;)Z
0N/A */
0N/AJNIEXPORT jboolean JNICALL Java_sun_management_FileSystemImpl_isAccessUserOnly0
0N/A (JNIEnv *env, jclass ignored, jstring str)
0N/A{
0N/A jboolean res = JNI_FALSE;
0N/A jboolean isCopy;
0N/A const char* path;
0N/A
0N/A path = JNU_GetStringPlatformChars(env, str, &isCopy);
0N/A if (path != NULL) {
0N/A /*
0N/A * From the security descriptor get the file owner and
0N/A * DACL. Then check if anybody but the owner has access
0N/A * to the file.
0N/A */
0N/A SECURITY_DESCRIPTOR* sd = getFileSecurityDescriptor(env, path);
0N/A if (sd != NULL) {
0N/A SID *owner = getFileOwner(env, sd);
0N/A if (owner != NULL) {
0N/A ACL* acl = getFileDACL(env, sd);
0N/A if (acl != NULL) {
0N/A res = isAccessUserOnly(env, owner, acl);
0N/A } else {
0N/A /*
0N/A * If acl is NULL it means that an exception was thrown
0N/A * or there is "all acess" to the file.
0N/A */
0N/A res = JNI_FALSE;
0N/A }
0N/A }
0N/A free(sd);
0N/A }
0N/A if (isCopy) {
0N/A JNU_ReleaseStringPlatformChars(env, str, path);
0N/A }
0N/A }
0N/A return res;
0N/A}