/* * Copyright (c) 2000, 2015, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 "jni_util.h" #include "com_sun_security_auth_module_NTSystem.h" #include #include #include #include #include static BOOL debug = FALSE; BOOL getToken(PHANDLE); BOOL getUser(HANDLE tokenHandle, LPTSTR *userName, LPTSTR *domainName, LPTSTR *userSid, LPTSTR *domainSid); BOOL getPrimaryGroup(HANDLE tokenHandle, LPTSTR *primaryGroup); BOOL getGroups(HANDLE tokenHandle, PDWORD numGroups, LPTSTR **groups); BOOL getImpersonationToken(PHANDLE impersonationToken); BOOL getTextualSid(PSID pSid, LPTSTR TextualSid, LPDWORD lpdwBufferLen); void DisplayErrorText(DWORD dwLastError); static void throwIllegalArgumentException(JNIEnv *env, const char *msg) { jclass clazz = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); if (clazz != NULL) (*env)->ThrowNew(env, clazz, msg); } /* * Declare library specific JNI_Onload entry if static build */ DEF_STATIC_JNI_OnLoad JNIEXPORT jlong JNICALL Java_com_sun_security_auth_module_NTSystem_getImpersonationToken0 (JNIEnv *env, jobject obj) { HANDLE impersonationToken = 0; // impersonation token if (debug) { printf("getting impersonation token\n"); } if (getImpersonationToken(&impersonationToken) == FALSE) { return 0; } return (jlong)impersonationToken; } JNIEXPORT void JNICALL Java_com_sun_security_auth_module_NTSystem_getCurrent (JNIEnv *env, jobject obj, jboolean debugNative) { long i, j = 0; HANDLE tokenHandle = INVALID_HANDLE_VALUE; LPTSTR userName = NULL; // user name LPTSTR userSid = NULL; // user sid LPTSTR domainName = NULL; // domain name LPTSTR domainSid = NULL; // domain sid LPTSTR primaryGroup = NULL; // primary group sid DWORD numGroups = 0; // num groups LPTSTR *groups = NULL; // groups array long pIndex = -1; // index of primaryGroup in groups array jfieldID fid; jstring jstr; jobjectArray jgroups; jclass stringClass = 0; jclass cls = (*env)->GetObjectClass(env, obj); debug = debugNative; // get NT information first if (debug) { printf("getting access token\n"); } if (getToken(&tokenHandle) == FALSE) { return; } if (debug) { printf("getting user info\n"); } if (getUser (tokenHandle, &userName, &domainName, &userSid, &domainSid) == FALSE) { return; } if (debug) { printf("getting primary group\n"); } if (getPrimaryGroup(tokenHandle, &primaryGroup) == FALSE) { return; } if (debug) { printf("getting supplementary groups\n"); } if (getGroups(tokenHandle, &numGroups, &groups) == FALSE) { return; } // then set values into NTSystem fid = (*env)->GetFieldID(env, cls, "userName", "Ljava/lang/String;"); if (fid == 0) { (*env)->ExceptionClear(env); throwIllegalArgumentException(env, "invalid field: userName"); goto cleanup; } jstr = (*env)->NewStringUTF(env, userName); if (jstr == NULL) goto cleanup; (*env)->SetObjectField(env, obj, fid, jstr); fid = (*env)->GetFieldID(env, cls, "userSID", "Ljava/lang/String;"); if (fid == 0) { (*env)->ExceptionClear(env); throwIllegalArgumentException(env, "invalid field: userSID"); goto cleanup; } jstr = (*env)->NewStringUTF(env, userSid); if (jstr == NULL) goto cleanup; (*env)->SetObjectField(env, obj, fid, jstr); fid = (*env)->GetFieldID(env, cls, "domain", "Ljava/lang/String;"); if (fid == 0) { (*env)->ExceptionClear(env); throwIllegalArgumentException(env, "invalid field: domain"); goto cleanup; } jstr = (*env)->NewStringUTF(env, domainName); if (jstr == NULL) goto cleanup; (*env)->SetObjectField(env, obj, fid, jstr); if (domainSid != NULL) { fid = (*env)->GetFieldID(env, cls, "domainSID", "Ljava/lang/String;"); if (fid == 0) { (*env)->ExceptionClear(env); throwIllegalArgumentException(env, "invalid field: domainSID"); goto cleanup; } jstr = (*env)->NewStringUTF(env, domainSid); if (jstr == NULL) goto cleanup; (*env)->SetObjectField(env, obj, fid, jstr); } fid = (*env)->GetFieldID(env, cls, "primaryGroupID", "Ljava/lang/String;"); if (fid == 0) { (*env)->ExceptionClear(env); throwIllegalArgumentException(env, "invalid field: PrimaryGroupID"); goto cleanup; } jstr = (*env)->NewStringUTF(env, primaryGroup); if (jstr == NULL) goto cleanup; (*env)->SetObjectField(env, obj, fid, jstr); // primary group may or may not be part of supplementary groups for (i = 0; i < (long)numGroups; i++) { if (strcmp(primaryGroup, groups[i]) == 0) { // found primary group in groups array pIndex = i; break; } } if (numGroups == 0 || (pIndex == 0 && numGroups == 1)) { // primary group is only group in groups array if (debug) { printf("no secondary groups\n"); } } else { // the groups array is non-empty, // and may or may not contain the primary group fid = (*env)->GetFieldID(env, cls, "groupIDs", "[Ljava/lang/String;"); if (fid == 0) { (*env)->ExceptionClear(env); throwIllegalArgumentException(env, "groupIDs"); goto cleanup; } stringClass = (*env)->FindClass(env, "java/lang/String"); if (stringClass == NULL) goto cleanup; if (pIndex == -1) { // primary group not in groups array jgroups = (*env)->NewObjectArray(env, numGroups, stringClass, 0); } else { // primary group in groups array - // allocate one less array entry and do not add into new array jgroups = (*env)->NewObjectArray(env, numGroups-1, stringClass, 0); } if (jgroups == NULL) goto cleanup; for (i = 0, j = 0; i < (long)numGroups; i++) { if (pIndex == i) { // continue if equal to primary group continue; } jstr = (*env)->NewStringUTF(env, groups[i]); if (jstr == NULL) goto cleanup; (*env)->SetObjectArrayElement(env, jgroups, j++, jstr); } (*env)->SetObjectField(env, obj, fid, jgroups); } cleanup: if (userName != NULL) { HeapFree(GetProcessHeap(), 0, userName); } if (domainName != NULL) { HeapFree(GetProcessHeap(), 0, domainName); } if (userSid != NULL) { HeapFree(GetProcessHeap(), 0, userSid); } if (domainSid != NULL) { HeapFree(GetProcessHeap(), 0, domainSid); } if (primaryGroup != NULL) { HeapFree(GetProcessHeap(), 0, primaryGroup); } if (groups != NULL) { for (i = 0; i < (long)numGroups; i++) { if (groups[i] != NULL) { HeapFree(GetProcessHeap(), 0, groups[i]); } } HeapFree(GetProcessHeap(), 0, groups); } CloseHandle(tokenHandle); return; } BOOL getToken(PHANDLE tokenHandle) { // first try the thread token if (OpenThreadToken(GetCurrentThread(), TOKEN_READ, FALSE, tokenHandle) == 0) { if (debug) { printf(" [getToken] OpenThreadToken error [%d]: ", GetLastError()); DisplayErrorText(GetLastError()); } // next try the process token if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, tokenHandle) == 0) { if (debug) { printf(" [getToken] OpenProcessToken error [%d]: ", GetLastError()); DisplayErrorText(GetLastError()); } return FALSE; } } if (debug) { printf(" [getToken] got user access token\n"); } return TRUE; } BOOL getUser(HANDLE tokenHandle, LPTSTR *userName, LPTSTR *domainName, LPTSTR *userSid, LPTSTR *domainSid) { BOOL error = FALSE; DWORD bufSize = 0; DWORD buf2Size = 0; DWORD retBufSize = 0; PTOKEN_USER tokenUserInfo = NULL; // getTokenInformation SID_NAME_USE nameUse; // LookupAccountSid PSID dSid = NULL; LPTSTR domainSidName = NULL; // get token information GetTokenInformation(tokenHandle, TokenUser, NULL, // TokenInformation - if NULL get buffer size 0, // since TokenInformation is NULL &bufSize); tokenUserInfo = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, bufSize); if (GetTokenInformation(tokenHandle, TokenUser, tokenUserInfo, bufSize, &retBufSize) == 0) { if (debug) { printf(" [getUser] GetTokenInformation error [%d]: ", GetLastError()); DisplayErrorText(GetLastError()); } error = TRUE; goto cleanup; } if (debug) { printf(" [getUser] Got TokenUser info\n"); } // get userName bufSize = 0; buf2Size = 0; LookupAccountSid(NULL, // local host tokenUserInfo->User.Sid, NULL, &bufSize, NULL, &buf2Size, &nameUse); *userName = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, bufSize); *domainName = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, buf2Size); if (LookupAccountSid(NULL, // local host tokenUserInfo->User.Sid, *userName, &bufSize, *domainName, &buf2Size, &nameUse) == 0) { if (debug) { printf(" [getUser] LookupAccountSid error [%d]: ", GetLastError()); DisplayErrorText(GetLastError()); } error = TRUE; goto cleanup; } if (debug) { printf(" [getUser] userName: %s, domainName = %s\n", *userName, *domainName); } bufSize = 0; getTextualSid(tokenUserInfo->User.Sid, NULL, &bufSize); *userSid = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, bufSize); getTextualSid(tokenUserInfo->User.Sid, *userSid, &bufSize); if (debug) { printf(" [getUser] userSid: %s\n", *userSid); } // get domainSid bufSize = 0; buf2Size = 0; LookupAccountName(NULL, // local host *domainName, NULL, &bufSize, NULL, &buf2Size, &nameUse); dSid = (PSID)HeapAlloc(GetProcessHeap(), 0, bufSize); domainSidName = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, buf2Size); if (LookupAccountName(NULL, // local host *domainName, dSid, &bufSize, domainSidName, &buf2Size, &nameUse) == 0) { if (debug) { printf(" [getUser] LookupAccountName error [%d]: ", GetLastError()); DisplayErrorText(GetLastError()); } // ok not to have a domain SID (no error) goto cleanup; } bufSize = 0; getTextualSid(dSid, NULL, &bufSize); *domainSid = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, bufSize); getTextualSid(dSid, *domainSid, &bufSize); if (debug) { printf(" [getUser] domainSid: %s\n", *domainSid); } cleanup: if (tokenUserInfo != NULL) { HeapFree(GetProcessHeap(), 0, tokenUserInfo); } if (dSid != NULL) { HeapFree(GetProcessHeap(), 0, dSid); } if (domainSidName != NULL) { HeapFree(GetProcessHeap(), 0, domainSidName); } if (error) { return FALSE; } return TRUE; } BOOL getPrimaryGroup(HANDLE tokenHandle, LPTSTR *primaryGroup) { BOOL error = FALSE; DWORD bufSize = 0; DWORD retBufSize = 0; PTOKEN_PRIMARY_GROUP tokenGroupInfo = NULL; // get token information GetTokenInformation(tokenHandle, TokenPrimaryGroup, NULL, // TokenInformation - if NULL get buffer size 0, // since TokenInformation is NULL &bufSize); tokenGroupInfo = (PTOKEN_PRIMARY_GROUP)HeapAlloc (GetProcessHeap(), 0, bufSize); if (GetTokenInformation(tokenHandle, TokenPrimaryGroup, tokenGroupInfo, bufSize, &retBufSize) == 0) { if (debug) { printf(" [getPrimaryGroup] GetTokenInformation error [%d]: ", GetLastError()); DisplayErrorText(GetLastError()); } error = TRUE; goto cleanup; } if (debug) { printf(" [getPrimaryGroup] Got TokenPrimaryGroup info\n"); } bufSize = 0; getTextualSid(tokenGroupInfo->PrimaryGroup, NULL, &bufSize); *primaryGroup = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, bufSize); getTextualSid(tokenGroupInfo->PrimaryGroup, *primaryGroup, &bufSize); if (debug) { printf(" [getPrimaryGroup] primaryGroup: %s\n", *primaryGroup); } cleanup: if (tokenGroupInfo != NULL) { HeapFree(GetProcessHeap(), 0, tokenGroupInfo); } if (error) { return FALSE; } return TRUE; } BOOL getGroups(HANDLE tokenHandle, PDWORD numGroups, LPTSTR **groups) { BOOL error = FALSE; DWORD bufSize = 0; DWORD retBufSize = 0; long i = 0; PTOKEN_GROUPS tokenGroupInfo = NULL; // get token information GetTokenInformation(tokenHandle, TokenGroups, NULL, // TokenInformation - if NULL get buffer size 0, // since TokenInformation is NULL &bufSize); tokenGroupInfo = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), 0, bufSize); if (GetTokenInformation(tokenHandle, TokenGroups, tokenGroupInfo, bufSize, &retBufSize) == 0) { if (debug) { printf(" [getGroups] GetTokenInformation error [%d]: ", GetLastError()); DisplayErrorText(GetLastError()); } error = TRUE; goto cleanup; } if (debug) { printf(" [getGroups] Got TokenGroups info\n"); } if (tokenGroupInfo->GroupCount == 0) { // no groups goto cleanup; } // return group info *numGroups = tokenGroupInfo->GroupCount; *groups = (LPTSTR *)HeapAlloc (GetProcessHeap(), 0, (*numGroups) * sizeof(LPTSTR)); for (i = 0; i < (long)*numGroups; i++) { bufSize = 0; getTextualSid(tokenGroupInfo->Groups[i].Sid, NULL, &bufSize); (*groups)[i] = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, bufSize); getTextualSid(tokenGroupInfo->Groups[i].Sid, (*groups)[i], &bufSize); if (debug) { printf(" [getGroups] group %d: %s\n", i, (*groups)[i]); } } cleanup: if (tokenGroupInfo != NULL) { HeapFree(GetProcessHeap(), 0, tokenGroupInfo); } if (error) { return FALSE; } return TRUE; } BOOL getImpersonationToken(PHANDLE impersonationToken) { HANDLE dupToken; if (OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE, FALSE, &dupToken) == 0) { if (OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &dupToken) == 0) { if (debug) { printf (" [getImpersonationToken] OpenProcessToken error [%d]: ", GetLastError()); DisplayErrorText(GetLastError()); } return FALSE; } } if (DuplicateToken(dupToken, SecurityImpersonation, impersonationToken) == 0) { if (debug) { printf(" [getImpersonationToken] DuplicateToken error [%d]: ", GetLastError()); DisplayErrorText(GetLastError()); } return FALSE; } CloseHandle(dupToken); if (debug) { printf(" [getImpersonationToken] token = %p\n", (void *)*impersonationToken); } return TRUE; } BOOL getTextualSid (PSID pSid, // binary SID LPTSTR TextualSid, // buffer for Textual representation of SID LPDWORD lpdwBufferLen) { // required/provided TextualSid buffersize PSID_IDENTIFIER_AUTHORITY psia; DWORD dwSubAuthorities; DWORD dwSidRev=SID_REVISION; DWORD dwCounter; DWORD dwSidSize; // Validate the binary SID. if(!IsValidSid(pSid)) return FALSE; // Get the identifier authority value from the SID. psia = GetSidIdentifierAuthority(pSid); // Get the number of subauthorities in the SID. dwSubAuthorities = *GetSidSubAuthorityCount(pSid); // Compute the buffer length. // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR); // Check input buffer length. // If too small, indicate the proper size and set last error. if (*lpdwBufferLen < dwSidSize) { *lpdwBufferLen = dwSidSize; SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } // Add 'S' prefix and revision number to the string. dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev ); // Add SID identifier authority to the string. if ((psia->Value[0] != 0) || (psia->Value[1] != 0)) { dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid), TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"), (USHORT)psia->Value[0], (USHORT)psia->Value[1], (USHORT)psia->Value[2], (USHORT)psia->Value[3], (USHORT)psia->Value[4], (USHORT)psia->Value[5]); } else { dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid), TEXT("%lu"), (ULONG)(psia->Value[5] ) + (ULONG)(psia->Value[4] << 8) + (ULONG)(psia->Value[3] << 16) + (ULONG)(psia->Value[2] << 24) ); } // Add SID subauthorities to the string. for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++) { dwSidSize+=wsprintf(TextualSid + dwSidSize, TEXT("-%lu"), *GetSidSubAuthority(pSid, dwCounter) ); } return TRUE; } void DisplayErrorText(DWORD dwLastError) { HMODULE hModule = NULL; // default to system source LPSTR MessageBuffer; DWORD dwBufferLength; DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM ; // // If dwLastError is in the network range, // load the message source. // if(dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) { hModule = LoadLibraryEx(TEXT("netmsg.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE); if(hModule != NULL) dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE; } // // Call FormatMessage() to allow for message // text to be acquired from the system // or from the supplied module handle. // if(dwBufferLength = FormatMessageA(dwFormatFlags, hModule, // module to get message from (NULL == system) dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language (LPSTR) &MessageBuffer, 0, NULL)) { DWORD dwBytesWritten; // // Output message string on stderr. // WriteFile(GetStdHandle(STD_ERROR_HANDLE), MessageBuffer, dwBufferLength, &dwBytesWritten, NULL); // // Free the buffer allocated by the system. // LocalFree(MessageBuffer); } // // If we loaded a message source, unload it. // if(hModule != NULL) FreeLibrary(hModule); } /** * 1. comment out first two #includes * 2. set 'debug' to TRUE * 3. comment out 'getCurrent' * 4. uncomment 'main' * 5. cc -c nt.c * 6. link nt.obj user32.lib advapi32.lib /out:nt.exe */ /* void main(int argc, char *argv[]) { long i = 0; HANDLE tokenHandle = INVALID_HANDLE_VALUE; LPTSTR userName = NULL; LPTSTR userSid = NULL; LPTSTR domainName = NULL; LPTSTR domainSid = NULL; LPTSTR primaryGroup = NULL; DWORD numGroups = 0; LPTSTR *groups = NULL; HANDLE impersonationToken = 0; printf("getting access token\n"); if (getToken(&tokenHandle) == FALSE) { exit(1); } printf("getting user info\n"); if (getUser (tokenHandle, &userName, &domainName, &userSid, &domainSid) == FALSE) { exit(1); } printf("getting primary group\n"); if (getPrimaryGroup(tokenHandle, &primaryGroup) == FALSE) { exit(1); } printf("getting supplementary groups\n"); if (getGroups(tokenHandle, &numGroups, &groups) == FALSE) { exit(1); } printf("getting impersonation token\n"); if (getImpersonationToken(&impersonationToken) == FALSE) { exit(1); } printf("userName = %s, userSid = %s, domainName = %s, domainSid = %s\n", userName, userSid, domainName, domainSid); printf("primaryGroup = %s\n", primaryGroup); for (i = 0; i < numGroups; i++) { printf("Group[%d] = %s\n", i, groups[i]); } printf("impersonationToken = %ld\n", impersonationToken); if (userName != NULL) { HeapFree(GetProcessHeap(), 0, userName); } if (userSid != NULL) { HeapFree(GetProcessHeap(), 0, userSid); } if (domainName != NULL) { HeapFree(GetProcessHeap(), 0, domainName); } if (domainSid != NULL) { HeapFree(GetProcessHeap(), 0, domainSid); } if (primaryGroup != NULL) { HeapFree(GetProcessHeap(), 0, primaryGroup); } if (groups != NULL) { for (i = 0; i < numGroups; i++) { if (groups[i] != NULL) { HeapFree(GetProcessHeap(), 0, groups[i]); } } HeapFree(GetProcessHeap(), 0, groups); } CloseHandle(impersonationToken); CloseHandle(tokenHandle); } */ /** * extra main method for testing debug printing */ /* void main(int argc, char *argv[]) { if(argc != 2) { fprintf(stderr,"Usage: %s \n", argv[0]); } DisplayErrorText(atoi(argv[1])); } */