diff -r 4ebc2e2fb97c -r 71c04702a3d5 src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,1091 @@ +/* + * 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. + */ + +/* + * =========================================================================== + * (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 "jni_util.h" +#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 DEF_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 DEF_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; +}