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