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