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 }