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