NativeCreds.c 30.4 KB
Newer Older
D
duke 已提交
1
/*
X
xdono 已提交
2
 * Portions Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
D
duke 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

/*
 * ===========================================================================
 * (C) Copyright IBM Corp. 2000 All Rights Reserved.
 * ===========================================================================
 */

#define UNICODE
#define _UNICODE

#include <windows.h>
#include <stdio.h>
#include <string.h>
#define SECURITY_WIN32
#include <security.h>
#include <ntsecapi.h>
#include <dsgetdc.h>
#include <lmcons.h>
#include <lmapibuf.h>
#include <jni.h>
#include <winsock.h>

#undef LSA_SUCCESS
#define LSA_SUCCESS(Status) ((Status) >= 0)
#define EXIT_FAILURE -1 // mdu

/*
 * Library-wide static references
 */

jclass derValueClass = NULL;
jclass ticketClass = NULL;
jclass principalNameClass = NULL;
jclass encryptionKeyClass = NULL;
jclass ticketFlagsClass = NULL;
jclass kerberosTimeClass = NULL;
jclass javaLangStringClass = NULL;

jmethodID derValueConstructor = 0;
jmethodID ticketConstructor = 0;
jmethodID principalNameConstructor = 0;
jmethodID encryptionKeyConstructor = 0;
jmethodID ticketFlagsConstructor = 0;
jmethodID kerberosTimeConstructor = 0;
jmethodID krbcredsConstructor = 0;
jmethodID setRealmMethod = 0;

/*
 * Function prototypes for internal routines
 *
 */

BOOL PackageConnectLookup(PHANDLE,PULONG);

NTSTATUS ConstructTicketRequest(UNICODE_STRING DomainName,
                                PKERB_RETRIEVE_TKT_REQUEST *outRequest,
                                ULONG *outSize);

DWORD ConcatenateUnicodeStrings(UNICODE_STRING *pTarget,
                                UNICODE_STRING Source1,
                                UNICODE_STRING Source2);

VOID ShowNTError(LPSTR,NTSTATUS);

VOID
InitUnicodeString(
91
    PUNICODE_STRING DestinationString,
D
duke 已提交
92
    PCWSTR SourceString OPTIONAL
93
);
D
duke 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110

jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize);

//mdu
jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,
                                UNICODE_STRING domainName);

jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey);
jobject BuildTicketFlags(JNIEnv *env, PULONG flags);
jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime);

/*
 * Class:     sun_security_krb5_KrbCreds
 * Method:    JNI_OnLoad
 */

JNIEXPORT jint JNICALL JNI_OnLoad(
111 112
        JavaVM  *jvm,
        void    *reserved) {
D
duke 已提交
113

114 115
    jclass cls;
    JNIEnv *env;
D
duke 已提交
116

117 118 119
    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
        return JNI_EVERSION; /* JNI version not supported */
    }
D
duke 已提交
120

121
    cls = (*env)->FindClass(env,"sun/security/krb5/internal/Ticket");
D
duke 已提交
122

123 124 125 126 127 128 129
    if (cls == NULL) {
        printf("Couldn't find Ticket\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found Ticket\n");
    #endif /* DEBUG */
D
duke 已提交
130

131 132 133 134 135 136 137
    ticketClass = (*env)->NewWeakGlobalRef(env,cls);
    if (ticketClass == NULL) {
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Made NewWeakGlobalRef\n");
    #endif /* DEBUG */
D
duke 已提交
138

139
    cls = (*env)->FindClass(env, "sun/security/krb5/PrincipalName");
D
duke 已提交
140

141 142 143 144 145 146 147
    if (cls == NULL) {
        printf("Couldn't find PrincipalName\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found PrincipalName\n");
    #endif /* DEBUG */
D
duke 已提交
148

149 150 151 152 153 154 155
    principalNameClass = (*env)->NewWeakGlobalRef(env,cls);
    if (principalNameClass == NULL) {
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Made NewWeakGlobalRef\n");
    #endif /* DEBUG */
D
duke 已提交
156

157
    cls = (*env)->FindClass(env,"sun/security/util/DerValue");
D
duke 已提交
158

159 160 161 162 163 164 165
    if (cls == NULL) {
        printf("Couldn't find DerValue\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found DerValue\n");
    #endif /* DEBUG */
D
duke 已提交
166

167 168 169 170 171 172 173
    derValueClass = (*env)->NewWeakGlobalRef(env,cls);
    if (derValueClass == NULL) {
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Made NewWeakGlobalRef\n");
    #endif /* DEBUG */
D
duke 已提交
174

175
    cls = (*env)->FindClass(env,"sun/security/krb5/EncryptionKey");
D
duke 已提交
176

177 178 179 180 181 182 183
    if (cls == NULL) {
        printf("Couldn't find EncryptionKey\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found EncryptionKey\n");
    #endif /* DEBUG */
D
duke 已提交
184

185 186 187 188 189 190 191
    encryptionKeyClass = (*env)->NewWeakGlobalRef(env,cls);
    if (encryptionKeyClass == NULL) {
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Made NewWeakGlobalRef\n");
    #endif /* DEBUG */
D
duke 已提交
192

193
    cls = (*env)->FindClass(env,"sun/security/krb5/internal/TicketFlags");
D
duke 已提交
194

195 196 197 198 199 200 201
    if (cls == NULL) {
        printf("Couldn't find TicketFlags\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found TicketFlags\n");
    #endif /* DEBUG */
D
duke 已提交
202

203 204 205 206 207 208 209
    ticketFlagsClass = (*env)->NewWeakGlobalRef(env,cls);
    if (ticketFlagsClass == NULL) {
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Made NewWeakGlobalRef\n");
    #endif /* DEBUG */
D
duke 已提交
210

211
    cls = (*env)->FindClass(env,"sun/security/krb5/internal/KerberosTime");
D
duke 已提交
212

213 214 215 216 217 218 219
    if (cls == NULL) {
        printf("Couldn't find KerberosTime\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found KerberosTime\n");
    #endif /* DEBUG */
D
duke 已提交
220

221 222 223 224 225 226 227
    kerberosTimeClass = (*env)->NewWeakGlobalRef(env,cls);
    if (kerberosTimeClass == NULL) {
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Made NewWeakGlobalRef\n");
    #endif /* DEBUG */
D
duke 已提交
228

229
    cls = (*env)->FindClass(env,"java/lang/String");
D
duke 已提交
230

231 232 233 234 235 236 237
    if (cls == NULL) {
        printf("Couldn't find String\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found String\n");
    #endif /* DEBUG */
D
duke 已提交
238

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
    javaLangStringClass = (*env)->NewWeakGlobalRef(env,cls);
    if (javaLangStringClass == NULL) {
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Made NewWeakGlobalRef\n");
    #endif /* DEBUG */

    derValueConstructor = (*env)->GetMethodID(env, derValueClass,
                                            "<init>", "([B)V");
    if (derValueConstructor == 0) {
        printf("Couldn't find DerValue constructor\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found DerValue constructor\n");
    #endif /* DEBUG */

    ticketConstructor = (*env)->GetMethodID(env, ticketClass,
                            "<init>", "(Lsun/security/util/DerValue;)V");
    if (ticketConstructor == 0) {
        printf("Couldn't find Ticket constructor\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found Ticket constructor\n");
    #endif /* DEBUG */

    principalNameConstructor = (*env)->GetMethodID(env, principalNameClass,
                                    "<init>", "([Ljava/lang/String;)V");
    if (principalNameConstructor == 0) {
        printf("Couldn't find PrincipalName constructor\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found PrincipalName constructor\n");
    #endif /* DEBUG */

    encryptionKeyConstructor = (*env)->GetMethodID(env, encryptionKeyClass,
                                            "<init>", "(I[B)V");
    if (encryptionKeyConstructor == 0) {
        printf("Couldn't find EncryptionKey constructor\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found EncryptionKey constructor\n");
    #endif /* DEBUG */

    ticketFlagsConstructor = (*env)->GetMethodID(env, ticketFlagsClass,
                                            "<init>", "(I[B)V");
    if (ticketFlagsConstructor == 0) {
        printf("Couldn't find TicketFlags constructor\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found TicketFlags constructor\n");
    #endif /* DEBUG */

    kerberosTimeConstructor = (*env)->GetMethodID(env, kerberosTimeClass,
                                    "<init>", "(Ljava/lang/String;)V");
    if (kerberosTimeConstructor == 0) {
        printf("Couldn't find KerberosTime constructor\n");
        return JNI_ERR;
    }
    #ifdef DEBUG
    printf("Found KerberosTime constructor\n");
    #endif /* DEBUG */

    // load the setRealm method in PrincipalName
    setRealmMethod = (*env)->GetMethodID(env, principalNameClass,
                                    "setRealm", "(Ljava/lang/String;)V");
    if (setRealmMethod == 0) {
        printf("Couldn't find setRealm in PrincipalName\n");
        return JNI_ERR;
    }
D
duke 已提交
314

315 316 317
    #ifdef DEBUG
    printf("Finished OnLoad processing\n");
    #endif /* DEBUG */
D
duke 已提交
318

319
    return JNI_VERSION_1_2;
D
duke 已提交
320 321 322 323 324 325 326 327
}

/*
 * Class:     sun_security_jgss_KrbCreds
 * Method:    JNI_OnUnload
 */

JNIEXPORT void JNICALL JNI_OnUnload(
328 329
        JavaVM  *jvm,
        void    *reserved) {
D
duke 已提交
330

331
    JNIEnv *env;
D
duke 已提交
332

333 334 335
    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
        return; /* Nothing else we can do */
    }
D
duke 已提交
336

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    if (ticketClass != NULL) {
        (*env)->DeleteWeakGlobalRef(env,ticketClass);
    }
    if (derValueClass != NULL) {
        (*env)->DeleteWeakGlobalRef(env,derValueClass);
    }
    if (principalNameClass != NULL) {
        (*env)->DeleteWeakGlobalRef(env,principalNameClass);
    }
    if (encryptionKeyClass != NULL) {
        (*env)->DeleteWeakGlobalRef(env,encryptionKeyClass);
    }
    if (ticketFlagsClass != NULL) {
        (*env)->DeleteWeakGlobalRef(env,ticketFlagsClass);
    }
    if (kerberosTimeClass != NULL) {
        (*env)->DeleteWeakGlobalRef(env,kerberosTimeClass);
    }
    if (javaLangStringClass != NULL) {
        (*env)->DeleteWeakGlobalRef(env,javaLangStringClass);
    }
D
duke 已提交
358

359
    return;
D
duke 已提交
360 361 362 363 364 365 366 367
}

/*
 * Class:     sun_security_krb5_Credentials
 * Method:    acquireDefaultNativeCreds
 * Signature: ()Lsun/security/krb5/Credentials;
 */
JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds(
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
        JNIEnv *env,
        jclass krbcredsClass) {

    KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
    PKERB_RETRIEVE_TKT_RESPONSE TktCacheResponse = NULL;
    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
    PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
    NTSTATUS Status, SubStatus;
    ULONG requestSize = 0;
    ULONG responseSize = 0;
    ULONG rspSize = 0;
    HANDLE LogonHandle = NULL;
    ULONG PackageId;
    jobject ticket, clientPrincipal, targetPrincipal, encryptionKey;
    jobject ticketFlags, startTime, endTime, krbCreds = NULL;
    jobject authTime, renewTillTime, hostAddresses = NULL;
    KERB_EXTERNAL_TICKET *msticket;
    int ignore_cache = 0;
    FILETIME Now, EndTime, LocalEndTime;

    while (TRUE) {
D
duke 已提交
389 390

        if (krbcredsConstructor == 0) {
391 392
            krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>",
                    "(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");
D
duke 已提交
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
            if (krbcredsConstructor == 0) {
                printf("Couldn't find sun.security.krb5.Credentials constructor\n");
                break;
            }
        }

        #ifdef DEBUG
        printf("Found KrbCreds constructor\n");
        #endif

        //
        // Get the logon handle and package ID from the
        // Kerberos package
        //
        if (!PackageConnectLookup(&LogonHandle, &PackageId))
            break;

        #ifdef DEBUG
        printf("Got handle to Kerberos package\n");
        #endif /* DEBUG */

        // Get the MS TGT from cache
        CacheRequest.MessageType = KerbRetrieveTicketMessage;
        CacheRequest.LogonId.LowPart = 0;
        CacheRequest.LogonId.HighPart = 0;

        Status = LsaCallAuthenticationPackage(
                        LogonHandle,
                        PackageId,
                        &CacheRequest,
                        sizeof(CacheRequest),
                        &TktCacheResponse,
                        &rspSize,
                        &SubStatus
                        );

        #ifdef DEBUG
        printf("Response size is %d\n", rspSize);
        #endif

        if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {
            if (!LSA_SUCCESS(Status)) {
                ShowNTError("LsaCallAuthenticationPackage", Status);
            } else {
                ShowNTError("Protocol status", SubStatus);
            }
            break;
        }

        // got the native MS TGT
        msticket = &(TktCacheResponse->Ticket);

        // check TGT validity
        switch (msticket->SessionKey.KeyType) {
            case KERB_ETYPE_DES_CBC_CRC:
            case KERB_ETYPE_DES_CBC_MD5:
            case KERB_ETYPE_NULL:
            case KERB_ETYPE_RC4_HMAC_NT:
                GetSystemTimeAsFileTime(&Now);
                EndTime.dwLowDateTime = msticket->EndTime.LowPart;
                EndTime.dwHighDateTime = msticket->EndTime.HighPart;
                FileTimeToLocalFileTime(&EndTime, &LocalEndTime);
                if (CompareFileTime(&Now, &LocalEndTime) >= 0) {
                    ignore_cache = 1;
                }
                if (msticket->TicketFlags & KERB_TICKET_FLAGS_invalid) {
                    ignore_cache = 1;
                }
                break;
            case KERB_ETYPE_RC4_MD4:
            default:
                // not supported
                ignore_cache = 1;
                break;
        }

        if (ignore_cache) {
            #ifdef DEBUG
            printf("MS TGT in cache is invalid/not supported; request new ticket\n");
            #endif /* DEBUG */

            // use domain to request Ticket
            Status = ConstructTicketRequest(msticket->TargetDomainName,
                                &pTicketRequest, &requestSize);
            if (!LSA_SUCCESS(Status)) {
                ShowNTError("ConstructTicketRequest status", Status);
                break;
            }

            pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
            pTicketRequest->EncryptionType = KERB_ETYPE_DES_CBC_MD5;
            pTicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_DONT_USE_CACHE;

            Status = LsaCallAuthenticationPackage(
                        LogonHandle,
                        PackageId,
                        pTicketRequest,
                        requestSize,
                        &pTicketResponse,
                        &responseSize,
                        &SubStatus
                        );

            #ifdef DEBUG
            printf("Response size is %d\n", responseSize);
            #endif /* DEBUG */

            if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {
                if (!LSA_SUCCESS(Status)) {
                    ShowNTError("LsaCallAuthenticationPackage", Status);
                } else {
                    ShowNTError("Protocol status", SubStatus);
                }
                break;
            }

            // got the native MS Kerberos TGT
            msticket = &(pTicketResponse->Ticket);
        }

513
        /*
D
duke 已提交
514

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
        typedef struct _KERB_RETRIEVE_TKT_RESPONSE {
            KERB_EXTERNAL_TICKET Ticket;
        } KERB_RETRIEVE_TKT_RESPONSE, *PKERB_RETRIEVE_TKT_RESPONSE;

        typedef struct _KERB_EXTERNAL_TICKET {
            PKERB_EXTERNAL_NAME ServiceName;
            PKERB_EXTERNAL_NAME TargetName;
            PKERB_EXTERNAL_NAME ClientName;
            UNICODE_STRING DomainName;
            UNICODE_STRING TargetDomainName;
            UNICODE_STRING AltTargetDomainName;
            KERB_CRYPTO_KEY SessionKey;
            ULONG TicketFlags;
            ULONG Flags;
            LARGE_INTEGER KeyExpirationTime;
            LARGE_INTEGER StartTime;
            LARGE_INTEGER EndTime;
            LARGE_INTEGER RenewUntil;
            LARGE_INTEGER TimeSkew;
            ULONG EncodedTicketSize;
            PUCHAR EncodedTicket; <========== Here's the good stuff
        } KERB_EXTERNAL_TICKET, *PKERB_EXTERNAL_TICKET;

        typedef struct _KERB_EXTERNAL_NAME {
            SHORT NameType;
            USHORT NameCount;
            UNICODE_STRING Names[ANYSIZE_ARRAY];
        } KERB_EXTERNAL_NAME, *PKERB_EXTERNAL_NAME;

        typedef struct _LSA_UNICODE_STRING {
            USHORT Length;
            USHORT MaximumLength;
            PWSTR  Buffer;
        } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;

        typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;

        typedef struct KERB_CRYPTO_KEY {
            LONG KeyType;
            ULONG Length;
            PUCHAR Value;
        } KERB_CRYPTO_KEY, *PKERB_CRYPTO_KEY;

        */
D
duke 已提交
559 560 561 562
        // Build a com.sun.security.krb5.Ticket
        ticket = BuildTicket(env, msticket->EncodedTicket,
                                msticket->EncodedTicketSize);
        if (ticket == NULL) {
563
            break;
D
duke 已提交
564 565 566 567 568
        }
        // OK, have a Ticket, now need to get the client name
        clientPrincipal = BuildPrincipal(env, msticket->ClientName,
                                msticket->TargetDomainName); // mdu
        if (clientPrincipal == NULL) {
569
            break;
D
duke 已提交
570 571 572 573 574 575
        }

        // and the "name" of tgt
        targetPrincipal = BuildPrincipal(env, msticket->ServiceName,
                        msticket->DomainName);
        if (targetPrincipal == NULL) {
576
            break;
D
duke 已提交
577 578 579 580 581
        }

        // Get the encryption key
        encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey));
        if (encryptionKey == NULL) {
582
            break;
D
duke 已提交
583 584 585 586 587
        }

        // and the ticket flags
        ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags));
        if (ticketFlags == NULL) {
588
            break;
D
duke 已提交
589 590 591 592 593
        }

        // Get the start time
        startTime = BuildKerberosTime(env, &(msticket->StartTime));
        if (startTime == NULL) {
594
            break;
D
duke 已提交
595 596 597 598 599 600 601 602 603 604 605 606
        }

        /*
         * mdu: No point storing the eky expiration time in the auth
         * time field. Set it to be same as startTime. Looks like
         * windows does not have post-dated tickets.
         */
        authTime = startTime;

        // and the end time
        endTime = BuildKerberosTime(env, &(msticket->EndTime));
        if (endTime == NULL) {
607
            break;
D
duke 已提交
608 609 610 611 612
        }

        // Get the renew till time
        renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil));
        if (renewTillTime == NULL) {
613
            break;
D
duke 已提交
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
        }

        // and now go build a KrbCreds object
        krbCreds = (*env)->NewObject(
                env,
                krbcredsClass,
                krbcredsConstructor,
                ticket,
                clientPrincipal,
                targetPrincipal,
                encryptionKey,
                ticketFlags,
                authTime, // mdu
                startTime,
                endTime,
                renewTillTime, //mdu
                hostAddresses);

        break;
633
    } // end of WHILE
D
duke 已提交
634

635 636 637 638 639 640 641 642 643 644
    // clean up resources
    if (TktCacheResponse != NULL) {
        LsaFreeReturnBuffer(TktCacheResponse);
    }
    if (pTicketRequest) {
        LocalFree(pTicketRequest);
    }
    if (pTicketResponse != NULL) {
        LsaFreeReturnBuffer(pTicketResponse);
    }
D
duke 已提交
645

646
    return krbCreds;
D
duke 已提交
647 648 649 650 651 652
}

static NTSTATUS
ConstructTicketRequest(UNICODE_STRING DomainName,
                PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize)
{
653 654 655 656 657 658
    NTSTATUS Status;
    UNICODE_STRING TargetPrefix;
    USHORT TargetSize;
    ULONG RequestSize;
    ULONG Length;
    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
D
duke 已提交
659

660 661
    *outRequest = NULL;
    *outSize = 0;
D
duke 已提交
662

663 664 665 666
    //
    // Set up the "krbtgt/" target prefix into a UNICODE_STRING so we
    // can easily concatenate it later.
    //
D
duke 已提交
667

668 669 670 671
    TargetPrefix.Buffer = L"krbtgt/";
    Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);
    TargetPrefix.Length = (USHORT)Length;
    TargetPrefix.MaximumLength = TargetPrefix.Length;
D
duke 已提交
672

673 674 675 676 677 678 679 680
    //
    // We will need to concatenate the "krbtgt/" prefix and the
    // Logon Session's DnsDomainName into our request's target name.
    //
    // Therefore, first compute the necessary buffer size for that.
    //
    // Note that we might theoretically have integer overflow.
    //
D
duke 已提交
681

682
    TargetSize = TargetPrefix.Length + DomainName.Length;
D
duke 已提交
683

684 685 686 687
    //
    // The ticket request buffer needs to be a single buffer.  That buffer
    // needs to include the buffer for the target name.
    //
D
duke 已提交
688

689
    RequestSize = sizeof (*pTicketRequest) + TargetSize;
D
duke 已提交
690

691 692 693
    //
    // Allocate the request buffer and make sure it's zero-filled.
    //
D
duke 已提交
694

695 696 697 698
    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)
                    LocalAlloc(LMEM_ZEROINIT, RequestSize);
    if (!pTicketRequest)
        return GetLastError();
D
duke 已提交
699

700 701 702 703
    //
    // Concatenate the target prefix with the previous reponse's
    // target domain.
    //
D
duke 已提交
704

705 706 707 708 709 710 711 712 713
    pTicketRequest->TargetName.Length = 0;
    pTicketRequest->TargetName.MaximumLength = TargetSize;
    pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
    Status = ConcatenateUnicodeStrings(&(pTicketRequest->TargetName),
                                    TargetPrefix,
                                    DomainName);
    *outRequest = pTicketRequest;
    *outSize    = RequestSize;
    return Status;
D
duke 已提交
714 715 716 717 718 719 720 721 722
}

DWORD
ConcatenateUnicodeStrings(
    UNICODE_STRING *pTarget,
    UNICODE_STRING Source1,
    UNICODE_STRING Source2
    )
{
723 724 725 726 727
    //
    // The buffers for Source1 and Source2 cannot overlap pTarget's
    // buffer.  Source1.Length + Source2.Length must be <= 0xFFFF,
    // otherwise we overflow...
    //
D
duke 已提交
728

729 730
    USHORT TotalSize = Source1.Length + Source2.Length;
    PBYTE buffer = (PBYTE) pTarget->Buffer;
D
duke 已提交
731

732 733
    if (TotalSize > pTarget->MaximumLength)
        return ERROR_INSUFFICIENT_BUFFER;
D
duke 已提交
734

735 736 737 738
    pTarget->Length = TotalSize;
    memcpy(buffer, Source1.Buffer, Source1.Length);
    memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);
    return ERROR_SUCCESS;
D
duke 已提交
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
}

BOOL
PackageConnectLookup(
    HANDLE *pLogonHandle,
    ULONG *pPackageId
    )
{
    LSA_STRING Name;
    NTSTATUS Status;

    Status = LsaConnectUntrusted(
                pLogonHandle
                );

    if (!LSA_SUCCESS(Status))
    {
        ShowNTError("LsaConnectUntrusted", Status);
        return FALSE;
    }

    Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
    Name.Length = (USHORT)strlen(Name.Buffer);
    Name.MaximumLength = Name.Length + 1;

    Status = LsaLookupAuthenticationPackage(
                *pLogonHandle,
                &Name,
                pPackageId
                );

    if (!LSA_SUCCESS(Status))
    {
        ShowNTError("LsaLookupAuthenticationPackage", Status);
        return FALSE;
    }

    return TRUE;

}

VOID
ShowLastError(
        LPSTR szAPI,
        DWORD dwError
        )
{
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
    #define MAX_MSG_SIZE 256

    static WCHAR szMsgBuf[MAX_MSG_SIZE];
    DWORD dwRes;

    printf("Error calling function %s: %lu\n", szAPI, dwError);

    dwRes = FormatMessage (
            FORMAT_MESSAGE_FROM_SYSTEM,
            NULL,
            dwError,
            0,
            szMsgBuf,
            MAX_MSG_SIZE,
            NULL);
    if (0 == dwRes) {
        printf("FormatMessage failed with %d\n", GetLastError());
        // ExitProcess(EXIT_FAILURE);
    } else {
        printf("%S",szMsgBuf);
    }
D
duke 已提交
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
}

VOID
ShowNTError(
        LPSTR szAPI,
        NTSTATUS Status
        )
{
    //
    // Convert the NTSTATUS to Winerror. Then call ShowLastError().
    //
    ShowLastError(szAPI, LsaNtStatusToWinError(Status));
}

VOID
InitUnicodeString(
        PUNICODE_STRING DestinationString,
    PCWSTR SourceString OPTIONAL
    )
{
    ULONG Length;

    DestinationString->Buffer = (PWSTR)SourceString;
    if (SourceString != NULL) {
        Length = (ULONG)wcslen( SourceString ) * sizeof( WCHAR );
        DestinationString->Length = (USHORT)Length;
        DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
834
    }
D
duke 已提交
835 836 837
    else {
        DestinationString->MaximumLength = 0;
        DestinationString->Length = 0;
838
    }
D
duke 已提交
839 840 841 842
}

jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize) {

843 844 845
    /* To build a Ticket, we first need to build a DerValue out of the EncodedTicket.
     * But before we can do that, we need to make a byte array out of the ET.
     */
D
duke 已提交
846

847 848
    jobject derValue, ticket;
    jbyteArray ary;
D
duke 已提交
849

850 851 852 853
    ary = (*env)->NewByteArray(env,encodedTicketSize);
    if ((*env)->ExceptionOccurred(env)) {
        return (jobject) NULL;
    }
D
duke 已提交
854

855 856 857 858 859 860
    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize,
                                    (jbyte *)encodedTicket);
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->DeleteLocalRef(env, ary);
        return (jobject) NULL;
    }
D
duke 已提交
861

862 863
    derValue = (*env)->NewObject(env, derValueClass, derValueConstructor, ary);
    if ((*env)->ExceptionOccurred(env)) {
D
duke 已提交
864
        (*env)->DeleteLocalRef(env, ary);
865 866 867 868 869 870
        return (jobject) NULL;
    }

    (*env)->DeleteLocalRef(env, ary);
    ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, derValue);
    if ((*env)->ExceptionOccurred(env)) {
D
duke 已提交
871
        (*env)->DeleteLocalRef(env, derValue);
872 873 874 875
        return (jobject) NULL;
    }
    (*env)->DeleteLocalRef(env, derValue);
    return ticket;
D
duke 已提交
876 877 878 879 880 881
}

// mdu
jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,
                                UNICODE_STRING domainName) {

882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
    /*
     * To build the Principal, we need to get the names out of
     * this goofy MS structure
     */
    jobject principal = NULL;
    jobject realmStr = NULL;
    jobjectArray stringArray;
    jstring tempString;
    int nameCount,i;
    PUNICODE_STRING scanner;
    WCHAR *realm;
    ULONG realmLen;

    realm = (WCHAR *) LocalAlloc(LMEM_ZEROINIT,
            ((domainName.Length)*sizeof(WCHAR) + sizeof(UNICODE_NULL)));
    wcsncpy(realm, domainName.Buffer, domainName.Length/sizeof(WCHAR));

    #ifdef DEBUG
    printf("Principal domain is %S\n", realm);
    printf("Name type is %x\n", principalName->NameType);
    printf("Name count is %x\n", principalName->NameCount);
    #endif

    nameCount = principalName->NameCount;
    stringArray = (*env)->NewObjectArray(env, nameCount,
                            javaLangStringClass, NULL);
    if (stringArray == NULL) {
        printf("Can't allocate String array for Principal\n");
        LocalFree(realm);
        return principal;
    }
D
duke 已提交
913

914 915 916
    for (i=0; i<nameCount; i++) {
        // get the principal name
        scanner = &(principalName->Names[i]);
D
duke 已提交
917

918 919 920 921 922
        // OK, got a Char array, so construct a String
        tempString = (*env)->NewString(env, (const jchar*)scanner->Buffer,
                            scanner->Length/sizeof(WCHAR));
        // Set the String into the StringArray
        (*env)->SetObjectArrayElement(env, stringArray, i, tempString);
D
duke 已提交
923

924 925 926 927
        // Do I have to worry about storage reclamation here?
    }
    principal = (*env)->NewObject(env, principalNameClass,
                    principalNameConstructor, stringArray);
D
duke 已提交
928

929 930 931 932
    // now set the realm in the principal
    realmLen = (ULONG)wcslen((PWCHAR)realm);
    realmStr = (*env)->NewString(env, (PWCHAR)realm, (USHORT)realmLen);
    (*env)->CallVoidMethod(env, principal, setRealmMethod, realmStr);
D
duke 已提交
933

934 935
    // free local resources
    LocalFree(realm);
D
duke 已提交
936

937
    return principal;
D
duke 已提交
938 939 940
}

jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) {
941 942 943 944 945 946 947 948 949 950 951 952 953
    // First, need to build a byte array
    jbyteArray ary;
    jobject encryptionKey = NULL;

    ary = (*env)->NewByteArray(env,cryptoKey->Length);
    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, cryptoKey->Length,
                                    (jbyte *)cryptoKey->Value);
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->DeleteLocalRef(env, ary);
    } else {
        encryptionKey = (*env)->NewObject(env, encryptionKeyClass,
                encryptionKeyConstructor, cryptoKey->KeyType, ary);
    }
D
duke 已提交
954

955
    return encryptionKey;
D
duke 已提交
956 957 958
}

jobject BuildTicketFlags(JNIEnv *env, PULONG flags) {
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
    jobject ticketFlags = NULL;
    jbyteArray ary;
    /*
     * mdu: Convert the bytes to nework byte order before copying
     * them to a Java byte array.
     */
    ULONG nlflags = htonl(*flags);

    ary = (*env)->NewByteArray(env, sizeof(*flags));
    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, sizeof(*flags),
                                    (jbyte *)&nlflags);
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->DeleteLocalRef(env, ary);
    } else {
        ticketFlags = (*env)->NewObject(env, ticketFlagsClass,
                ticketFlagsConstructor, sizeof(*flags)*8, ary);
    }
D
duke 已提交
976

977
    return ticketFlags;
D
duke 已提交
978 979 980
}

jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) {
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001
    jobject kerberosTime = NULL;
    jstring stringTime = NULL;
    SYSTEMTIME systemTime;
    WCHAR timeString[16];
    WCHAR month[3];
    WCHAR day[3];
    WCHAR hour[3];
    WCHAR minute[3];
    WCHAR second[3];

    if (FileTimeToSystemTime((FILETIME *)kerbtime, &systemTime)) {
        // XXX Cannot use %02.2ld, because the leading 0 is ignored for integers.
        // So, print them to strings, and then print them to the master string with a
        // format pattern that makes it two digits and prefix with a 0 if necessary.
        swprintf( (wchar_t *)month, L"%2.2d", systemTime.wMonth);
        swprintf( (wchar_t *)day, L"%2.2d", systemTime.wDay);
        swprintf( (wchar_t *)hour, L"%2.2d", systemTime.wHour);
        swprintf( (wchar_t *)minute, L"%2.2d", systemTime.wMinute);
        swprintf( (wchar_t *)second, L"%2.2d", systemTime.wSecond);
        swprintf( (wchar_t *)timeString,
                L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",
D
duke 已提交
1002 1003 1004 1005 1006 1007
                systemTime.wYear,
                month,
                day,
                hour,
                minute,
                second );
1008 1009 1010 1011 1012 1013 1014 1015
        #ifdef DEBUG
        printf("%S\n", (wchar_t *)timeString);
        #endif /* DEBUG */
        stringTime = (*env)->NewString(env, timeString,
                (sizeof(timeString)/sizeof(WCHAR))-1);
        if (stringTime != NULL) { // everything's OK so far
            kerberosTime = (*env)->NewObject(env, kerberosTimeClass,
                    kerberosTimeConstructor, stringTime);
D
duke 已提交
1016
        }
1017 1018
    }
    return kerberosTime;
D
duke 已提交
1019
}