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