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