Path: blob/master/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c
41149 views
/*1* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* ===========================================================================27* (C) Copyright IBM Corp. 2000 All Rights Reserved.28* ===========================================================================29*/3031#define UNICODE32#define _UNICODE3334#include <windows.h>35#include <stdio.h>36#include <string.h>37#define SECURITY_WIN3238#include <security.h>39#include <ntsecapi.h>40#include <dsgetdc.h>41#include <lmcons.h>42#include <lmapibuf.h>43#include <jni.h>44#include "jni_util.h"45#include <winsock.h>46#include "sun_security_krb5_Credentials.h"4748#undef LSA_SUCCESS49#define LSA_SUCCESS(Status) ((Status) >= 0)50#define EXIT_FAILURE -1 // mdu5152/*53* Library-wide static references54*/5556jclass ticketClass = NULL;57jclass principalNameClass = NULL;58jclass encryptionKeyClass = NULL;59jclass ticketFlagsClass = NULL;60jclass kerberosTimeClass = NULL;61jclass javaLangStringClass = NULL;6263jmethodID ticketConstructor = 0;64jmethodID principalNameConstructor = 0;65jmethodID encryptionKeyConstructor = 0;66jmethodID ticketFlagsConstructor = 0;67jmethodID kerberosTimeConstructor = 0;68jmethodID krbcredsConstructor = 0;6970/*71* Function prototypes for internal routines72*73*/74BOOL native_debug = 0;7576BOOL PackageConnectLookup(PHANDLE,PULONG);7778NTSTATUS ConstructTicketRequest(JNIEnv *env,79UNICODE_STRING DomainName,80PKERB_RETRIEVE_TKT_REQUEST *outRequest,81ULONG *outSize);8283DWORD ConcatenateUnicodeStrings(UNICODE_STRING *pTarget,84UNICODE_STRING Source1,85UNICODE_STRING Source2);8687VOID ShowNTError(LPSTR,NTSTATUS);8889VOID90InitUnicodeString(91PUNICODE_STRING DestinationString,92PCWSTR SourceString OPTIONAL93);9495jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize);9697//mdu98jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,99UNICODE_STRING domainName);100101jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey);102jobject BuildTicketFlags(JNIEnv *env, PULONG flags);103jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime);104105void ThrowOOME(JNIEnv *env, const char *szMessage);106107/*108* Class: sun_security_krb5_KrbCreds109* Method: JNI_OnLoad110*/111112JNIEXPORT jint JNICALL DEF_JNI_OnLoad(113JavaVM *jvm,114void *reserved) {115116jclass cls;117JNIEnv *env;118jfieldID fldDEBUG;119120if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {121return JNI_EVERSION; /* JNI version not supported */122}123124cls = (*env)->FindClass(env,"sun/security/krb5/internal/Krb5");125if (cls == NULL) {126printf("LSA: Couldn't find Krb5\n");127return JNI_ERR;128}129fldDEBUG = (*env)->GetStaticFieldID(env, cls, "DEBUG", "Z");130if (fldDEBUG == NULL) {131printf("LSA: Krb5 has no DEBUG field\n");132return JNI_ERR;133}134native_debug = (*env)->GetStaticBooleanField(env, cls, fldDEBUG);135136cls = (*env)->FindClass(env,"sun/security/krb5/internal/Ticket");137138if (cls == NULL) {139printf("LSA: Couldn't find Ticket\n");140return JNI_ERR;141}142if (native_debug) {143printf("LSA: Found Ticket\n");144}145146ticketClass = (*env)->NewWeakGlobalRef(env,cls);147if (ticketClass == NULL) {148return JNI_ERR;149}150if (native_debug) {151printf("LSA: Made NewWeakGlobalRef\n");152}153154cls = (*env)->FindClass(env, "sun/security/krb5/PrincipalName");155156if (cls == NULL) {157printf("LSA: Couldn't find PrincipalName\n");158return JNI_ERR;159}160if (native_debug) {161printf("LSA: Found PrincipalName\n");162}163164principalNameClass = (*env)->NewWeakGlobalRef(env,cls);165if (principalNameClass == NULL) {166return JNI_ERR;167}168if (native_debug) {169printf("LSA: Made NewWeakGlobalRef\n");170}171172cls = (*env)->FindClass(env,"sun/security/krb5/EncryptionKey");173174if (cls == NULL) {175printf("LSA: Couldn't find EncryptionKey\n");176return JNI_ERR;177}178if (native_debug) {179printf("LSA: Found EncryptionKey\n");180}181182encryptionKeyClass = (*env)->NewWeakGlobalRef(env,cls);183if (encryptionKeyClass == NULL) {184return JNI_ERR;185}186if (native_debug) {187printf("LSA: Made NewWeakGlobalRef\n");188}189190cls = (*env)->FindClass(env,"sun/security/krb5/internal/TicketFlags");191192if (cls == NULL) {193printf("LSA: Couldn't find TicketFlags\n");194return JNI_ERR;195}196if (native_debug) {197printf("LSA: Found TicketFlags\n");198}199200ticketFlagsClass = (*env)->NewWeakGlobalRef(env,cls);201if (ticketFlagsClass == NULL) {202return JNI_ERR;203}204if (native_debug) {205printf("LSA: Made NewWeakGlobalRef\n");206}207208cls = (*env)->FindClass(env,"sun/security/krb5/internal/KerberosTime");209210if (cls == NULL) {211printf("LSA: Couldn't find KerberosTime\n");212return JNI_ERR;213}214if (native_debug) {215printf("LSA: Found KerberosTime\n");216}217218kerberosTimeClass = (*env)->NewWeakGlobalRef(env,cls);219if (kerberosTimeClass == NULL) {220return JNI_ERR;221}222if (native_debug) {223printf("LSA: Made NewWeakGlobalRef\n");224}225226cls = (*env)->FindClass(env,"java/lang/String");227228if (cls == NULL) {229printf("LSA: Couldn't find String\n");230return JNI_ERR;231}232if (native_debug) {233printf("LSA: Found String\n");234}235236javaLangStringClass = (*env)->NewWeakGlobalRef(env,cls);237if (javaLangStringClass == NULL) {238return JNI_ERR;239}240if (native_debug) {241printf("LSA: Made NewWeakGlobalRef\n");242}243244ticketConstructor = (*env)->GetMethodID(env, ticketClass,245"<init>", "([B)V");246if (ticketConstructor == 0) {247printf("LSA: Couldn't find Ticket constructor\n");248return JNI_ERR;249}250if (native_debug) {251printf("LSA: Found Ticket constructor\n");252}253254principalNameConstructor = (*env)->GetMethodID(env, principalNameClass,255"<init>", "([Ljava/lang/String;Ljava/lang/String;)V");256if (principalNameConstructor == 0) {257printf("LSA: Couldn't find PrincipalName constructor\n");258return JNI_ERR;259}260if (native_debug) {261printf("LSA: Found PrincipalName constructor\n");262}263264encryptionKeyConstructor = (*env)->GetMethodID(env, encryptionKeyClass,265"<init>", "(I[B)V");266if (encryptionKeyConstructor == 0) {267printf("LSA: Couldn't find EncryptionKey constructor\n");268return JNI_ERR;269}270if (native_debug) {271printf("LSA: Found EncryptionKey constructor\n");272}273274ticketFlagsConstructor = (*env)->GetMethodID(env, ticketFlagsClass,275"<init>", "(I[B)V");276if (ticketFlagsConstructor == 0) {277printf("LSA: Couldn't find TicketFlags constructor\n");278return JNI_ERR;279}280if (native_debug) {281printf("LSA: Found TicketFlags constructor\n");282}283284kerberosTimeConstructor = (*env)->GetMethodID(env, kerberosTimeClass,285"<init>", "(Ljava/lang/String;)V");286if (kerberosTimeConstructor == 0) {287printf("LSA: Couldn't find KerberosTime constructor\n");288return JNI_ERR;289}290if (native_debug) {291printf("LSA: Found KerberosTime constructor\n");292}293294if (native_debug) {295printf("LSA: Finished OnLoad processing\n");296}297298return JNI_VERSION_1_2;299}300301/*302* Class: sun_security_jgss_KrbCreds303* Method: JNI_OnUnload304*/305306JNIEXPORT void JNICALL DEF_JNI_OnUnload(307JavaVM *jvm,308void *reserved) {309310JNIEnv *env;311312if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {313return; /* Nothing else we can do */314}315316if (ticketClass != NULL) {317(*env)->DeleteWeakGlobalRef(env,ticketClass);318}319if (principalNameClass != NULL) {320(*env)->DeleteWeakGlobalRef(env,principalNameClass);321}322if (encryptionKeyClass != NULL) {323(*env)->DeleteWeakGlobalRef(env,encryptionKeyClass);324}325if (ticketFlagsClass != NULL) {326(*env)->DeleteWeakGlobalRef(env,ticketFlagsClass);327}328if (kerberosTimeClass != NULL) {329(*env)->DeleteWeakGlobalRef(env,kerberosTimeClass);330}331if (javaLangStringClass != NULL) {332(*env)->DeleteWeakGlobalRef(env,javaLangStringClass);333}334335return;336}337338/*339* Class: sun_security_krb5_Credentials340* Method: acquireDefaultNativeCreds341* Signature: ([I])Lsun/security/krb5/Credentials;342*/343JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds(344JNIEnv *env,345jclass krbcredsClass,346jintArray jetypes) {347348KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;349PKERB_RETRIEVE_TKT_RESPONSE TktCacheResponse = NULL;350PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;351PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;352NTSTATUS Status, SubStatus;353ULONG requestSize = 0;354ULONG responseSize = 0;355ULONG rspSize = 0;356HANDLE LogonHandle = NULL;357ULONG PackageId;358jobject ticket, clientPrincipal, targetPrincipal, encryptionKey;359jobject ticketFlags, startTime, endTime, krbCreds = NULL;360jobject authTime, renewTillTime, hostAddresses = NULL;361KERB_EXTERNAL_TICKET *msticket;362int found = 0;363FILETIME Now, EndTime;364365int i, netypes;366jint *etypes = NULL;367368while (TRUE) {369370if (krbcredsConstructor == 0) {371krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>",372"(Lsun/security/krb5/internal/Ticket;"373"Lsun/security/krb5/PrincipalName;"374"Lsun/security/krb5/PrincipalName;"375"Lsun/security/krb5/PrincipalName;"376"Lsun/security/krb5/PrincipalName;"377"Lsun/security/krb5/EncryptionKey;"378"Lsun/security/krb5/internal/TicketFlags;"379"Lsun/security/krb5/internal/KerberosTime;"380"Lsun/security/krb5/internal/KerberosTime;"381"Lsun/security/krb5/internal/KerberosTime;"382"Lsun/security/krb5/internal/KerberosTime;"383"Lsun/security/krb5/internal/HostAddresses;)V");384if (krbcredsConstructor == 0) {385printf("LSA: Couldn't find sun.security.krb5.Credentials constructor\n");386break;387}388}389390if (native_debug) {391printf("LSA: Found KrbCreds constructor\n");392}393394//395// Get the logon handle and package ID from the396// Kerberos package397//398if (!PackageConnectLookup(&LogonHandle, &PackageId))399break;400401if (native_debug) {402printf("LSA: Got handle to Kerberos package\n");403}404405// Get the MS TGT from cache406CacheRequest.MessageType = KerbRetrieveTicketMessage;407CacheRequest.LogonId.LowPart = 0;408CacheRequest.LogonId.HighPart = 0;409410Status = LsaCallAuthenticationPackage(411LogonHandle,412PackageId,413&CacheRequest,414sizeof(CacheRequest),415&TktCacheResponse,416&rspSize,417&SubStatus418);419420if (native_debug) {421printf("LSA: Response size is %d\n", rspSize);422}423424if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {425if (!LSA_SUCCESS(Status)) {426ShowNTError("LsaCallAuthenticationPackage", Status);427} else {428ShowNTError("Protocol status", SubStatus);429}430break;431}432433// got the native MS TGT434msticket = &(TktCacheResponse->Ticket);435436netypes = (*env)->GetArrayLength(env, jetypes);437etypes = (jint *) (*env)->GetIntArrayElements(env, jetypes, NULL);438439if (etypes == NULL) {440break;441}442443// check TGT validity444if (native_debug) {445printf("LSA: TICKET SessionKey KeyType is %d\n", msticket->SessionKey.KeyType);446}447448if ((msticket->TicketFlags & KERB_TICKET_FLAGS_invalid) == 0) {449GetSystemTimeAsFileTime(&Now);450EndTime.dwLowDateTime = msticket->EndTime.LowPart;451EndTime.dwHighDateTime = msticket->EndTime.HighPart;452if (CompareFileTime(&Now, &EndTime) < 0) {453for (i=0; i<netypes; i++) {454if (etypes[i] == msticket->SessionKey.KeyType) {455found = 1;456if (native_debug) {457printf("LSA: Valid etype found: %d\n", etypes[i]);458}459break;460}461}462}463}464465if (!found) {466if (native_debug) {467printf("LSA: MS TGT in cache is invalid/not supported; request new ticket\n");468}469470// use domain to request Ticket471Status = ConstructTicketRequest(env, msticket->TargetDomainName,472&pTicketRequest, &requestSize);473if (!LSA_SUCCESS(Status)) {474ShowNTError("ConstructTicketRequest status", Status);475break;476}477478pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;479pTicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_DONT_USE_CACHE;480481for (i=0; i<netypes; i++) {482pTicketRequest->EncryptionType = etypes[i];483Status = LsaCallAuthenticationPackage(484LogonHandle,485PackageId,486pTicketRequest,487requestSize,488&pTicketResponse,489&responseSize,490&SubStatus491);492493if (native_debug) {494printf("LSA: Response size is %d for %d\n", responseSize, etypes[i]);495}496497if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {498if (!LSA_SUCCESS(Status)) {499ShowNTError("LsaCallAuthenticationPackage", Status);500} else {501ShowNTError("Protocol status", SubStatus);502}503continue;504}505506// got the native MS Kerberos TGT507msticket = &(pTicketResponse->Ticket);508509if (msticket->SessionKey.KeyType != etypes[i]) {510if (native_debug) {511printf("LSA: Response etype is %d for %d. Retry.\n", msticket->SessionKey.KeyType, etypes[i]);512}513continue;514}515found = 1;516break;517}518}519520if (etypes != NULL) {521(*env)->ReleaseIntArrayElements(env, jetypes, etypes, 0);522}523524/*525526typedef struct _KERB_RETRIEVE_TKT_RESPONSE {527KERB_EXTERNAL_TICKET Ticket;528} KERB_RETRIEVE_TKT_RESPONSE, *PKERB_RETRIEVE_TKT_RESPONSE;529530typedef struct _KERB_EXTERNAL_TICKET {531PKERB_EXTERNAL_NAME ServiceName;532PKERB_EXTERNAL_NAME TargetName;533PKERB_EXTERNAL_NAME ClientName;534UNICODE_STRING DomainName;535UNICODE_STRING TargetDomainName;536UNICODE_STRING AltTargetDomainName;537KERB_CRYPTO_KEY SessionKey;538ULONG TicketFlags;539ULONG Flags;540LARGE_INTEGER KeyExpirationTime;541LARGE_INTEGER StartTime;542LARGE_INTEGER EndTime;543LARGE_INTEGER RenewUntil;544LARGE_INTEGER TimeSkew;545ULONG EncodedTicketSize;546PUCHAR EncodedTicket; <========== Here's the good stuff547} KERB_EXTERNAL_TICKET, *PKERB_EXTERNAL_TICKET;548549typedef struct _KERB_EXTERNAL_NAME {550SHORT NameType;551USHORT NameCount;552UNICODE_STRING Names[ANYSIZE_ARRAY];553} KERB_EXTERNAL_NAME, *PKERB_EXTERNAL_NAME;554555typedef struct _LSA_UNICODE_STRING {556USHORT Length;557USHORT MaximumLength;558PWSTR Buffer;559} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;560561typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;562563typedef struct KERB_CRYPTO_KEY {564LONG KeyType;565ULONG Length;566PUCHAR Value;567} KERB_CRYPTO_KEY, *PKERB_CRYPTO_KEY;568569*/570if (!found) {571break;572}573574// Build a com.sun.security.krb5.Ticket575ticket = BuildTicket(env, msticket->EncodedTicket,576msticket->EncodedTicketSize);577if (ticket == NULL) {578break;579}580// OK, have a Ticket, now need to get the client name581clientPrincipal = BuildPrincipal(env, msticket->ClientName,582msticket->TargetDomainName); // mdu583if (clientPrincipal == NULL) {584break;585}586587// and the "name" of tgt588targetPrincipal = BuildPrincipal(env, msticket->ServiceName,589msticket->DomainName);590if (targetPrincipal == NULL) {591break;592}593594// Get the encryption key595encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey));596if (encryptionKey == NULL) {597break;598}599600// and the ticket flags601ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags));602if (ticketFlags == NULL) {603break;604}605606// Get the start time607startTime = BuildKerberosTime(env, &(msticket->StartTime));608if (startTime == NULL) {609break;610}611612/*613* mdu: No point storing the eky expiration time in the auth614* time field. Set it to be same as startTime. Looks like615* windows does not have post-dated tickets.616*/617authTime = startTime;618619// and the end time620endTime = BuildKerberosTime(env, &(msticket->EndTime));621if (endTime == NULL) {622break;623}624625// Get the renew till time626renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil));627if (renewTillTime == NULL) {628break;629}630631// and now go build a KrbCreds object632krbCreds = (*env)->NewObject(633env,634krbcredsClass,635krbcredsConstructor,636ticket,637clientPrincipal,638NULL,639targetPrincipal,640NULL,641encryptionKey,642ticketFlags,643authTime, // mdu644startTime,645endTime,646renewTillTime, //mdu647hostAddresses);648649break;650} // end of WHILE. This WHILE will never loop.651652// clean up resources653if (TktCacheResponse != NULL) {654LsaFreeReturnBuffer(TktCacheResponse);655}656if (pTicketRequest) {657LocalFree(pTicketRequest);658}659if (pTicketResponse != NULL) {660LsaFreeReturnBuffer(pTicketResponse);661}662663return krbCreds;664}665666static NTSTATUS667ConstructTicketRequest(JNIEnv *env, UNICODE_STRING DomainName,668PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize)669{670NTSTATUS Status;671UNICODE_STRING TargetPrefix;672USHORT TargetSize;673ULONG RequestSize;674ULONG Length;675PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;676677*outRequest = NULL;678*outSize = 0;679680//681// Set up the "krbtgt/" target prefix into a UNICODE_STRING so we682// can easily concatenate it later.683//684685TargetPrefix.Buffer = L"krbtgt/";686Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);687TargetPrefix.Length = (USHORT)Length;688TargetPrefix.MaximumLength = TargetPrefix.Length;689690//691// We will need to concatenate the "krbtgt/" prefix and the692// Logon Session's DnsDomainName into our request's target name.693//694// Therefore, first compute the necessary buffer size for that.695//696// Note that we might theoretically have integer overflow.697//698699TargetSize = TargetPrefix.Length + DomainName.Length;700701//702// The ticket request buffer needs to be a single buffer. That buffer703// needs to include the buffer for the target name.704//705706RequestSize = sizeof (*pTicketRequest) + TargetSize;707708//709// Allocate the request buffer and make sure it's zero-filled.710//711712pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)713LocalAlloc(LMEM_ZEROINIT, RequestSize);714if (!pTicketRequest) {715ThrowOOME(env, "Can't allocate memory for ticket");716return GetLastError();717}718719//720// Concatenate the target prefix with the previous response's721// target domain.722//723724pTicketRequest->TargetName.Length = 0;725pTicketRequest->TargetName.MaximumLength = TargetSize;726pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);727Status = ConcatenateUnicodeStrings(&(pTicketRequest->TargetName),728TargetPrefix,729DomainName);730*outRequest = pTicketRequest;731*outSize = RequestSize;732return Status;733}734735DWORD736ConcatenateUnicodeStrings(737UNICODE_STRING *pTarget,738UNICODE_STRING Source1,739UNICODE_STRING Source2740)741{742//743// The buffers for Source1 and Source2 cannot overlap pTarget's744// buffer. Source1.Length + Source2.Length must be <= 0xFFFF,745// otherwise we overflow...746//747748USHORT TotalSize = Source1.Length + Source2.Length;749PBYTE buffer = (PBYTE) pTarget->Buffer;750751if (TotalSize > pTarget->MaximumLength)752return ERROR_INSUFFICIENT_BUFFER;753754pTarget->Length = TotalSize;755memcpy(buffer, Source1.Buffer, Source1.Length);756memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);757return ERROR_SUCCESS;758}759760BOOL761PackageConnectLookup(762HANDLE *pLogonHandle,763ULONG *pPackageId764)765{766LSA_STRING Name;767NTSTATUS Status;768769Status = LsaConnectUntrusted(770pLogonHandle771);772773if (!LSA_SUCCESS(Status))774{775ShowNTError("LsaConnectUntrusted", Status);776return FALSE;777}778779Name.Buffer = MICROSOFT_KERBEROS_NAME_A;780Name.Length = (USHORT)strlen(Name.Buffer);781Name.MaximumLength = Name.Length + 1;782783Status = LsaLookupAuthenticationPackage(784*pLogonHandle,785&Name,786pPackageId787);788789if (!LSA_SUCCESS(Status))790{791ShowNTError("LsaLookupAuthenticationPackage", Status);792return FALSE;793}794795return TRUE;796797}798799VOID800ShowLastError(801LPSTR szAPI,802DWORD dwError803)804{805#define MAX_MSG_SIZE 256806807static WCHAR szMsgBuf[MAX_MSG_SIZE];808DWORD dwRes;809810if (native_debug) {811printf("LSA: Error calling function %s: %lu\n", szAPI, dwError);812}813814dwRes = FormatMessage (815FORMAT_MESSAGE_FROM_SYSTEM,816NULL,817dwError,8180,819szMsgBuf,820MAX_MSG_SIZE,821NULL);822if (native_debug) {823if (0 == dwRes) {824printf("LSA: FormatMessage failed with %d\n", GetLastError());825// ExitProcess(EXIT_FAILURE);826} else {827printf("LSA: %S",szMsgBuf);828}829}830}831832VOID833ShowNTError(834LPSTR szAPI,835NTSTATUS Status836)837{838//839// Convert the NTSTATUS to Winerror. Then call ShowLastError().840//841ShowLastError(szAPI, LsaNtStatusToWinError(Status));842}843844VOID845InitUnicodeString(846PUNICODE_STRING DestinationString,847PCWSTR SourceString OPTIONAL848)849{850ULONG Length;851852DestinationString->Buffer = (PWSTR)SourceString;853if (SourceString != NULL) {854Length = (ULONG)wcslen( SourceString ) * sizeof( WCHAR );855DestinationString->Length = (USHORT)Length;856DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));857}858else {859DestinationString->MaximumLength = 0;860DestinationString->Length = 0;861}862}863864jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize) {865866// To build a Ticket, we need to make a byte array out of the EncodedTicket.867868jobject ticket;869jbyteArray ary;870871ary = (*env)->NewByteArray(env,encodedTicketSize);872if (ary == NULL) {873return (jobject) NULL;874}875876(*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize,877(jbyte *)encodedTicket);878if ((*env)->ExceptionOccurred(env)) {879(*env)->DeleteLocalRef(env, ary);880return (jobject) NULL;881}882883ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, ary);884if ((*env)->ExceptionOccurred(env)) {885(*env)->DeleteLocalRef(env, ary);886return (jobject) NULL;887}888(*env)->DeleteLocalRef(env, ary);889return ticket;890}891892// mdu893jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,894UNICODE_STRING domainName) {895896/*897* To build the Principal, we need to get the names out of898* this goofy MS structure899*/900jobject principal = NULL;901jobject realmStr = NULL;902jobjectArray stringArray;903jstring tempString;904int nameCount,i;905PUNICODE_STRING scanner;906WCHAR *realm;907ULONG realmLen;908909realm = (WCHAR *) LocalAlloc(LMEM_ZEROINIT,910((domainName.Length)*sizeof(WCHAR) + sizeof(UNICODE_NULL)));911if (realm == NULL) {912ThrowOOME(env, "Can't allocate memory for realm");913return NULL;914}915wcsncpy(realm, domainName.Buffer, domainName.Length/sizeof(WCHAR));916917if (native_debug) {918printf("LSA: Principal domain is %S\n", realm);919printf("LSA: Name type is %x\n", principalName->NameType);920printf("LSA: Name count is %x\n", principalName->NameCount);921}922923nameCount = principalName->NameCount;924stringArray = (*env)->NewObjectArray(env, nameCount,925javaLangStringClass, NULL);926if (stringArray == NULL) {927if (native_debug) {928printf("LSA: Can't allocate String array for Principal\n");929}930goto cleanup;931}932933for (i=0; i<nameCount; i++) {934// get the principal name935scanner = &(principalName->Names[i]);936937// OK, got a Char array, so construct a String938tempString = (*env)->NewString(env, (const jchar*)scanner->Buffer,939scanner->Length/sizeof(WCHAR));940941if (tempString == NULL) {942goto cleanup;943}944945// Set the String into the StringArray946(*env)->SetObjectArrayElement(env, stringArray, i, tempString);947948if ((*env)->ExceptionCheck(env)) {949goto cleanup;950}951952// Do I have to worry about storage reclamation here?953}954// now set the realm in the principal955realmLen = (ULONG)wcslen((PWCHAR)realm);956realmStr = (*env)->NewString(env, (PWCHAR)realm, (USHORT)realmLen);957958if (realmStr == NULL) {959goto cleanup;960}961962principal = (*env)->NewObject(env, principalNameClass,963principalNameConstructor, stringArray, realmStr);964965cleanup:966// free local resources967LocalFree(realm);968969return principal;970}971972jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) {973// First, need to build a byte array974jbyteArray ary;975jobject encryptionKey = NULL;976unsigned int i;977978for (i=0; i<cryptoKey->Length; i++) {979if (cryptoKey->Value[i]) break;980}981if (i == cryptoKey->Length) {982if (native_debug) {983printf("LSA: Session key all zero. Stop.\n");984}985return NULL;986}987988ary = (*env)->NewByteArray(env,cryptoKey->Length);989if (ary == NULL) {990return (jobject) NULL;991}992(*env)->SetByteArrayRegion(env, ary, (jsize) 0, cryptoKey->Length,993(jbyte *)cryptoKey->Value);994if ((*env)->ExceptionOccurred(env)) {995(*env)->DeleteLocalRef(env, ary);996} else {997encryptionKey = (*env)->NewObject(env, encryptionKeyClass,998encryptionKeyConstructor, cryptoKey->KeyType, ary);999}10001001return encryptionKey;1002}10031004jobject BuildTicketFlags(JNIEnv *env, PULONG flags) {1005jobject ticketFlags = NULL;1006jbyteArray ary;1007/*1008* mdu: Convert the bytes to nework byte order before copying1009* them to a Java byte array.1010*/1011ULONG nlflags = htonl(*flags);10121013ary = (*env)->NewByteArray(env, sizeof(*flags));1014if (ary == NULL) {1015return (jobject) NULL;1016}1017(*env)->SetByteArrayRegion(env, ary, (jsize) 0, sizeof(*flags),1018(jbyte *)&nlflags);1019if ((*env)->ExceptionOccurred(env)) {1020(*env)->DeleteLocalRef(env, ary);1021} else {1022ticketFlags = (*env)->NewObject(env, ticketFlagsClass,1023ticketFlagsConstructor, sizeof(*flags)*8, ary);1024}10251026return ticketFlags;1027}10281029jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) {1030jobject kerberosTime = NULL;1031jstring stringTime = NULL;1032SYSTEMTIME systemTime;1033WCHAR timeString[16];1034WCHAR month[3];1035WCHAR day[3];1036WCHAR hour[3];1037WCHAR minute[3];1038WCHAR second[3];10391040if (FileTimeToSystemTime((FILETIME *)kerbtime, &systemTime)) {1041// XXX Cannot use %02.2ld, because the leading 0 is ignored for integers.1042// So, print them to strings, and then print them to the master string with a1043// format pattern that makes it two digits and prefix with a 0 if necessary.1044swprintf( (wchar_t *)month, 3, L"%2.2d", systemTime.wMonth);1045swprintf( (wchar_t *)day, 3, L"%2.2d", systemTime.wDay);1046swprintf( (wchar_t *)hour, 3, L"%2.2d", systemTime.wHour);1047swprintf( (wchar_t *)minute, 3, L"%2.2d", systemTime.wMinute);1048swprintf( (wchar_t *)second, 3, L"%2.2d", systemTime.wSecond);1049swprintf( (wchar_t *)timeString, 16,1050L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",1051systemTime.wYear,1052month,1053day,1054hour,1055minute,1056second );1057if (native_debug) {1058printf("LSA: %S\n", (wchar_t *)timeString);1059}1060stringTime = (*env)->NewString(env, timeString,1061(sizeof(timeString)/sizeof(WCHAR))-1);1062if (stringTime != NULL) { // everything's OK so far1063kerberosTime = (*env)->NewObject(env, kerberosTimeClass,1064kerberosTimeConstructor, stringTime);1065}1066}1067return kerberosTime;1068}10691070void ThrowOOME(JNIEnv *env, const char *szMessage) {1071jclass exceptionClazz = (*env)->FindClass(env, "java/lang/OutOfMemoryError");1072if (exceptionClazz != NULL) {1073(*env)->ThrowNew(env, exceptionClazz, szMessage);1074}1075}107610771078