src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c
changeset 47216 71c04702a3d5
parent 33653 c1ee09fe3274
child 50471 f0aeede1b855
child 56466 4de0b680c1cd
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     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 }