/* * Copyright (c) 2000, 2013, 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. */ /* * =========================================================================== * (C) Copyright IBM Corp. 2000 All Rights Reserved. * =========================================================================== */ #define UNICODE #define _UNICODE #include #include #include #define SECURITY_WIN32 #include #include #include #include #include #include #include #undef LSA_SUCCESS #define LSA_SUCCESS(Status) ((Status) >= 0) #define EXIT_FAILURE -1 // mdu /* * Library-wide static references */ jclass derValueClass = NULL; jclass ticketClass = NULL; jclass principalNameClass = NULL; jclass encryptionKeyClass = NULL; jclass ticketFlagsClass = NULL; jclass kerberosTimeClass = NULL; jclass javaLangStringClass = NULL; jmethodID derValueConstructor = 0; jmethodID ticketConstructor = 0; jmethodID principalNameConstructor = 0; jmethodID encryptionKeyConstructor = 0; jmethodID ticketFlagsConstructor = 0; jmethodID kerberosTimeConstructor = 0; jmethodID krbcredsConstructor = 0; /* * Function prototypes for internal routines * */ BOOL native_debug = 0; BOOL PackageConnectLookup(PHANDLE,PULONG); NTSTATUS ConstructTicketRequest(UNICODE_STRING DomainName, PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize); DWORD ConcatenateUnicodeStrings(UNICODE_STRING *pTarget, UNICODE_STRING Source1, UNICODE_STRING Source2); VOID ShowNTError(LPSTR,NTSTATUS); VOID InitUnicodeString( PUNICODE_STRING DestinationString, PCWSTR SourceString OPTIONAL ); jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize); //mdu jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName, UNICODE_STRING domainName); jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey); jobject BuildTicketFlags(JNIEnv *env, PULONG flags); jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime); /* * Class: sun_security_krb5_KrbCreds * Method: JNI_OnLoad */ JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM *jvm, void *reserved) { jclass cls; JNIEnv *env; jfieldID fldDEBUG; if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) { return JNI_EVERSION; /* JNI version not supported */ } cls = (*env)->FindClass(env,"sun/security/krb5/internal/Krb5"); if (cls == NULL) { printf("LSA: Couldn't find Krb5\n"); return JNI_ERR; } fldDEBUG = (*env)->GetStaticFieldID(env, cls, "DEBUG", "Z"); if (fldDEBUG == NULL) { printf("LSA: Krb5 has no DEBUG field\n"); return JNI_ERR; } native_debug = (*env)->GetStaticBooleanField(env, cls, fldDEBUG); cls = (*env)->FindClass(env,"sun/security/krb5/internal/Ticket"); if (cls == NULL) { printf("LSA: Couldn't find Ticket\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found Ticket\n"); } ticketClass = (*env)->NewWeakGlobalRef(env,cls); if (ticketClass == NULL) { return JNI_ERR; } if (native_debug) { printf("LSA: Made NewWeakGlobalRef\n"); } cls = (*env)->FindClass(env, "sun/security/krb5/PrincipalName"); if (cls == NULL) { printf("LSA: Couldn't find PrincipalName\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found PrincipalName\n"); } principalNameClass = (*env)->NewWeakGlobalRef(env,cls); if (principalNameClass == NULL) { return JNI_ERR; } if (native_debug) { printf("LSA: Made NewWeakGlobalRef\n"); } cls = (*env)->FindClass(env,"sun/security/util/DerValue"); if (cls == NULL) { printf("LSA: Couldn't find DerValue\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found DerValue\n"); } derValueClass = (*env)->NewWeakGlobalRef(env,cls); if (derValueClass == NULL) { return JNI_ERR; } if (native_debug) { printf("LSA: Made NewWeakGlobalRef\n"); } cls = (*env)->FindClass(env,"sun/security/krb5/EncryptionKey"); if (cls == NULL) { printf("LSA: Couldn't find EncryptionKey\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found EncryptionKey\n"); } encryptionKeyClass = (*env)->NewWeakGlobalRef(env,cls); if (encryptionKeyClass == NULL) { return JNI_ERR; } if (native_debug) { printf("LSA: Made NewWeakGlobalRef\n"); } cls = (*env)->FindClass(env,"sun/security/krb5/internal/TicketFlags"); if (cls == NULL) { printf("LSA: Couldn't find TicketFlags\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found TicketFlags\n"); } ticketFlagsClass = (*env)->NewWeakGlobalRef(env,cls); if (ticketFlagsClass == NULL) { return JNI_ERR; } if (native_debug) { printf("LSA: Made NewWeakGlobalRef\n"); } cls = (*env)->FindClass(env,"sun/security/krb5/internal/KerberosTime"); if (cls == NULL) { printf("LSA: Couldn't find KerberosTime\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found KerberosTime\n"); } kerberosTimeClass = (*env)->NewWeakGlobalRef(env,cls); if (kerberosTimeClass == NULL) { return JNI_ERR; } if (native_debug) { printf("LSA: Made NewWeakGlobalRef\n"); } cls = (*env)->FindClass(env,"java/lang/String"); if (cls == NULL) { printf("LSA: Couldn't find String\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found String\n"); } javaLangStringClass = (*env)->NewWeakGlobalRef(env,cls); if (javaLangStringClass == NULL) { return JNI_ERR; } if (native_debug) { printf("LSA: Made NewWeakGlobalRef\n"); } derValueConstructor = (*env)->GetMethodID(env, derValueClass, "", "([B)V"); if (derValueConstructor == 0) { printf("LSA: Couldn't find DerValue constructor\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found DerValue constructor\n"); } ticketConstructor = (*env)->GetMethodID(env, ticketClass, "", "(Lsun/security/util/DerValue;)V"); if (ticketConstructor == 0) { printf("LSA: Couldn't find Ticket constructor\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found Ticket constructor\n"); } principalNameConstructor = (*env)->GetMethodID(env, principalNameClass, "", "([Ljava/lang/String;Ljava/lang/String;)V"); if (principalNameConstructor == 0) { printf("LSA: Couldn't find PrincipalName constructor\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found PrincipalName constructor\n"); } encryptionKeyConstructor = (*env)->GetMethodID(env, encryptionKeyClass, "", "(I[B)V"); if (encryptionKeyConstructor == 0) { printf("LSA: Couldn't find EncryptionKey constructor\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found EncryptionKey constructor\n"); } ticketFlagsConstructor = (*env)->GetMethodID(env, ticketFlagsClass, "", "(I[B)V"); if (ticketFlagsConstructor == 0) { printf("LSA: Couldn't find TicketFlags constructor\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found TicketFlags constructor\n"); } kerberosTimeConstructor = (*env)->GetMethodID(env, kerberosTimeClass, "", "(Ljava/lang/String;)V"); if (kerberosTimeConstructor == 0) { printf("LSA: Couldn't find KerberosTime constructor\n"); return JNI_ERR; } if (native_debug) { printf("LSA: Found KerberosTime constructor\n"); } if (native_debug) { printf("LSA: Finished OnLoad processing\n"); } return JNI_VERSION_1_2; } /* * Class: sun_security_jgss_KrbCreds * Method: JNI_OnUnload */ JNIEXPORT void JNICALL JNI_OnUnload( JavaVM *jvm, void *reserved) { JNIEnv *env; if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) { return; /* Nothing else we can do */ } if (ticketClass != NULL) { (*env)->DeleteWeakGlobalRef(env,ticketClass); } if (derValueClass != NULL) { (*env)->DeleteWeakGlobalRef(env,derValueClass); } if (principalNameClass != NULL) { (*env)->DeleteWeakGlobalRef(env,principalNameClass); } if (encryptionKeyClass != NULL) { (*env)->DeleteWeakGlobalRef(env,encryptionKeyClass); } if (ticketFlagsClass != NULL) { (*env)->DeleteWeakGlobalRef(env,ticketFlagsClass); } if (kerberosTimeClass != NULL) { (*env)->DeleteWeakGlobalRef(env,kerberosTimeClass); } if (javaLangStringClass != NULL) { (*env)->DeleteWeakGlobalRef(env,javaLangStringClass); } return; } /* * Class: sun_security_krb5_Credentials * Method: acquireDefaultNativeCreds * Signature: ([I])Lsun/security/krb5/Credentials; */ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds( JNIEnv *env, jclass krbcredsClass, jintArray jetypes) { KERB_QUERY_TKT_CACHE_REQUEST CacheRequest; PKERB_RETRIEVE_TKT_RESPONSE TktCacheResponse = NULL; PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL; PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL; NTSTATUS Status, SubStatus; ULONG requestSize = 0; ULONG responseSize = 0; ULONG rspSize = 0; HANDLE LogonHandle = NULL; ULONG PackageId; jobject ticket, clientPrincipal, targetPrincipal, encryptionKey; jobject ticketFlags, startTime, endTime, krbCreds = NULL; jobject authTime, renewTillTime, hostAddresses = NULL; KERB_EXTERNAL_TICKET *msticket; int found = 0; FILETIME Now, EndTime; int i, netypes; jint *etypes = NULL; while (TRUE) { if (krbcredsConstructor == 0) { krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "", "(Lsun/security/krb5/internal/Ticket;" "Lsun/security/krb5/PrincipalName;" "Lsun/security/krb5/PrincipalName;" "Lsun/security/krb5/EncryptionKey;" "Lsun/security/krb5/internal/TicketFlags;" "Lsun/security/krb5/internal/KerberosTime;" "Lsun/security/krb5/internal/KerberosTime;" "Lsun/security/krb5/internal/KerberosTime;" "Lsun/security/krb5/internal/KerberosTime;" "Lsun/security/krb5/internal/HostAddresses;)V"); if (krbcredsConstructor == 0) { printf("LSA: Couldn't find sun.security.krb5.Credentials constructor\n"); break; } } if (native_debug) { printf("LSA: Found KrbCreds constructor\n"); } // // Get the logon handle and package ID from the // Kerberos package // if (!PackageConnectLookup(&LogonHandle, &PackageId)) break; if (native_debug) { printf("LSA: Got handle to Kerberos package\n"); } // Get the MS TGT from cache CacheRequest.MessageType = KerbRetrieveTicketMessage; CacheRequest.LogonId.LowPart = 0; CacheRequest.LogonId.HighPart = 0; Status = LsaCallAuthenticationPackage( LogonHandle, PackageId, &CacheRequest, sizeof(CacheRequest), &TktCacheResponse, &rspSize, &SubStatus ); if (native_debug) { printf("LSA: Response size is %d\n", rspSize); } if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) { if (!LSA_SUCCESS(Status)) { ShowNTError("LsaCallAuthenticationPackage", Status); } else { ShowNTError("Protocol status", SubStatus); } break; } // got the native MS TGT msticket = &(TktCacheResponse->Ticket); netypes = (*env)->GetArrayLength(env, jetypes); etypes = (jint *) (*env)->GetIntArrayElements(env, jetypes, NULL); if (etypes == NULL) { break; } // check TGT validity if (native_debug) { printf("LSA: TICKET SessionKey KeyType is %d\n", msticket->SessionKey.KeyType); } if ((msticket->TicketFlags & KERB_TICKET_FLAGS_invalid) == 0) { GetSystemTimeAsFileTime(&Now); EndTime.dwLowDateTime = msticket->EndTime.LowPart; EndTime.dwHighDateTime = msticket->EndTime.HighPart; if (CompareFileTime(&Now, &EndTime) < 0) { for (i=0; iSessionKey.KeyType) { found = 1; if (native_debug) { printf("LSA: Valid etype found: %d\n", etypes[i]); } break; } } } } if (!found) { if (native_debug) { printf("LSA: MS TGT in cache is invalid/not supported; request new ticket\n"); } // use domain to request Ticket Status = ConstructTicketRequest(msticket->TargetDomainName, &pTicketRequest, &requestSize); if (!LSA_SUCCESS(Status)) { ShowNTError("ConstructTicketRequest status", Status); break; } pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage; pTicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_DONT_USE_CACHE; for (i=0; iEncryptionType = etypes[i]; Status = LsaCallAuthenticationPackage( LogonHandle, PackageId, pTicketRequest, requestSize, &pTicketResponse, &responseSize, &SubStatus ); if (native_debug) { printf("LSA: Response size is %d for %d\n", responseSize, etypes[i]); } if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) { if (!LSA_SUCCESS(Status)) { ShowNTError("LsaCallAuthenticationPackage", Status); } else { ShowNTError("Protocol status", SubStatus); } continue; } // got the native MS Kerberos TGT msticket = &(pTicketResponse->Ticket); if (msticket->SessionKey.KeyType != etypes[i]) { if (native_debug) { printf("LSA: Response etype is %d for %d. Retry.\n", msticket->SessionKey.KeyType, etypes[i]); } continue; } found = 1; break; } } if (etypes != NULL) { (*env)->ReleaseIntArrayElements(env, jetypes, etypes, 0); } /* typedef struct _KERB_RETRIEVE_TKT_RESPONSE { KERB_EXTERNAL_TICKET Ticket; } KERB_RETRIEVE_TKT_RESPONSE, *PKERB_RETRIEVE_TKT_RESPONSE; typedef struct _KERB_EXTERNAL_TICKET { PKERB_EXTERNAL_NAME ServiceName; PKERB_EXTERNAL_NAME TargetName; PKERB_EXTERNAL_NAME ClientName; UNICODE_STRING DomainName; UNICODE_STRING TargetDomainName; UNICODE_STRING AltTargetDomainName; KERB_CRYPTO_KEY SessionKey; ULONG TicketFlags; ULONG Flags; LARGE_INTEGER KeyExpirationTime; LARGE_INTEGER StartTime; LARGE_INTEGER EndTime; LARGE_INTEGER RenewUntil; LARGE_INTEGER TimeSkew; ULONG EncodedTicketSize; PUCHAR EncodedTicket; <========== Here's the good stuff } KERB_EXTERNAL_TICKET, *PKERB_EXTERNAL_TICKET; typedef struct _KERB_EXTERNAL_NAME { SHORT NameType; USHORT NameCount; UNICODE_STRING Names[ANYSIZE_ARRAY]; } KERB_EXTERNAL_NAME, *PKERB_EXTERNAL_NAME; typedef struct _LSA_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING; typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING; typedef struct KERB_CRYPTO_KEY { LONG KeyType; ULONG Length; PUCHAR Value; } KERB_CRYPTO_KEY, *PKERB_CRYPTO_KEY; */ if (!found) { break; } // Build a com.sun.security.krb5.Ticket ticket = BuildTicket(env, msticket->EncodedTicket, msticket->EncodedTicketSize); if (ticket == NULL) { break; } // OK, have a Ticket, now need to get the client name clientPrincipal = BuildPrincipal(env, msticket->ClientName, msticket->TargetDomainName); // mdu if (clientPrincipal == NULL) { break; } // and the "name" of tgt targetPrincipal = BuildPrincipal(env, msticket->ServiceName, msticket->DomainName); if (targetPrincipal == NULL) { break; } // Get the encryption key encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey)); if (encryptionKey == NULL) { break; } // and the ticket flags ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags)); if (ticketFlags == NULL) { break; } // Get the start time startTime = BuildKerberosTime(env, &(msticket->StartTime)); if (startTime == NULL) { break; } /* * mdu: No point storing the eky expiration time in the auth * time field. Set it to be same as startTime. Looks like * windows does not have post-dated tickets. */ authTime = startTime; // and the end time endTime = BuildKerberosTime(env, &(msticket->EndTime)); if (endTime == NULL) { break; } // Get the renew till time renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil)); if (renewTillTime == NULL) { break; } // and now go build a KrbCreds object krbCreds = (*env)->NewObject( env, krbcredsClass, krbcredsConstructor, ticket, clientPrincipal, targetPrincipal, encryptionKey, ticketFlags, authTime, // mdu startTime, endTime, renewTillTime, //mdu hostAddresses); break; } // end of WHILE. This WHILE will never loop. // clean up resources if (TktCacheResponse != NULL) { LsaFreeReturnBuffer(TktCacheResponse); } if (pTicketRequest) { LocalFree(pTicketRequest); } if (pTicketResponse != NULL) { LsaFreeReturnBuffer(pTicketResponse); } return krbCreds; } static NTSTATUS ConstructTicketRequest(UNICODE_STRING DomainName, PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize) { NTSTATUS Status; UNICODE_STRING TargetPrefix; USHORT TargetSize; ULONG RequestSize; ULONG Length; PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL; *outRequest = NULL; *outSize = 0; // // Set up the "krbtgt/" target prefix into a UNICODE_STRING so we // can easily concatenate it later. // TargetPrefix.Buffer = L"krbtgt/"; Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR); TargetPrefix.Length = (USHORT)Length; TargetPrefix.MaximumLength = TargetPrefix.Length; // // We will need to concatenate the "krbtgt/" prefix and the // Logon Session's DnsDomainName into our request's target name. // // Therefore, first compute the necessary buffer size for that. // // Note that we might theoretically have integer overflow. // TargetSize = TargetPrefix.Length + DomainName.Length; // // The ticket request buffer needs to be a single buffer. That buffer // needs to include the buffer for the target name. // RequestSize = sizeof (*pTicketRequest) + TargetSize; // // Allocate the request buffer and make sure it's zero-filled. // pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize); if (!pTicketRequest) return GetLastError(); // // Concatenate the target prefix with the previous response's // target domain. // pTicketRequest->TargetName.Length = 0; pTicketRequest->TargetName.MaximumLength = TargetSize; pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1); Status = ConcatenateUnicodeStrings(&(pTicketRequest->TargetName), TargetPrefix, DomainName); *outRequest = pTicketRequest; *outSize = RequestSize; return Status; } DWORD ConcatenateUnicodeStrings( UNICODE_STRING *pTarget, UNICODE_STRING Source1, UNICODE_STRING Source2 ) { // // The buffers for Source1 and Source2 cannot overlap pTarget's // buffer. Source1.Length + Source2.Length must be <= 0xFFFF, // otherwise we overflow... // USHORT TotalSize = Source1.Length + Source2.Length; PBYTE buffer = (PBYTE) pTarget->Buffer; if (TotalSize > pTarget->MaximumLength) return ERROR_INSUFFICIENT_BUFFER; pTarget->Length = TotalSize; memcpy(buffer, Source1.Buffer, Source1.Length); memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length); return ERROR_SUCCESS; } BOOL PackageConnectLookup( HANDLE *pLogonHandle, ULONG *pPackageId ) { LSA_STRING Name; NTSTATUS Status; Status = LsaConnectUntrusted( pLogonHandle ); if (!LSA_SUCCESS(Status)) { ShowNTError("LsaConnectUntrusted", Status); return FALSE; } Name.Buffer = MICROSOFT_KERBEROS_NAME_A; Name.Length = (USHORT)strlen(Name.Buffer); Name.MaximumLength = Name.Length + 1; Status = LsaLookupAuthenticationPackage( *pLogonHandle, &Name, pPackageId ); if (!LSA_SUCCESS(Status)) { ShowNTError("LsaLookupAuthenticationPackage", Status); return FALSE; } return TRUE; } VOID ShowLastError( LPSTR szAPI, DWORD dwError ) { #define MAX_MSG_SIZE 256 static WCHAR szMsgBuf[MAX_MSG_SIZE]; DWORD dwRes; if (native_debug) { printf("LSA: Error calling function %s: %lu\n", szAPI, dwError); } dwRes = FormatMessage ( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, szMsgBuf, MAX_MSG_SIZE, NULL); if (native_debug) { if (0 == dwRes) { printf("LSA: FormatMessage failed with %d\n", GetLastError()); // ExitProcess(EXIT_FAILURE); } else { printf("LSA: %S",szMsgBuf); } } } VOID ShowNTError( LPSTR szAPI, NTSTATUS Status ) { // // Convert the NTSTATUS to Winerror. Then call ShowLastError(). // ShowLastError(szAPI, LsaNtStatusToWinError(Status)); } VOID InitUnicodeString( PUNICODE_STRING DestinationString, PCWSTR SourceString OPTIONAL ) { ULONG Length; DestinationString->Buffer = (PWSTR)SourceString; if (SourceString != NULL) { Length = (ULONG)wcslen( SourceString ) * sizeof( WCHAR ); DestinationString->Length = (USHORT)Length; DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL)); } else { DestinationString->MaximumLength = 0; DestinationString->Length = 0; } } jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize) { /* To build a Ticket, we first need to build a DerValue out of the EncodedTicket. * But before we can do that, we need to make a byte array out of the ET. */ jobject derValue, ticket; jbyteArray ary; ary = (*env)->NewByteArray(env,encodedTicketSize); if ((*env)->ExceptionOccurred(env)) { return (jobject) NULL; } (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize, (jbyte *)encodedTicket); if ((*env)->ExceptionOccurred(env)) { (*env)->DeleteLocalRef(env, ary); return (jobject) NULL; } derValue = (*env)->NewObject(env, derValueClass, derValueConstructor, ary); if ((*env)->ExceptionOccurred(env)) { (*env)->DeleteLocalRef(env, ary); return (jobject) NULL; } (*env)->DeleteLocalRef(env, ary); ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, derValue); if ((*env)->ExceptionOccurred(env)) { (*env)->DeleteLocalRef(env, derValue); return (jobject) NULL; } (*env)->DeleteLocalRef(env, derValue); return ticket; } // mdu jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName, UNICODE_STRING domainName) { /* * To build the Principal, we need to get the names out of * this goofy MS structure */ jobject principal = NULL; jobject realmStr = NULL; jobjectArray stringArray; jstring tempString; int nameCount,i; PUNICODE_STRING scanner; WCHAR *realm; ULONG realmLen; realm = (WCHAR *) LocalAlloc(LMEM_ZEROINIT, ((domainName.Length)*sizeof(WCHAR) + sizeof(UNICODE_NULL))); wcsncpy(realm, domainName.Buffer, domainName.Length/sizeof(WCHAR)); if (native_debug) { printf("LSA: Principal domain is %S\n", realm); printf("LSA: Name type is %x\n", principalName->NameType); printf("LSA: Name count is %x\n", principalName->NameCount); } nameCount = principalName->NameCount; stringArray = (*env)->NewObjectArray(env, nameCount, javaLangStringClass, NULL); if (stringArray == NULL) { if (native_debug) { printf("LSA: Can't allocate String array for Principal\n"); } goto cleanup; } for (i=0; iNames[i]); // OK, got a Char array, so construct a String tempString = (*env)->NewString(env, (const jchar*)scanner->Buffer, scanner->Length/sizeof(WCHAR)); if (tempString == NULL) { goto cleanup; } // Set the String into the StringArray (*env)->SetObjectArrayElement(env, stringArray, i, tempString); if ((*env)->ExceptionCheck(env)) { goto cleanup; } // Do I have to worry about storage reclamation here? } // now set the realm in the principal realmLen = (ULONG)wcslen((PWCHAR)realm); realmStr = (*env)->NewString(env, (PWCHAR)realm, (USHORT)realmLen); if (realmStr == NULL) { goto cleanup; } principal = (*env)->NewObject(env, principalNameClass, principalNameConstructor, stringArray, realmStr); cleanup: // free local resources LocalFree(realm); return principal; } jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) { // First, need to build a byte array jbyteArray ary; jobject encryptionKey = NULL; unsigned int i; for (i=0; iLength; i++) { if (cryptoKey->Value[i]) break; } if (i == cryptoKey->Length) { if (native_debug) { printf("LSA: Session key all zero. Stop.\n"); } return NULL; } ary = (*env)->NewByteArray(env,cryptoKey->Length); (*env)->SetByteArrayRegion(env, ary, (jsize) 0, cryptoKey->Length, (jbyte *)cryptoKey->Value); if ((*env)->ExceptionOccurred(env)) { (*env)->DeleteLocalRef(env, ary); } else { encryptionKey = (*env)->NewObject(env, encryptionKeyClass, encryptionKeyConstructor, cryptoKey->KeyType, ary); } return encryptionKey; } jobject BuildTicketFlags(JNIEnv *env, PULONG flags) { jobject ticketFlags = NULL; jbyteArray ary; /* * mdu: Convert the bytes to nework byte order before copying * them to a Java byte array. */ ULONG nlflags = htonl(*flags); ary = (*env)->NewByteArray(env, sizeof(*flags)); (*env)->SetByteArrayRegion(env, ary, (jsize) 0, sizeof(*flags), (jbyte *)&nlflags); if ((*env)->ExceptionOccurred(env)) { (*env)->DeleteLocalRef(env, ary); } else { ticketFlags = (*env)->NewObject(env, ticketFlagsClass, ticketFlagsConstructor, sizeof(*flags)*8, ary); } return ticketFlags; } jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) { jobject kerberosTime = NULL; jstring stringTime = NULL; SYSTEMTIME systemTime; WCHAR timeString[16]; WCHAR month[3]; WCHAR day[3]; WCHAR hour[3]; WCHAR minute[3]; WCHAR second[3]; if (FileTimeToSystemTime((FILETIME *)kerbtime, &systemTime)) { // XXX Cannot use %02.2ld, because the leading 0 is ignored for integers. // So, print them to strings, and then print them to the master string with a // format pattern that makes it two digits and prefix with a 0 if necessary. swprintf( (wchar_t *)month, 3, L"%2.2d", systemTime.wMonth); swprintf( (wchar_t *)day, 3, L"%2.2d", systemTime.wDay); swprintf( (wchar_t *)hour, 3, L"%2.2d", systemTime.wHour); swprintf( (wchar_t *)minute, 3, L"%2.2d", systemTime.wMinute); swprintf( (wchar_t *)second, 3, L"%2.2d", systemTime.wSecond); swprintf( (wchar_t *)timeString, 16, L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ", systemTime.wYear, month, day, hour, minute, second ); if (native_debug) { printf("LSA: %S\n", (wchar_t *)timeString); } stringTime = (*env)->NewString(env, timeString, (sizeof(timeString)/sizeof(WCHAR))-1); if (stringTime != NULL) { // everything's OK so far kerberosTime = (*env)->NewObject(env, kerberosTimeClass, kerberosTimeConstructor, stringTime); } } return kerberosTime; }