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