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, LocalEndTime; 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 FileTimeToLocalFileTime(&EndTime, &LocalEndTime); 480 if (CompareFileTime(&Now, &LocalEndTime) < 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 }