1 /*
   2  * Copyright (c) 2004, 2011, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <windows.h>
  27 #include <malloc.h>
  28 #include <string.h>
  29 
  30 #include "jni.h"
  31 #include "jni_util.h"
  32 #include "jdk_internal_agent_FileSystemImpl.h"
  33 
  34 JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
  35 {
  36     JNIEnv* env;
  37 
  38     if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_2) != JNI_OK) {
  39         return JNI_EVERSION; /* JNI version not supported */
  40     }
  41 
  42     return JNI_VERSION_9;
  43 }
  44 
  45 
  46 /*
  47  * Access mask to represent any file access
  48  */
  49 #define ANY_ACCESS (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE)
  50 
  51 /*
  52  * Returns JNI_TRUE if the specified file is on a file system that supports
  53  * persistent ACLs (On NTFS file systems returns true, on FAT32 file systems
  54  * returns false).
  55  */
  56 static jboolean isSecuritySupported(JNIEnv* env, const char* path) {
  57     char* root;
  58     char* p;
  59     BOOL res;
  60     DWORD dwMaxComponentLength;
  61     DWORD dwFlags;
  62     char fsName[128];
  63     DWORD fsNameLength;
  64 
  65     /*
  66      * Get root directory. Assume that files are absolute paths. For UNCs
  67      * the slash after the share name is required.
  68      */
  69     root = strdup(path);
  70     if (*root == '\\') {
  71         /*
  72          * \\server\share\file ==> \\server\share\
  73          */
  74         int slashskip = 3;
  75         p = root;
  76         while ((*p == '\\') && (slashskip > 0)) {
  77             char* p2;
  78             p++;
  79             p2 = strchr(p, '\\');
  80             if ((p2 == NULL) || (*p2 != '\\')) {
  81                 free(root);
  82                 JNU_ThrowIOException(env, "Malformed UNC");
  83                 return JNI_FALSE;
  84             }
  85             p = p2;
  86             slashskip--;
  87         }
  88         if (slashskip != 0) {
  89             free(root);
  90             JNU_ThrowIOException(env, "Malformed UNC");
  91             return JNI_FALSE;
  92         }
  93         p++;
  94         *p = '\0';
  95 
  96     } else {
  97         p = strchr(root, '\\');
  98         if (p == NULL) {
  99             free(root);
 100             JNU_ThrowIOException(env, "Absolute filename not specified");
 101             return JNI_FALSE;
 102         }
 103         p++;
 104         *p = '\0';
 105     }
 106 
 107 
 108     /*
 109      * Get the volume information - this gives us the file system file and
 110      * also tells us if the file system supports persistent ACLs.
 111      */
 112     fsNameLength = sizeof(fsName)-1;
 113     res = GetVolumeInformation(root,
 114                                NULL,        // address of name of the volume, can be NULL
 115                                0,           // length of volume name
 116                                NULL,        // address of volume serial number, can be NULL
 117                                &dwMaxComponentLength,
 118                                &dwFlags,
 119                                fsName,
 120                                fsNameLength);
 121     if (res == 0) {
 122         free(root);
 123         JNU_ThrowIOExceptionWithLastError(env, "GetVolumeInformation failed");
 124         return JNI_FALSE;
 125     }
 126 
 127     free(root);
 128     return (dwFlags & FS_PERSISTENT_ACLS) ? JNI_TRUE : JNI_FALSE;
 129 }
 130 
 131 
 132 /*
 133  * Returns the security descriptor for a file.
 134  */
 135 static SECURITY_DESCRIPTOR* getFileSecurityDescriptor(JNIEnv* env, const char* path) {
 136     SECURITY_DESCRIPTOR* sd;
 137     DWORD len = 0;
 138     SECURITY_INFORMATION info =
 139         OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
 140 
 141     GetFileSecurityA(path, info , 0, 0, &len);
 142     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
 143         JNU_ThrowIOExceptionWithLastError(env, "GetFileSecurity failed");
 144         return NULL;
 145     }
 146     sd = (SECURITY_DESCRIPTOR *)malloc(len);
 147     if (sd == NULL) {
 148         JNU_ThrowOutOfMemoryError(env, 0);
 149     } else {
 150         if (!(*GetFileSecurityA)(path, info, sd, len, &len)) {
 151             JNU_ThrowIOExceptionWithLastError(env, "GetFileSecurity failed");
 152             free(sd);
 153             return NULL;
 154         }
 155     }
 156     return sd;
 157 }
 158 
 159 /*
 160  * Returns pointer to the SID identifying the owner of the specified
 161  * file.
 162  */
 163 static SID* getFileOwner(JNIEnv* env, SECURITY_DESCRIPTOR* sd) {
 164     SID* owner;
 165     BOOL defaulted;
 166 
 167     if (!GetSecurityDescriptorOwner(sd, &owner, &defaulted)) {
 168         JNU_ThrowIOExceptionWithLastError(env, "GetSecurityDescriptorOwner failed");
 169         return NULL;
 170     }
 171     return owner;
 172 }
 173 
 174 /*
 175  * Returns pointer discretionary access-control list (ACL) from the security
 176  * descriptor of the specified file.
 177  */
 178 static ACL* getFileDACL(JNIEnv* env, SECURITY_DESCRIPTOR* sd) {
 179     ACL *acl;
 180     int defaulted, present;
 181 
 182     if (!GetSecurityDescriptorDacl(sd, &present, &acl, &defaulted)) {
 183         JNU_ThrowIOExceptionWithLastError(env, "GetSecurityDescriptorDacl failed");
 184         return NULL;
 185     }
 186     if (!present) {
 187         JNU_ThrowInternalError(env, "Security descriptor does not contain a DACL");
 188         return NULL;
 189     }
 190     return acl;
 191 }
 192 
 193 /*
 194  * Returns JNI_TRUE if the specified owner is the only SID will access
 195  * to the file.
 196  */
 197 static jboolean isAccessUserOnly(JNIEnv* env, SID* owner, ACL* acl) {
 198     ACL_SIZE_INFORMATION acl_size_info;
 199     DWORD i;
 200 
 201     /*
 202      * If there's no DACL then there's no access to the file
 203      */
 204     if (acl == NULL) {
 205         return JNI_TRUE;
 206     }
 207 
 208     /*
 209      * Get the ACE count
 210      */
 211     if (!GetAclInformation(acl, (void *) &acl_size_info, sizeof(acl_size_info),
 212                            AclSizeInformation)) {
 213         JNU_ThrowIOExceptionWithLastError(env, "GetAclInformation failed");
 214         return JNI_FALSE;
 215     }
 216 
 217     /*
 218      * Iterate over the ACEs. For each "allow" type check that the SID
 219      * matches the owner, and check that the access is read only.
 220      */
 221     for (i = 0; i < acl_size_info.AceCount; i++) {
 222         void* ace;
 223         ACCESS_ALLOWED_ACE *access;
 224         SID* sid;
 225 
 226         if (!GetAce(acl, i, &ace)) {
 227             JNU_ThrowIOExceptionWithLastError(env, "GetAce failed");
 228             return -1;
 229         }
 230         if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
 231             continue;
 232         }
 233         access = (ACCESS_ALLOWED_ACE *)ace;
 234         sid = (SID *) &access->SidStart;
 235         if (!EqualSid(owner, sid)) {
 236             /*
 237              * If the ACE allows any access then the file is not secure.
 238              */
 239             if (access->Mask & ANY_ACCESS) {
 240                 return JNI_FALSE;
 241             }
 242         }
 243     }
 244     return JNI_TRUE;
 245 }
 246 
 247 
 248 /*
 249  * Class:     jdk_internal_agent_FileSystemImpl
 250  * Method:    init0
 251  * Signature: ()V
 252  */
 253 JNIEXPORT void JNICALL Java_jdk_internal_agent_FileSystemImpl_init0
 254   (JNIEnv *env, jclass ignored)
 255 {
 256         /* nothing to do */
 257 }
 258 
 259 /*
 260  * Class:     jdk_internal_agent_FileSystemImpl
 261  * Method:    isSecuritySupported0
 262  * Signature: (Ljava/lang/String;)Z
 263  */
 264 JNIEXPORT jboolean JNICALL Java_jdk_internal_agent_FileSystemImpl_isSecuritySupported0
 265   (JNIEnv *env, jclass ignored, jstring str)
 266 {
 267     jboolean res;
 268     jboolean isCopy;
 269     const char* path;
 270 
 271     path = JNU_GetStringPlatformChars(env, str, &isCopy);
 272     if (path != NULL) {
 273         res = isSecuritySupported(env, path);
 274         if (isCopy) {
 275             JNU_ReleaseStringPlatformChars(env, str, path);
 276         }
 277         return res;
 278     } else {
 279         /* exception thrown - doesn't matter what we return */
 280         return JNI_TRUE;
 281     }
 282 }
 283 
 284 
 285 /*
 286  * Class:     jdk_internal_agent_FileSystemImpl
 287  * Method:    isAccessUserOnly0
 288  * Signature: (Ljava/lang/String;)Z
 289  */
 290 JNIEXPORT jboolean JNICALL Java_jdk_internal_agent_FileSystemImpl_isAccessUserOnly0
 291   (JNIEnv *env, jclass ignored, jstring str)
 292 {
 293     jboolean res = JNI_FALSE;
 294     jboolean isCopy;
 295     const char* path;
 296 
 297     path = JNU_GetStringPlatformChars(env, str, &isCopy);
 298     if (path != NULL) {
 299         /*
 300          * From the security descriptor get the file owner and
 301          * DACL. Then check if anybody but the owner has access
 302          * to the file.
 303          */
 304         SECURITY_DESCRIPTOR* sd = getFileSecurityDescriptor(env, path);
 305         if (sd != NULL) {
 306             SID *owner = getFileOwner(env, sd);
 307             if (owner != NULL) {
 308                 ACL* acl = getFileDACL(env, sd);
 309                 if (acl != NULL) {
 310                     res = isAccessUserOnly(env, owner, acl);
 311                 } else {
 312                     /*
 313                      * If acl is NULL it means that an exception was thrown
 314                      * or there is "all acess" to the file.
 315                      */
 316                     res = JNI_FALSE;
 317                 }
 318             }
 319             free(sd);
 320         }
 321         if (isCopy) {
 322             JNU_ReleaseStringPlatformChars(env, str, path);
 323         }
 324     }
 325     return res;
 326 }