JNIEXPORT jstring JNICALL Java_com_microsoft_tfs_jni_internal_filesystem_NativeFileSystem_nativeGetOwner(JNIEnv *env, jclass cls, jstring jPath) { const WCHAR * path = NULL; DWORD result = 0; PSECURITY_DESCRIPTOR securityDescriptor = NULL; PSID ownerSID = NULL; WCHAR * ownerSIDString = NULL; jstring jOwnerSIDString = NULL; if (jPath == NULL) { throwRuntimeExceptionString(env, "path must not be null"); goto cleanup; } if ((path = javaStringToPlatformChars(env, jPath)) == NULL) { // String allocation failed, exception already thrown goto cleanup; } // Get sid, which points into securityDescriptor result = GetNamedSecurityInfoW(path, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &ownerSID, NULL, NULL, NULL, &securityDescriptor); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error getting file security info for %S", path); goto cleanup; } // Convert to string SID if (ConvertSidToStringSidW(ownerSID, &ownerSIDString) == FALSE) { throwRuntimeExceptionCode(env, GetLastError(), "Error converting sid to string sid"); goto cleanup; } jOwnerSIDString = platformCharsToJavaString(env, ownerSIDString); cleanup: if (path != NULL) { releasePlatformChars(env, jPath, path); } // ownerSID points inside securityDescriptor if (securityDescriptor != NULL) { LocalFree(securityDescriptor); } if (ownerSIDString != NULL) { LocalFree(ownerSIDString); } return jOwnerSIDString; }
void throwRuntimeExceptionCode(_In_ JNIEnv * env, platform_error errorCode, _Printf_format_string_ const char * prefixFormat, ...) { va_list ap; char * prefix = NULL; #if defined(__solaris__) || defined(__hpux__) char * tmpErrorString = NULL; #endif char errorString[MESSAGE_BUFFER_SIZE]; char message[MESSAGE_BUFFER_SIZE]; if (prefixFormat != NULL) { va_start(ap, prefixFormat); prefix = tee_vsprintf(prefixFormat, ap); va_end(ap); } // Format errorString #ifdef _WIN32 // String is single-byte wide. Use FormatMessageA instead of Unicode method. if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode, 0, errorString, MESSAGE_BUFFER_SIZE, NULL) == 0) { sprintf_s(errorString, MESSAGE_BUFFER_SIZE, "Unknown error: %d", errorCode); } #elif defined(__solaris__) || defined(__hpux__) /* strerror_r is not available on Solaris, but strerror is thread-safe. It's marked "obsolescent" on HP-UX, and strerror is thread-safe there, too. */ tmpErrorString = strerror(errorCode); if (tmpErrorString != NULL) { snprintf(errorString, MESSAGE_BUFFER_SIZE, "%s", tmpErrorString); } else { snprintf(errorString, MESSAGE_BUFFER_SIZE, "Unknown error: %d", errorCode); } #else if (strerror_r(errorCode, errorString, MESSAGE_BUFFER_SIZE) != 0) { snprintf(errorString, MESSAGE_BUFFER_SIZE, "Unknown error: %d", errorCode); } #endif // Format with a prefix if it was provided if (prefix != NULL) { #ifdef _WIN32 sprintf_s(message, MESSAGE_BUFFER_SIZE, "%s: %s", prefix, errorString); #else snprintf(message, MESSAGE_BUFFER_SIZE, "%s: %s", prefix, errorString); #endif free(prefix); throwRuntimeExceptionString(env, message); } else { throwRuntimeExceptionString(env, errorString); } }
JNIEXPORT void JNICALL Java_com_microsoft_tfs_jni_internal_filesystem_NativeFileSystem_nativeSetOwner(JNIEnv *env, jclass cls, jstring jPath, jstring jOwnerSIDString) { const WCHAR * path= NULL; const WCHAR * ownerSIDString = NULL; PSID ownerSID = NULL; DWORD result = 0; if (jPath == NULL) { throwRuntimeExceptionString(env, "path must not be null"); goto cleanup; } if (jOwnerSIDString == NULL) { throwRuntimeExceptionString(env, "user must not be null"); goto cleanup; } if ((ownerSIDString = javaStringToPlatformChars(env, jOwnerSIDString)) == NULL) { // String allocation failed, exception already thrown goto cleanup; } if (ConvertStringSidToSidW(ownerSIDString, &ownerSID) == FALSE) { throwRuntimeExceptionCode(env, GetLastError(), "Error converting string %S sid to sid", ownerSIDString); goto cleanup; } if ((path = javaStringToPlatformChars(env, jPath)) == NULL) { // String allocation failed, exception already thrown goto cleanup; } result = SetNamedSecurityInfoW((WCHAR *) path, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, ownerSID, NULL, NULL, NULL); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error getting file security info for %S", path); goto cleanup; } cleanup: if (ownerSIDString != NULL) { releasePlatformChars(env, jOwnerSIDString, ownerSIDString); } if (path != NULL) { releasePlatformChars(env, jPath, path); } if (ownerSID != NULL) { LocalFree(ownerSID); } }
JNIEXPORT void JNICALL Java_com_microsoft_tfs_jni_internal_filesystem_NativeFileSystem_nativeCopyExplicitDACLEntries( JNIEnv *env, jclass cls, jstring jSourcePath, jstring jTargetPath) { const WCHAR * sourcePath = NULL; const WCHAR * targetPath = NULL; DWORD result = 0; PACL sourceDACL = NULL; PACL targetDACL = NULL; PACL newDACL = NULL; PSECURITY_DESCRIPTOR sourceSecurityDescriptor = NULL; PSECURITY_DESCRIPTOR targetSecurityDescriptor = NULL; PEXPLICIT_ACCESS sourceExplicitEntries = NULL; ULONG sourceExplicitEntriesCount = 0; if (jSourcePath == NULL) { throwRuntimeExceptionString(env, "source path must not be null"); goto cleanup; } if (jTargetPath == NULL) { throwRuntimeExceptionString(env, "target path must not be null"); goto cleanup; } if ((sourcePath = javaStringToPlatformChars(env, jSourcePath)) == NULL) { // String allocation failed, exception already thrown goto cleanup; } if ((targetPath = javaStringToPlatformChars(env, jTargetPath)) == NULL) { // String allocation failed, exception already thrown goto cleanup; } // Get source's DACL result = GetNamedSecurityInfo(sourcePath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &sourceDACL, NULL, &sourceSecurityDescriptor); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error getting security info for %S", sourcePath); goto cleanup; } // Get the explicit entries in the source DACL result = GetExplicitEntriesFromAcl(sourceDACL, &sourceExplicitEntriesCount, &sourceExplicitEntries); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error getting ACL entries"); goto cleanup; } if (sourceExplicitEntries == 0) { goto cleanup; } // Get target's DACL result = GetNamedSecurityInfo(targetPath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &targetDACL, NULL, &targetSecurityDescriptor); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error getting security info for %S", targetPath); goto cleanup; } // Merge the source entries into the target list result = SetEntriesInAcl(sourceExplicitEntriesCount, sourceExplicitEntries, targetDACL, &newDACL); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error setting entries in ACL"); goto cleanup; } // Set the list on the target path result = SetNamedSecurityInfo((WCHAR *) targetPath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, newDACL, NULL); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error setting security info for %S", targetPath); goto cleanup; } cleanup: if (sourcePath != NULL) { releasePlatformChars(env, jSourcePath, sourcePath); } if (targetPath != NULL) { releasePlatformChars(env, jTargetPath, targetPath); } // sourceDACL points into sourceSecurityDescriptor if (sourceSecurityDescriptor != NULL) { LocalFree(sourceSecurityDescriptor); } // targetDACL points into targetSecurityDescriptor if (targetSecurityDescriptor != NULL) { LocalFree(targetSecurityDescriptor); } if (sourceExplicitEntries != NULL) { LocalFree(sourceExplicitEntries); } if (newDACL != NULL) { LocalFree(newDACL); } }
JNIEXPORT void JNICALL Java_com_microsoft_tfs_jni_internal_filesystem_NativeFileSystem_nativeRemoveExplicitAllowEntries( JNIEnv *env, jclass cls, jstring jPath, jstring jUserSIDString) { const WCHAR * path = NULL; const WCHAR * userSIDString = NULL; PSID userSID = NULL; DWORD result = 0; PACL dacl = NULL; PSECURITY_DESCRIPTOR securityDescriptor = NULL; ACL_SIZE_INFORMATION aclSizeInfo; ULONG aceCount = 0; BOOL modifiedDACL = FALSE; if (jPath == NULL) { throwRuntimeExceptionString(env, "path must not be null"); goto cleanup; } if (jUserSIDString == NULL) { throwRuntimeExceptionString(env, "user must not be null"); goto cleanup; } // Convert the SID string to a struct if ((userSIDString = javaStringToPlatformChars(env, jUserSIDString)) == NULL) { // String allocation failed, exception already thrown goto cleanup; } if (ConvertStringSidToSidW(userSIDString, &userSID) == FALSE) { throwRuntimeExceptionCode(env, GetLastError(), "Error converting string sid %S to sid", userSIDString); goto cleanup; } if ((path = javaStringToPlatformChars(env, jPath)) == NULL) { // String allocation failed, exception already thrown goto cleanup; } // Get file's DACL result = GetNamedSecurityInfo(path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, NULL, &securityDescriptor); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error getting file security info for %S", path); goto cleanup; } // Get the count of entries int the DACL if (GetAclInformation(dacl, &aclSizeInfo, sizeof(aclSizeInfo), AclSizeInformation) == 0) { throwRuntimeExceptionCode(env, GetLastError(), "Error getting DACL"); goto cleanup; } // Loop over the DACL backwards, removing matching entries for (aceCount = aclSizeInfo.AceCount; aceCount > 0; aceCount--) { ULONG aceIndex = aceCount - 1; ACCESS_ALLOWED_ACE * ace = NULL; PSID sid = NULL; if (GetAce(dacl, aceIndex, (LPVOID *) &ace) == 0) { throwRuntimeExceptionCode(env, GetLastError(), "Error getting ACE at index %d", aceIndex); goto cleanup; } // Skip inherited (non-explicit) entries if ((((ACE_HEADER *) ace)->AceFlags & INHERITED_ACE) == INHERITED_ACE) { continue; } // Extract the SID for "allow" types switch(((ACE_HEADER *) ace)->AceType) { case ACCESS_ALLOWED_ACE_TYPE: sid = (PSID) &((ACCESS_ALLOWED_ACE *) ace)->SidStart; break; case ACCESS_ALLOWED_CALLBACK_ACE_TYPE: sid = (PSID) &((ACCESS_ALLOWED_CALLBACK_ACE *) ace)->SidStart; break; case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE: sid = (PSID) &((ACCESS_ALLOWED_CALLBACK_OBJECT_ACE *) ace)->SidStart; break; case ACCESS_ALLOWED_OBJECT_ACE_TYPE: sid = (PSID) &((ACCESS_ALLOWED_OBJECT_ACE *) ace)->SidStart; break; default: // These are "deny" or other entries break; } if (sid != NULL && EqualSid(sid, userSID)) { if (DeleteAce(dacl, aceIndex) == 0) { throwRuntimeExceptionCode(env, GetLastError(), "Error deleting ACE at index %d", aceIndex); goto cleanup; } modifiedDACL = TRUE; } // Nothing to free in the loop, all pointers are into dacl } if (modifiedDACL) { result = SetNamedSecurityInfo((WCHAR *) path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, dacl, NULL); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error setting security info for %S", path); goto cleanup; } } cleanup: if (path != NULL) { releasePlatformChars(env, jPath, path); } if (userSID != NULL) { LocalFree(userSID); } if (userSIDString != NULL) { releasePlatformChars(env, jUserSIDString, userSIDString); } // dacl points inside securityDescriptor if (securityDescriptor != NULL) { LocalFree(securityDescriptor); } }
JNIEXPORT void JNICALL Java_com_microsoft_tfs_jni_internal_filesystem_NativeFileSystem_nativeGrantInheritableFullControl( JNIEnv *env, jclass cls, jstring jPath, jstring jUserSIDString, jstring jCopyExplicitRulesFromPath) { const WCHAR * path = NULL; const WCHAR * userSIDString = NULL; const WCHAR * copyExplicitRulesFromPath = NULL; DWORD result = 0; PACL existingDACL = NULL; PACL newDACL = NULL; PSECURITY_DESCRIPTOR securityDescriptor = NULL; PSID userSID = NULL; EXPLICIT_ACCESS fullControl; if (jPath == NULL) { throwRuntimeExceptionString(env, "path must not be null"); goto cleanup; } if (jUserSIDString == NULL) { throwRuntimeExceptionString(env, "user must not be null"); goto cleanup; } // Get the existing DACL entries if (jCopyExplicitRulesFromPath != NULL) { if ((copyExplicitRulesFromPath = javaStringToPlatformChars(env, jCopyExplicitRulesFromPath)) == NULL) { // String allocation failed, exception already thrown goto cleanup; } result = GetNamedSecurityInfo(copyExplicitRulesFromPath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &existingDACL, NULL, &securityDescriptor); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error getting file security info for %S", copyExplicitRulesFromPath); goto cleanup; } } // Convert the string SID to a structure if ((userSIDString = javaStringToPlatformChars(env, jUserSIDString)) == NULL) { // String allocation failed, exception already thrown goto cleanup; } if (ConvertStringSidToSidW(userSIDString, &userSID) == FALSE) { throwRuntimeExceptionCode(env, GetLastError(), "Error converting string sid %S to sid", userSIDString); goto cleanup; } /* * Create a new explicit access entry with rights equivalent to .NET's * FileSystemRights.FullControl (0x1F01FF; see FileSecurity.cs) and * full inheritance. */ ZeroMemory(&fullControl, sizeof(EXPLICIT_ACCESS)); fullControl.grfAccessPermissions = 0x1F01FF; fullControl.grfAccessMode = GRANT_ACCESS; fullControl.grfInheritance= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE; fullControl.Trustee.TrusteeForm = TRUSTEE_IS_SID; fullControl.Trustee.TrusteeType = TRUSTEE_IS_USER; fullControl.Trustee.ptstrName = userSID; // Merge new entry with old entries into a new list result = SetEntriesInAcl(1, &fullControl, existingDACL, &newDACL); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error setting entries in ACL"); goto cleanup; } // Set the list on the path if ((path = javaStringToPlatformChars(env, jPath)) == NULL) { // String allocation failed, exception already thrown goto cleanup; } result = SetNamedSecurityInfo((WCHAR *) path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, newDACL, NULL); if (result != ERROR_SUCCESS) { throwRuntimeExceptionCode(env, result, "Error setting file security info for %S", path); goto cleanup; } cleanup: if (path != NULL) { releasePlatformChars(env, jPath, path); } if (userSIDString != NULL) { releasePlatformChars(env, jUserSIDString, userSIDString); } if (copyExplicitRulesFromPath != NULL) { releasePlatformChars(env, jCopyExplicitRulesFromPath, copyExplicitRulesFromPath); } if (securityDescriptor != NULL) { LocalFree(securityDescriptor); } if (userSID != NULL) { LocalFree(userSID); } if (newDACL != NULL) { LocalFree(newDACL); } // existingDACL points inside securityDescriptor }