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