blob: f466a6773effd94ac08bf58b37529658a5268fca [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 "sun_management_FileSystemImpl.h"
33
34/*
35 * Access mask to represent any file access
36 */
37#define ANY_ACCESS (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE)
38
39/*
40 * Function prototypes for security functions - we can't statically
41 * link because these functions aren't on Windows 9x.
42 */
43typedef BOOL (WINAPI *GetFileSecurityFunc)
44 (LPCTSTR lpFileName, SECURITY_INFORMATION RequestedInformation,
45 PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength,
46 LPDWORD lpnLengthNeeded);
47
48typedef BOOL (WINAPI *GetSecurityDescriptorOwnerFunc)
49 (PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID *pOwner,
50 LPBOOL lpbOwnerDefaulted);
51
52typedef BOOL (WINAPI *GetSecurityDescriptorDaclFunc)
53 (PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent,
54 PACL *pDacl, LPBOOL lpbDaclDefaulted);
55
56typedef BOOL (WINAPI *GetAclInformationFunc)
57 (PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength,
58 ACL_INFORMATION_CLASS dwAclInformationClass);
59
60typedef BOOL (WINAPI *GetAceFunc)
61 (PACL pAcl, DWORD dwAceIndex, LPVOID *pAce);
62
63typedef BOOL (WINAPI *EqualSidFunc)(PSID pSid1, PSID pSid2);
64
65
66/* Addresses of the security functions */
67static GetFileSecurityFunc GetFileSecurity_func;
68static GetSecurityDescriptorOwnerFunc GetSecurityDescriptorOwner_func;
69static GetSecurityDescriptorDaclFunc GetSecurityDescriptorDacl_func;
70static GetAclInformationFunc GetAclInformation_func;
71static GetAceFunc GetAce_func;
72static EqualSidFunc EqualSid_func;
73
74/* True if this OS is NT kernel based (NT/2000/XP) */
75static int isNT;
76
77
78/*
79 * Returns JNI_TRUE if the specified file is on a file system that supports
80 * persistent ACLs (On NTFS file systems returns true, on FAT32 file systems
81 * returns false).
82 */
83static jboolean isSecuritySupported(JNIEnv* env, const char* path) {
84 char* root;
85 char* p;
86 BOOL res;
87 DWORD dwMaxComponentLength;
88 DWORD dwFlags;
89 char fsName[128];
90 DWORD fsNameLength;
91
92 /*
93 * Get root directory. Assume that files are absolute paths. For UNCs
94 * the slash after the share name is required.
95 */
96 root = strdup(path);
97 if (*root == '\\') {
98 /*
99 * \\server\share\file ==> \\server\share\
100 */
101 int slashskip = 3;
102 p = root;
103 while ((*p == '\\') && (slashskip > 0)) {
104 char* p2;
105 p++;
106 p2 = strchr(p, '\\');
107 if ((p2 == NULL) || (*p2 != '\\')) {
108 free(root);
109 JNU_ThrowIOException(env, "Malformed UNC");
110 return JNI_FALSE;
111 }
112 p = p2;
113 slashskip--;
114 }
115 if (slashskip != 0) {
116 free(root);
117 JNU_ThrowIOException(env, "Malformed UNC");
118 return JNI_FALSE;
119 }
120 p++;
121 *p = '\0';
122
123 } else {
124 p = strchr(root, '\\');
125 if (p == NULL) {
126 free(root);
127 JNU_ThrowIOException(env, "Absolute filename not specified");
128 return JNI_FALSE;
129 }
130 p++;
131 *p = '\0';
132 }
133
134
135 /*
136 * Get the volume information - this gives us the file system file and
137 * also tells us if the file system supports persistent ACLs.
138 */
139 fsNameLength = sizeof(fsName)-1;
140 res = GetVolumeInformation(root,
141 NULL, // address of name of the volume, can be NULL
142 0, // length of volume name
143 NULL, // address of volume serial number, can be NULL
144 &dwMaxComponentLength,
145 &dwFlags,
146 fsName,
147 fsNameLength);
148 if (res == 0) {
149 free(root);
150 JNU_ThrowIOExceptionWithLastError(env, "GetVolumeInformation failed");
151 return JNI_FALSE;
152 }
153
154 free(root);
155 return (dwFlags & FS_PERSISTENT_ACLS) ? JNI_TRUE : JNI_FALSE;
156}
157
158
159/*
160 * Returns the security descriptor for a file.
161 */
162static SECURITY_DESCRIPTOR* getFileSecurityDescriptor(JNIEnv* env, const char* path) {
163 SECURITY_DESCRIPTOR* sd;
164 DWORD len = 0;
165 SECURITY_INFORMATION info =
166 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
167
168 (*GetFileSecurity_func)(path, info , 0, 0, &len);
169 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
170 JNU_ThrowIOExceptionWithLastError(env, "GetFileSecurity failed");
171 return NULL;
172 }
173 sd = (SECURITY_DESCRIPTOR *)malloc(len);
174 if (sd == NULL) {
175 JNU_ThrowOutOfMemoryError(env, 0);
176 } else {
177 if (!(*GetFileSecurity_func)(path, info, sd, len, &len)) {
178 JNU_ThrowIOExceptionWithLastError(env, "GetFileSecurity failed");
179 free(sd);
180 return NULL;
181 }
182 }
183 return sd;
184}
185
186/*
187 * Returns pointer to the SID identifying the owner of the specified
188 * file.
189 */
190static SID* getFileOwner(JNIEnv* env, SECURITY_DESCRIPTOR* sd) {
191 SID* owner;
192 BOOL defaulted;
193
194 if (!(*GetSecurityDescriptorOwner_func)(sd, &owner, &defaulted)) {
195 JNU_ThrowIOExceptionWithLastError(env, "GetSecurityDescriptorOwner failed");
196 return NULL;
197 }
198 return owner;
199}
200
201/*
202 * Returns pointer discretionary access-control list (ACL) from the security
203 * descriptor of the specified file.
204 */
205static ACL* getFileDACL(JNIEnv* env, SECURITY_DESCRIPTOR* sd) {
206 ACL *acl;
207 int defaulted, present;
208
209 if (!(*GetSecurityDescriptorDacl_func)(sd, &present, &acl, &defaulted)) {
210 JNU_ThrowIOExceptionWithLastError(env, "GetSecurityDescriptorDacl failed");
211 return NULL;
212 }
213 if (!present) {
214 JNU_ThrowInternalError(env, "Security descriptor does not contain a DACL");
215 return NULL;
216 }
217 return acl;
218}
219
220/*
221 * Returns JNI_TRUE if the specified owner is the only SID will access
222 * to the file.
223 */
224static jboolean isAccessUserOnly(JNIEnv* env, SID* owner, ACL* acl) {
225 ACL_SIZE_INFORMATION acl_size_info;
226 DWORD i;
227
228 /*
229 * If there's no DACL then there's no access to the file
230 */
231 if (acl == NULL) {
232 return JNI_TRUE;
233 }
234
235 /*
236 * Get the ACE count
237 */
238 if (!(*GetAclInformation_func)(acl, (void *) &acl_size_info, sizeof(acl_size_info),
239 AclSizeInformation)) {
240 JNU_ThrowIOExceptionWithLastError(env, "GetAclInformation failed");
241 return JNI_FALSE;
242 }
243
244 /*
245 * Iterate over the ACEs. For each "allow" type check that the SID
246 * matches the owner, and check that the access is read only.
247 */
248 for (i = 0; i < acl_size_info.AceCount; i++) {
249 void* ace;
250 ACCESS_ALLOWED_ACE *access;
251 SID* sid;
252
253 if (!(*GetAce_func)(acl, i, &ace)) {
254 JNU_ThrowIOExceptionWithLastError(env, "GetAce failed");
255 return -1;
256 }
257 if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
258 continue;
259 }
260 access = (ACCESS_ALLOWED_ACE *)ace;
261 sid = (SID *) &access->SidStart;
262 if (!EqualSid(owner, sid)) {
263 /*
264 * If the ACE allows any access then the file is not secure.
265 */
266 if (access->Mask & ANY_ACCESS) {
267 return JNI_FALSE;
268 }
269 }
270 }
271 return JNI_TRUE;
272}
273
274
275/*
276 * Class: sun_management_FileSystemImpl
277 * Method: init0
278 * Signature: ()V
279 */
280JNIEXPORT void JNICALL Java_sun_management_FileSystemImpl_init0
281 (JNIEnv *env, jclass ignored)
282{
283 OSVERSIONINFO ver;
284 HINSTANCE hInst;
285
286 /*
287 * Get the OS version. If dwPlatformId is VER_PLATFORM_WIN32_NT
288 * it means we're running on a Windows NT, 2000, or XP machine.
289 */
290 ver.dwOSVersionInfoSize = sizeof(ver);
291 GetVersionEx(&ver);
292 isNT = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT);
293 if (!isNT) {
294 return;
295 }
296
297 /*
298 * On NT/2000/XP we need the addresses of the security functions
299 */
300 hInst = LoadLibrary("ADVAPI32.DLL");
301 if (hInst == NULL) {
302 JNU_ThrowIOExceptionWithLastError(env, "Unable to load ADVAPI32.DLL");
303 return;
304 }
305
306
307 GetFileSecurity_func = (GetFileSecurityFunc)GetProcAddress(hInst, "GetFileSecurityA");
308 GetSecurityDescriptorOwner_func =
309 (GetSecurityDescriptorOwnerFunc)GetProcAddress(hInst, "GetSecurityDescriptorOwner");
310 GetSecurityDescriptorDacl_func =
311 (GetSecurityDescriptorDaclFunc)GetProcAddress(hInst, "GetSecurityDescriptorDacl");
312 GetAclInformation_func =
313 (GetAclInformationFunc)GetProcAddress(hInst, "GetAclInformation");
314 GetAce_func = (GetAceFunc)GetProcAddress(hInst, "GetAce");
315 EqualSid_func = (EqualSidFunc)GetProcAddress(hInst, "EqualSid");
316
317 if (GetFileSecurity_func == NULL ||
318 GetSecurityDescriptorDacl_func == NULL ||
319 GetSecurityDescriptorDacl_func == NULL ||
320 GetAclInformation_func == NULL ||
321 GetAce_func == NULL ||
322 EqualSid_func == NULL)
323 {
324 JNU_ThrowIOExceptionWithLastError(env,
325 "Unable to get address of security functions");
326 return;
327 }
328}
329
330/*
331 * Class: sun_management_FileSystemImpl
332 * Method: isSecuritySupported0
333 * Signature: (Ljava/lang/String;)Z
334 */
335JNIEXPORT jboolean JNICALL Java_sun_management_FileSystemImpl_isSecuritySupported0
336 (JNIEnv *env, jclass ignored, jstring str)
337{
338 jboolean res;
339 jboolean isCopy;
340 const char* path;
341
342 if (!isNT) {
343 return JNI_FALSE;
344 }
345
346 path = JNU_GetStringPlatformChars(env, str, &isCopy);
347 if (path != NULL) {
348 res = isSecuritySupported(env, path);
349 if (isCopy) {
350 JNU_ReleaseStringPlatformChars(env, str, path);
351 }
352 return res;
353 } else {
354 /* exception thrown - doesn't matter what we return */
355 return JNI_TRUE;
356 }
357}
358
359
360/*
361 * Class: sun_management_FileSystemImpl
362 * Method: isAccessUserOnly0
363 * Signature: (Ljava/lang/String;)Z
364 */
365JNIEXPORT jboolean JNICALL Java_sun_management_FileSystemImpl_isAccessUserOnly0
366 (JNIEnv *env, jclass ignored, jstring str)
367{
368 jboolean res = JNI_FALSE;
369 jboolean isCopy;
370 const char* path;
371
372 path = JNU_GetStringPlatformChars(env, str, &isCopy);
373 if (path != NULL) {
374 /*
375 * From the security descriptor get the file owner and
376 * DACL. Then check if anybody but the owner has access
377 * to the file.
378 */
379 SECURITY_DESCRIPTOR* sd = getFileSecurityDescriptor(env, path);
380 if (sd != NULL) {
381 SID *owner = getFileOwner(env, sd);
382 if (owner != NULL) {
383 ACL* acl = getFileDACL(env, sd);
384 if (acl != NULL) {
385 res = isAccessUserOnly(env, owner, acl);
386 } else {
387 /*
388 * If acl is NULL it means that an exception was thrown
389 * or there is "all acess" to the file.
390 */
391 res = JNI_FALSE;
392 }
393 }
394 free(sd);
395 }
396 if (isCopy) {
397 JNU_ReleaseStringPlatformChars(env, str, path);
398 }
399 }
400 return res;
401}