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