jdk
1077 строк · 32.2 Кб
1/*
2* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*
5* This code is free software; you can redistribute it and/or modify it
6* under the terms of the GNU General Public License version 2 only, as
7* published by the Free Software Foundation. Oracle designates this
8* particular file as subject to the "Classpath" exception as provided
9* by Oracle in the LICENSE file that accompanied this code.
10*
11* This code is distributed in the hope that it will be useful, but WITHOUT
12* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14* version 2 for more details (a copy is included in the LICENSE file that
15* accompanied this code).
16*
17* You should have received a copy of the GNU General Public License version
18* 2 along with this work; if not, write to the Free Software Foundation,
19* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20*
21* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22* or visit www.oracle.com if you need additional information or have any
23* questions.
24*/
25
26/*
27* ===========================================================================
28* (C) Copyright IBM Corp. 2000 All Rights Reserved.
29* ===========================================================================
30*/
31
32#define UNICODE33#define _UNICODE34
35#include <windows.h>36#include <stdio.h>37#include <string.h>38#define SECURITY_WIN3239#include <security.h>40#include <ntsecapi.h>41#include <dsgetdc.h>42#include <lmcons.h>43#include <lmapibuf.h>44#include <jni.h>45#include "jni_util.h"46#include <winsock.h>47#include "sun_security_krb5_Credentials.h"48
49#undef LSA_SUCCESS50#define LSA_SUCCESS(Status) ((Status) >= 0)51
52/*
53* Library-wide static references
54*/
55
56jclass ticketClass = NULL;57jclass principalNameClass = NULL;58jclass encryptionKeyClass = NULL;59jclass ticketFlagsClass = NULL;60jclass kerberosTimeClass = NULL;61jclass javaLangStringClass = NULL;62
63jmethodID ticketConstructor = 0;64jmethodID principalNameConstructor = 0;65jmethodID encryptionKeyConstructor = 0;66jmethodID ticketFlagsConstructor = 0;67jmethodID kerberosTimeConstructor = 0;68jmethodID krbcredsConstructor = 0;69
70/*
71* Function prototypes for internal routines
72*
73*/
74BOOL native_debug = 0;75
76BOOL PackageConnectLookup(PHANDLE,PULONG);77
78static
79NTSTATUS ConstructTicketRequest(JNIEnv *env,80UNICODE_STRING DomainName,81PKERB_RETRIEVE_TKT_REQUEST *outRequest,82ULONG *outSize);83
84DWORD ConcatenateUnicodeStrings(UNICODE_STRING *pTarget,85UNICODE_STRING Source1,86UNICODE_STRING Source2);87
88VOID ShowNTError(LPSTR,NTSTATUS);89
90VOID
91InitUnicodeString(92PUNICODE_STRING DestinationString,93PCWSTR SourceString OPTIONAL
94);95
96jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize);97
98//mdu
99jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,100UNICODE_STRING domainName);101
102jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey);103jobject BuildTicketFlags(JNIEnv *env, PULONG flags);104jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime);105
106void ThrowOOME(JNIEnv *env, const char *szMessage);107
108/*
109* Class: sun_security_krb5_KrbCreds
110* Method: JNI_OnLoad
111*/
112
113JNIEXPORT jint JNICALL DEF_JNI_OnLoad(114JavaVM *jvm,115void *reserved) {116
117jclass cls;118JNIEnv *env;119jfieldID fldDEBUG;120
121if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {122return JNI_EVERSION; /* JNI version not supported */123}124
125cls = (*env)->FindClass(env,"sun/security/krb5/internal/Krb5");126if (cls == NULL) {127fprintf(stderr, "LSA: Couldn't find Krb5\n");128return JNI_ERR;129}130fldDEBUG = (*env)->GetStaticFieldID(env, cls, "DEBUG", "Lsun/security/util/Debug;");131if (fldDEBUG == NULL) {132fprintf(stderr, "LSA: Krb5 has no DEBUG field\n");133return JNI_ERR;134}135native_debug = (*env)->GetStaticObjectField(env, cls, fldDEBUG) != NULL;136
137cls = (*env)->FindClass(env,"sun/security/krb5/internal/Ticket");138
139if (cls == NULL) {140fprintf(stderr, "LSA: Couldn't find Ticket\n");141return JNI_ERR;142}143if (native_debug) {144fprintf(stderr, "LSA: Found Ticket\n");145}146
147ticketClass = (*env)->NewWeakGlobalRef(env,cls);148if (ticketClass == NULL) {149return JNI_ERR;150}151if (native_debug) {152fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");153}154
155cls = (*env)->FindClass(env, "sun/security/krb5/PrincipalName");156
157if (cls == NULL) {158fprintf(stderr, "LSA: Couldn't find PrincipalName\n");159return JNI_ERR;160}161if (native_debug) {162fprintf(stderr, "LSA: Found PrincipalName\n");163}164
165principalNameClass = (*env)->NewWeakGlobalRef(env,cls);166if (principalNameClass == NULL) {167return JNI_ERR;168}169if (native_debug) {170fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");171}172
173cls = (*env)->FindClass(env,"sun/security/krb5/EncryptionKey");174
175if (cls == NULL) {176fprintf(stderr, "LSA: Couldn't find EncryptionKey\n");177return JNI_ERR;178}179if (native_debug) {180fprintf(stderr, "LSA: Found EncryptionKey\n");181}182
183encryptionKeyClass = (*env)->NewWeakGlobalRef(env,cls);184if (encryptionKeyClass == NULL) {185return JNI_ERR;186}187if (native_debug) {188fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");189}190
191cls = (*env)->FindClass(env,"sun/security/krb5/internal/TicketFlags");192
193if (cls == NULL) {194fprintf(stderr, "LSA: Couldn't find TicketFlags\n");195return JNI_ERR;196}197if (native_debug) {198fprintf(stderr, "LSA: Found TicketFlags\n");199}200
201ticketFlagsClass = (*env)->NewWeakGlobalRef(env,cls);202if (ticketFlagsClass == NULL) {203return JNI_ERR;204}205if (native_debug) {206fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");207}208
209cls = (*env)->FindClass(env,"sun/security/krb5/internal/KerberosTime");210
211if (cls == NULL) {212fprintf(stderr, "LSA: Couldn't find KerberosTime\n");213return JNI_ERR;214}215if (native_debug) {216fprintf(stderr, "LSA: Found KerberosTime\n");217}218
219kerberosTimeClass = (*env)->NewWeakGlobalRef(env,cls);220if (kerberosTimeClass == NULL) {221return JNI_ERR;222}223if (native_debug) {224fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");225}226
227cls = (*env)->FindClass(env,"java/lang/String");228
229if (cls == NULL) {230fprintf(stderr, "LSA: Couldn't find String\n");231return JNI_ERR;232}233if (native_debug) {234fprintf(stderr, "LSA: Found String\n");235}236
237javaLangStringClass = (*env)->NewWeakGlobalRef(env,cls);238if (javaLangStringClass == NULL) {239return JNI_ERR;240}241if (native_debug) {242fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");243}244
245ticketConstructor = (*env)->GetMethodID(env, ticketClass,246"<init>", "([B)V");247if (ticketConstructor == 0) {248fprintf(stderr, "LSA: Couldn't find Ticket constructor\n");249return JNI_ERR;250}251if (native_debug) {252fprintf(stderr, "LSA: Found Ticket constructor\n");253}254
255principalNameConstructor = (*env)->GetMethodID(env, principalNameClass,256"<init>", "([Ljava/lang/String;Ljava/lang/String;)V");257if (principalNameConstructor == 0) {258fprintf(stderr, "LSA: Couldn't find PrincipalName constructor\n");259return JNI_ERR;260}261if (native_debug) {262fprintf(stderr, "LSA: Found PrincipalName constructor\n");263}264
265encryptionKeyConstructor = (*env)->GetMethodID(env, encryptionKeyClass,266"<init>", "(I[B)V");267if (encryptionKeyConstructor == 0) {268fprintf(stderr, "LSA: Couldn't find EncryptionKey constructor\n");269return JNI_ERR;270}271if (native_debug) {272fprintf(stderr, "LSA: Found EncryptionKey constructor\n");273}274
275ticketFlagsConstructor = (*env)->GetMethodID(env, ticketFlagsClass,276"<init>", "(I[B)V");277if (ticketFlagsConstructor == 0) {278fprintf(stderr, "LSA: Couldn't find TicketFlags constructor\n");279return JNI_ERR;280}281if (native_debug) {282fprintf(stderr, "LSA: Found TicketFlags constructor\n");283}284
285kerberosTimeConstructor = (*env)->GetMethodID(env, kerberosTimeClass,286"<init>", "(Ljava/lang/String;)V");287if (kerberosTimeConstructor == 0) {288fprintf(stderr, "LSA: Couldn't find KerberosTime constructor\n");289return JNI_ERR;290}291if (native_debug) {292fprintf(stderr, "LSA: Found KerberosTime constructor\n");293}294
295if (native_debug) {296fprintf(stderr, "LSA: Finished OnLoad processing\n");297}298
299return JNI_VERSION_1_2;300}
301
302/*
303* Class: sun_security_jgss_KrbCreds
304* Method: JNI_OnUnload
305*/
306
307JNIEXPORT void JNICALL DEF_JNI_OnUnload(308JavaVM *jvm,309void *reserved) {310
311JNIEnv *env;312
313if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {314return; /* Nothing else we can do */315}316
317if (ticketClass != NULL) {318(*env)->DeleteWeakGlobalRef(env,ticketClass);319}320if (principalNameClass != NULL) {321(*env)->DeleteWeakGlobalRef(env,principalNameClass);322}323if (encryptionKeyClass != NULL) {324(*env)->DeleteWeakGlobalRef(env,encryptionKeyClass);325}326if (ticketFlagsClass != NULL) {327(*env)->DeleteWeakGlobalRef(env,ticketFlagsClass);328}329if (kerberosTimeClass != NULL) {330(*env)->DeleteWeakGlobalRef(env,kerberosTimeClass);331}332if (javaLangStringClass != NULL) {333(*env)->DeleteWeakGlobalRef(env,javaLangStringClass);334}335
336return;337}
338
339/*
340* Class: sun_security_krb5_Credentials
341* Method: acquireDefaultNativeCreds
342* Signature: ([I])Lsun/security/krb5/Credentials;
343*/
344JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds(345JNIEnv *env,346jclass krbcredsClass,347jintArray jetypes) {348
349KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;350PKERB_RETRIEVE_TKT_RESPONSE TktCacheResponse = NULL;351PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;352PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;353NTSTATUS Status, SubStatus;354ULONG requestSize = 0;355ULONG responseSize = 0;356ULONG rspSize = 0;357HANDLE LogonHandle = NULL;358ULONG PackageId;359jobject ticket, clientPrincipal, targetPrincipal, encryptionKey;360jobject ticketFlags, startTime, endTime, krbCreds = NULL;361jobject authTime, renewTillTime, hostAddresses = NULL;362KERB_EXTERNAL_TICKET *msticket;363int found = 0;364FILETIME Now, EndTime;365
366int i, netypes;367jint *etypes = NULL;368
369while (TRUE) {370
371if (krbcredsConstructor == 0) {372krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>",373"(Lsun/security/krb5/internal/Ticket;"374"Lsun/security/krb5/PrincipalName;"375"Lsun/security/krb5/PrincipalName;"376"Lsun/security/krb5/PrincipalName;"377"Lsun/security/krb5/PrincipalName;"378"Lsun/security/krb5/EncryptionKey;"379"Lsun/security/krb5/internal/TicketFlags;"380"Lsun/security/krb5/internal/KerberosTime;"381"Lsun/security/krb5/internal/KerberosTime;"382"Lsun/security/krb5/internal/KerberosTime;"383"Lsun/security/krb5/internal/KerberosTime;"384"Lsun/security/krb5/internal/HostAddresses;)V");385if (krbcredsConstructor == 0) {386fprintf(stderr, "LSA: Couldn't find sun.security.krb5.Credentials constructor\n");387break;388}389}390
391if (native_debug) {392fprintf(stderr, "LSA: Found KrbCreds constructor\n");393}394
395//396// Get the logon handle and package ID from the397// Kerberos package398//399if (!PackageConnectLookup(&LogonHandle, &PackageId))400break;401
402if (native_debug) {403fprintf(stderr, "LSA: Got handle to Kerberos package\n");404}405
406// Get the MS TGT from cache407CacheRequest.MessageType = KerbRetrieveTicketMessage;408CacheRequest.LogonId.LowPart = 0;409CacheRequest.LogonId.HighPart = 0;410
411Status = LsaCallAuthenticationPackage(412LogonHandle,413PackageId,414&CacheRequest,415sizeof(CacheRequest),416&TktCacheResponse,417&rspSize,418&SubStatus419);420
421if (native_debug) {422fprintf(stderr, "LSA: Response size is %d\n", rspSize);423}424
425if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {426if (!LSA_SUCCESS(Status)) {427ShowNTError("LsaCallAuthenticationPackage", Status);428} else {429ShowNTError("Protocol status", SubStatus);430}431break;432}433
434// got the native MS TGT435msticket = &(TktCacheResponse->Ticket);436
437netypes = (*env)->GetArrayLength(env, jetypes);438etypes = (jint *) (*env)->GetIntArrayElements(env, jetypes, NULL);439
440if (etypes == NULL) {441break;442}443
444// check TGT validity445if (native_debug) {446fprintf(stderr, "LSA: TICKET SessionKey KeyType is %d\n", msticket->SessionKey.KeyType);447}448
449if ((msticket->TicketFlags & KERB_TICKET_FLAGS_invalid) == 0) {450GetSystemTimeAsFileTime(&Now);451EndTime.dwLowDateTime = msticket->EndTime.LowPart;452EndTime.dwHighDateTime = msticket->EndTime.HighPart;453if (CompareFileTime(&Now, &EndTime) < 0) {454for (i=0; i<netypes; i++) {455if (etypes[i] == msticket->SessionKey.KeyType) {456found = 1;457if (native_debug) {458fprintf(stderr, "LSA: Valid etype found: %d\n", etypes[i]);459}460break;461}462}463}464}465
466if (!found) {467if (native_debug) {468fprintf(stderr, "LSA: MS TGT in cache is invalid/not supported; request new ticket\n");469}470
471// use domain to request Ticket472Status = ConstructTicketRequest(env, msticket->TargetDomainName,473&pTicketRequest, &requestSize);474if (!LSA_SUCCESS(Status)) {475ShowNTError("ConstructTicketRequest status", Status);476break;477}478
479pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;480pTicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_DONT_USE_CACHE;481
482for (i=0; i<netypes; i++) {483pTicketRequest->EncryptionType = etypes[i];484Status = LsaCallAuthenticationPackage(485LogonHandle,486PackageId,487pTicketRequest,488requestSize,489&pTicketResponse,490&responseSize,491&SubStatus492);493
494if (native_debug) {495fprintf(stderr, "LSA: Response size is %d for %d\n", responseSize, etypes[i]);496}497
498if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {499if (!LSA_SUCCESS(Status)) {500ShowNTError("LsaCallAuthenticationPackage", Status);501} else {502ShowNTError("Protocol status", SubStatus);503}504continue;505}506
507// got the native MS Kerberos TGT508msticket = &(pTicketResponse->Ticket);509
510if (msticket->SessionKey.KeyType != etypes[i]) {511if (native_debug) {512fprintf(stderr, "LSA: Response etype is %d for %d. Retry.\n", msticket->SessionKey.KeyType, etypes[i]);513}514continue;515}516found = 1;517break;518}519}520
521if (etypes != NULL) {522(*env)->ReleaseIntArrayElements(env, jetypes, etypes, 0);523}524
525/*526
527typedef struct _KERB_RETRIEVE_TKT_RESPONSE {
528KERB_EXTERNAL_TICKET Ticket;
529} KERB_RETRIEVE_TKT_RESPONSE, *PKERB_RETRIEVE_TKT_RESPONSE;
530
531typedef struct _KERB_EXTERNAL_TICKET {
532PKERB_EXTERNAL_NAME ServiceName;
533PKERB_EXTERNAL_NAME TargetName;
534PKERB_EXTERNAL_NAME ClientName;
535UNICODE_STRING DomainName;
536UNICODE_STRING TargetDomainName;
537UNICODE_STRING AltTargetDomainName;
538KERB_CRYPTO_KEY SessionKey;
539ULONG TicketFlags;
540ULONG Flags;
541LARGE_INTEGER KeyExpirationTime;
542LARGE_INTEGER StartTime;
543LARGE_INTEGER EndTime;
544LARGE_INTEGER RenewUntil;
545LARGE_INTEGER TimeSkew;
546ULONG EncodedTicketSize;
547PUCHAR EncodedTicket; <========== Here's the good stuff
548} KERB_EXTERNAL_TICKET, *PKERB_EXTERNAL_TICKET;
549
550typedef struct _KERB_EXTERNAL_NAME {
551SHORT NameType;
552USHORT NameCount;
553UNICODE_STRING Names[ANYSIZE_ARRAY];
554} KERB_EXTERNAL_NAME, *PKERB_EXTERNAL_NAME;
555
556typedef struct _LSA_UNICODE_STRING {
557USHORT Length;
558USHORT MaximumLength;
559PWSTR Buffer;
560} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;
561
562typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;
563
564typedef struct KERB_CRYPTO_KEY {
565LONG KeyType;
566ULONG Length;
567PUCHAR Value;
568} KERB_CRYPTO_KEY, *PKERB_CRYPTO_KEY;
569
570*/
571if (!found) {572break;573}574
575// Build a com.sun.security.krb5.Ticket576ticket = BuildTicket(env, msticket->EncodedTicket,577msticket->EncodedTicketSize);578if (ticket == NULL) {579break;580}581// OK, have a Ticket, now need to get the client name582clientPrincipal = BuildPrincipal(env, msticket->ClientName,583msticket->TargetDomainName); // mdu584if (clientPrincipal == NULL) {585break;586}587
588// and the "name" of tgt589targetPrincipal = BuildPrincipal(env, msticket->ServiceName,590msticket->DomainName);591if (targetPrincipal == NULL) {592break;593}594
595// Get the encryption key596encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey));597if (encryptionKey == NULL) {598break;599}600
601// and the ticket flags602ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags));603if (ticketFlags == NULL) {604break;605}606
607// Get the start time608startTime = BuildKerberosTime(env, &(msticket->StartTime));609if (startTime == NULL) {610break;611}612
613/*614* mdu: No point storing the eky expiration time in the auth
615* time field. Set it to be same as startTime. Looks like
616* windows does not have post-dated tickets.
617*/
618authTime = startTime;619
620// and the end time621endTime = BuildKerberosTime(env, &(msticket->EndTime));622if (endTime == NULL) {623break;624}625
626// Get the renew till time627renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil));628if (renewTillTime == NULL) {629break;630}631
632// and now go build a KrbCreds object633krbCreds = (*env)->NewObject(634env,635krbcredsClass,636krbcredsConstructor,637ticket,638clientPrincipal,639NULL,640targetPrincipal,641NULL,642encryptionKey,643ticketFlags,644authTime, // mdu645startTime,646endTime,647renewTillTime, //mdu648hostAddresses);649
650break;651} // end of WHILE. This WHILE will never loop.652
653// clean up resources654if (TktCacheResponse != NULL) {655LsaFreeReturnBuffer(TktCacheResponse);656}657if (pTicketRequest) {658LocalFree(pTicketRequest);659}660if (pTicketResponse != NULL) {661LsaFreeReturnBuffer(pTicketResponse);662}663
664return krbCreds;665}
666
667static NTSTATUS668ConstructTicketRequest(JNIEnv *env, UNICODE_STRING DomainName,669PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize)670{
671NTSTATUS Status;672UNICODE_STRING TargetPrefix;673USHORT TargetSize;674ULONG RequestSize;675ULONG Length;676PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;677
678*outRequest = NULL;679*outSize = 0;680
681//682// Set up the "krbtgt/" target prefix into a UNICODE_STRING so we683// can easily concatenate it later.684//685
686TargetPrefix.Buffer = L"krbtgt/";687Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);688TargetPrefix.Length = (USHORT)Length;689TargetPrefix.MaximumLength = TargetPrefix.Length;690
691//692// We will need to concatenate the "krbtgt/" prefix and the693// Logon Session's DnsDomainName into our request's target name.694//695// Therefore, first compute the necessary buffer size for that.696//697// Note that we might theoretically have integer overflow.698//699
700TargetSize = TargetPrefix.Length + DomainName.Length;701
702//703// The ticket request buffer needs to be a single buffer. That buffer704// needs to include the buffer for the target name.705//706
707RequestSize = sizeof (*pTicketRequest) + TargetSize;708
709//710// Allocate the request buffer and make sure it's zero-filled.711//712
713pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)714LocalAlloc(LMEM_ZEROINIT, RequestSize);715if (!pTicketRequest) {716ThrowOOME(env, "Can't allocate memory for ticket");717return GetLastError();718}719
720//721// Concatenate the target prefix with the previous response's722// target domain.723//724
725pTicketRequest->TargetName.Length = 0;726pTicketRequest->TargetName.MaximumLength = TargetSize;727pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);728Status = ConcatenateUnicodeStrings(&(pTicketRequest->TargetName),729TargetPrefix,730DomainName);731*outRequest = pTicketRequest;732*outSize = RequestSize;733return Status;734}
735
736DWORD
737ConcatenateUnicodeStrings(738UNICODE_STRING *pTarget,739UNICODE_STRING Source1,740UNICODE_STRING Source2
741)742{
743//744// The buffers for Source1 and Source2 cannot overlap pTarget's745// buffer. Source1.Length + Source2.Length must be <= 0xFFFF,746// otherwise we overflow...747//748
749USHORT TotalSize = Source1.Length + Source2.Length;750PBYTE buffer = (PBYTE) pTarget->Buffer;751
752if (TotalSize > pTarget->MaximumLength)753return ERROR_INSUFFICIENT_BUFFER;754
755pTarget->Length = TotalSize;756memcpy(buffer, Source1.Buffer, Source1.Length);757memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);758return ERROR_SUCCESS;759}
760
761BOOL
762PackageConnectLookup(763HANDLE *pLogonHandle,764ULONG *pPackageId765)766{
767LSA_STRING Name;768NTSTATUS Status;769
770Status = LsaConnectUntrusted(771pLogonHandle
772);773
774if (!LSA_SUCCESS(Status))775{776ShowNTError("LsaConnectUntrusted", Status);777return FALSE;778}779
780Name.Buffer = MICROSOFT_KERBEROS_NAME_A;781Name.Length = (USHORT)strlen(Name.Buffer);782Name.MaximumLength = Name.Length + 1;783
784Status = LsaLookupAuthenticationPackage(785*pLogonHandle,786&Name,787pPackageId
788);789
790if (!LSA_SUCCESS(Status))791{792ShowNTError("LsaLookupAuthenticationPackage", Status);793return FALSE;794}795
796return TRUE;797
798}
799
800VOID
801ShowLastError(802LPSTR szAPI,803DWORD dwError
804)805{
806#define MAX_MSG_SIZE 256807
808static WCHAR szMsgBuf[MAX_MSG_SIZE];809DWORD dwRes;810
811if (native_debug) {812fprintf(stderr, "LSA: Error calling function %s: %lu\n", szAPI, dwError);813}814
815dwRes = FormatMessage (816FORMAT_MESSAGE_FROM_SYSTEM,817NULL,818dwError,8190,820szMsgBuf,821MAX_MSG_SIZE,822NULL);823if (native_debug) {824if (0 == dwRes) {825fprintf(stderr, "LSA: FormatMessage failed with %d\n", GetLastError());826// #define EXIT_FAILURE -1 // mdu827// ExitProcess(EXIT_FAILURE);828} else {829fprintf(stderr, "LSA: %S",szMsgBuf);830}831}832}
833
834VOID
835ShowNTError(836LPSTR szAPI,837NTSTATUS Status
838)839{
840//841// Convert the NTSTATUS to Winerror. Then call ShowLastError().842//843ShowLastError(szAPI, LsaNtStatusToWinError(Status));844}
845
846VOID
847InitUnicodeString(848PUNICODE_STRING DestinationString,849PCWSTR SourceString OPTIONAL
850)851{
852ULONG Length;853
854DestinationString->Buffer = (PWSTR)SourceString;855if (SourceString != NULL) {856Length = (ULONG)wcslen( SourceString ) * sizeof( WCHAR );857DestinationString->Length = (USHORT)Length;858DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));859}860else {861DestinationString->MaximumLength = 0;862DestinationString->Length = 0;863}864}
865
866jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize) {867
868// To build a Ticket, we need to make a byte array out of the EncodedTicket.869
870jobject ticket;871jbyteArray ary;872
873ary = (*env)->NewByteArray(env,encodedTicketSize);874if (ary == NULL) {875return (jobject) NULL;876}877
878(*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize,879(jbyte *)encodedTicket);880if ((*env)->ExceptionOccurred(env)) {881(*env)->DeleteLocalRef(env, ary);882return (jobject) NULL;883}884
885ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, ary);886if ((*env)->ExceptionOccurred(env)) {887(*env)->DeleteLocalRef(env, ary);888return (jobject) NULL;889}890(*env)->DeleteLocalRef(env, ary);891return ticket;892}
893
894// mdu
895jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,896UNICODE_STRING domainName) {897
898/*899* To build the Principal, we need to get the names out of
900* this goofy MS structure
901*/
902jobject principal = NULL;903jobject realmStr = NULL;904jobjectArray stringArray;905jstring tempString;906int nameCount,i;907PUNICODE_STRING scanner;908WCHAR *realm;909ULONG realmLen;910
911realm = (WCHAR *) LocalAlloc(LMEM_ZEROINIT,912((domainName.Length)*sizeof(WCHAR) + sizeof(UNICODE_NULL)));913if (realm == NULL) {914ThrowOOME(env, "Can't allocate memory for realm");915return NULL;916}917wcsncpy(realm, domainName.Buffer, domainName.Length/sizeof(WCHAR));918
919if (native_debug) {920fprintf(stderr, "LSA: Principal domain is %S\n", realm);921fprintf(stderr, "LSA: Name type is %x\n", principalName->NameType);922fprintf(stderr, "LSA: Name count is %x\n", principalName->NameCount);923}924
925nameCount = principalName->NameCount;926stringArray = (*env)->NewObjectArray(env, nameCount,927javaLangStringClass, NULL);928if (stringArray == NULL) {929if (native_debug) {930fprintf(stderr, "LSA: Can't allocate String array for Principal\n");931}932goto cleanup;933}934
935for (i=0; i<nameCount; i++) {936// get the principal name937scanner = &(principalName->Names[i]);938
939// OK, got a Char array, so construct a String940tempString = (*env)->NewString(env, (const jchar*)scanner->Buffer,941scanner->Length/sizeof(WCHAR));942
943if (tempString == NULL) {944goto cleanup;945}946
947// Set the String into the StringArray948(*env)->SetObjectArrayElement(env, stringArray, i, tempString);949
950if ((*env)->ExceptionCheck(env)) {951goto cleanup;952}953
954// Do I have to worry about storage reclamation here?955}956// now set the realm in the principal957realmLen = (ULONG)wcslen((PWCHAR)realm);958realmStr = (*env)->NewString(env, (PWCHAR)realm, (USHORT)realmLen);959
960if (realmStr == NULL) {961goto cleanup;962}963
964principal = (*env)->NewObject(env, principalNameClass,965principalNameConstructor, stringArray, realmStr);966
967cleanup:968// free local resources969LocalFree(realm);970
971return principal;972}
973
974jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) {975// First, need to build a byte array976jbyteArray ary;977jobject encryptionKey = NULL;978unsigned int i;979
980for (i=0; i<cryptoKey->Length; i++) {981if (cryptoKey->Value[i]) break;982}983if (i == cryptoKey->Length) {984if (native_debug) {985fprintf(stderr, "LSA: Session key all zero. Stop.\n");986}987return NULL;988}989
990ary = (*env)->NewByteArray(env,cryptoKey->Length);991if (ary == NULL) {992return (jobject) NULL;993}994(*env)->SetByteArrayRegion(env, ary, (jsize) 0, cryptoKey->Length,995(jbyte *)cryptoKey->Value);996if ((*env)->ExceptionOccurred(env)) {997(*env)->DeleteLocalRef(env, ary);998} else {999encryptionKey = (*env)->NewObject(env, encryptionKeyClass,1000encryptionKeyConstructor, cryptoKey->KeyType, ary);1001}1002
1003return encryptionKey;1004}
1005
1006jobject BuildTicketFlags(JNIEnv *env, PULONG flags) {1007jobject ticketFlags = NULL;1008jbyteArray ary;1009/*1010* mdu: Convert the bytes to network byte order before copying
1011* them to a Java byte array.
1012*/
1013ULONG nlflags = htonl(*flags);1014
1015ary = (*env)->NewByteArray(env, sizeof(*flags));1016if (ary == NULL) {1017return (jobject) NULL;1018}1019(*env)->SetByteArrayRegion(env, ary, (jsize) 0, sizeof(*flags),1020(jbyte *)&nlflags);1021if ((*env)->ExceptionOccurred(env)) {1022(*env)->DeleteLocalRef(env, ary);1023} else {1024ticketFlags = (*env)->NewObject(env, ticketFlagsClass,1025ticketFlagsConstructor, sizeof(*flags)*8, ary);1026}1027
1028return ticketFlags;1029}
1030
1031jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) {1032jobject kerberosTime = NULL;1033jstring stringTime = NULL;1034SYSTEMTIME systemTime;1035WCHAR timeString[16];1036WCHAR month[3];1037WCHAR day[3];1038WCHAR hour[3];1039WCHAR minute[3];1040WCHAR second[3];1041
1042if (FileTimeToSystemTime((FILETIME *)kerbtime, &systemTime)) {1043// XXX Cannot use %02.2ld, because the leading 0 is ignored for integers.1044// So, print them to strings, and then print them to the master string with a1045// format pattern that makes it two digits and prefix with a 0 if necessary.1046swprintf( (wchar_t *)month, 3, L"%2.2d", systemTime.wMonth);1047swprintf( (wchar_t *)day, 3, L"%2.2d", systemTime.wDay);1048swprintf( (wchar_t *)hour, 3, L"%2.2d", systemTime.wHour);1049swprintf( (wchar_t *)minute, 3, L"%2.2d", systemTime.wMinute);1050swprintf( (wchar_t *)second, 3, L"%2.2d", systemTime.wSecond);1051swprintf( (wchar_t *)timeString, 16,1052L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",1053systemTime.wYear,1054month,1055day,1056hour,1057minute,1058second );1059if (native_debug) {1060fprintf(stderr, "LSA: %S\n", (wchar_t *)timeString);1061}1062stringTime = (*env)->NewString(env, timeString,1063(sizeof(timeString)/sizeof(WCHAR))-1);1064if (stringTime != NULL) { // everything's OK so far1065kerberosTime = (*env)->NewObject(env, kerberosTimeClass,1066kerberosTimeConstructor, stringTime);1067}1068}1069return kerberosTime;1070}
1071
1072void ThrowOOME(JNIEnv *env, const char *szMessage) {1073jclass exceptionClazz = (*env)->FindClass(env, "java/lang/OutOfMemoryError");1074if (exceptionClazz != NULL) {1075(*env)->ThrowNew(env, exceptionClazz, szMessage);1076}1077}
1078