NativeCreds.c 31.7 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6
 * 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
7
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
8
 * particular file as subject to the "Classpath" exception as provided
9
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
10 11 12 13 14 15 16 17 18 19 20
 *
 * 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.
 *
21 22 23
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
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
 */

/*
 * ===========================================================================
 * (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;

/*
 * Function prototypes for internal routines
 *
 */
75
BOOL native_debug = 0;
D
duke 已提交
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

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;
116
    jfieldID fldDEBUG;
D
duke 已提交
117

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

122 123 124 125 126 127 128 129 130 131
    cls = (*env)->FindClass(env,"sun/security/krb5/internal/Krb5");
    if (cls == NULL) {
        printf("LSA: Couldn't find Krb5\n");
        return JNI_ERR;
    }
    fldDEBUG = (*env)->GetStaticFieldID(env, cls, "DEBUG", "Z");
    if (fldDEBUG == NULL) {
        printf("LSA: Krb5 has no DEBUG field\n");
        return JNI_ERR;
    }
132
    native_debug = (*env)->GetStaticBooleanField(env, cls, fldDEBUG);
133

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

136
    if (cls == NULL) {
137
        printf("LSA: Couldn't find Ticket\n");
138 139
        return JNI_ERR;
    }
140
    if (native_debug) {
141
        printf("LSA: Found Ticket\n");
142
    }
D
duke 已提交
143

144 145 146 147
    ticketClass = (*env)->NewWeakGlobalRef(env,cls);
    if (ticketClass == NULL) {
        return JNI_ERR;
    }
148
    if (native_debug) {
149
        printf("LSA: Made NewWeakGlobalRef\n");
150
    }
D
duke 已提交
151

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

154
    if (cls == NULL) {
155
        printf("LSA: Couldn't find PrincipalName\n");
156 157
        return JNI_ERR;
    }
158
    if (native_debug) {
159
        printf("LSA: Found PrincipalName\n");
160
    }
D
duke 已提交
161

162 163 164 165
    principalNameClass = (*env)->NewWeakGlobalRef(env,cls);
    if (principalNameClass == NULL) {
        return JNI_ERR;
    }
166
    if (native_debug) {
167
        printf("LSA: Made NewWeakGlobalRef\n");
168
    }
D
duke 已提交
169

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

172
    if (cls == NULL) {
173
        printf("LSA: Couldn't find DerValue\n");
174 175
        return JNI_ERR;
    }
176
    if (native_debug) {
177
        printf("LSA: Found DerValue\n");
178
    }
D
duke 已提交
179

180 181 182 183
    derValueClass = (*env)->NewWeakGlobalRef(env,cls);
    if (derValueClass == NULL) {
        return JNI_ERR;
    }
184
    if (native_debug) {
185
        printf("LSA: Made NewWeakGlobalRef\n");
186
    }
D
duke 已提交
187

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

190
    if (cls == NULL) {
191
        printf("LSA: Couldn't find EncryptionKey\n");
192 193
        return JNI_ERR;
    }
194
    if (native_debug) {
195
        printf("LSA: Found EncryptionKey\n");
196
    }
D
duke 已提交
197

198 199 200 201
    encryptionKeyClass = (*env)->NewWeakGlobalRef(env,cls);
    if (encryptionKeyClass == NULL) {
        return JNI_ERR;
    }
202
    if (native_debug) {
203
        printf("LSA: Made NewWeakGlobalRef\n");
204
    }
D
duke 已提交
205

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

208
    if (cls == NULL) {
209
        printf("LSA: Couldn't find TicketFlags\n");
210 211
        return JNI_ERR;
    }
212
    if (native_debug) {
213
        printf("LSA: Found TicketFlags\n");
214
    }
D
duke 已提交
215

216 217 218 219
    ticketFlagsClass = (*env)->NewWeakGlobalRef(env,cls);
    if (ticketFlagsClass == NULL) {
        return JNI_ERR;
    }
220
    if (native_debug) {
221
        printf("LSA: Made NewWeakGlobalRef\n");
222
    }
D
duke 已提交
223

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

226
    if (cls == NULL) {
227
        printf("LSA: Couldn't find KerberosTime\n");
228 229
        return JNI_ERR;
    }
230
    if (native_debug) {
231
        printf("LSA: Found KerberosTime\n");
232
    }
D
duke 已提交
233

234 235 236 237
    kerberosTimeClass = (*env)->NewWeakGlobalRef(env,cls);
    if (kerberosTimeClass == NULL) {
        return JNI_ERR;
    }
238
    if (native_debug) {
239
        printf("LSA: Made NewWeakGlobalRef\n");
240
    }
D
duke 已提交
241

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

244
    if (cls == NULL) {
245
        printf("LSA: Couldn't find String\n");
246 247
        return JNI_ERR;
    }
248
    if (native_debug) {
249
        printf("LSA: Found String\n");
250
    }
D
duke 已提交
251

252 253 254 255
    javaLangStringClass = (*env)->NewWeakGlobalRef(env,cls);
    if (javaLangStringClass == NULL) {
        return JNI_ERR;
    }
256
    if (native_debug) {
257
        printf("LSA: Made NewWeakGlobalRef\n");
258
    }
259 260 261 262

    derValueConstructor = (*env)->GetMethodID(env, derValueClass,
                                            "<init>", "([B)V");
    if (derValueConstructor == 0) {
263
        printf("LSA: Couldn't find DerValue constructor\n");
264 265
        return JNI_ERR;
    }
266
    if (native_debug) {
267
        printf("LSA: Found DerValue constructor\n");
268
    }
269 270 271 272

    ticketConstructor = (*env)->GetMethodID(env, ticketClass,
                            "<init>", "(Lsun/security/util/DerValue;)V");
    if (ticketConstructor == 0) {
273
        printf("LSA: Couldn't find Ticket constructor\n");
274 275
        return JNI_ERR;
    }
276
    if (native_debug) {
277
        printf("LSA: Found Ticket constructor\n");
278
    }
279 280

    principalNameConstructor = (*env)->GetMethodID(env, principalNameClass,
281
                        "<init>", "([Ljava/lang/String;Ljava/lang/String;)V");
282
    if (principalNameConstructor == 0) {
283
        printf("LSA: Couldn't find PrincipalName constructor\n");
284 285
        return JNI_ERR;
    }
286
    if (native_debug) {
287
        printf("LSA: Found PrincipalName constructor\n");
288
    }
289 290 291 292

    encryptionKeyConstructor = (*env)->GetMethodID(env, encryptionKeyClass,
                                            "<init>", "(I[B)V");
    if (encryptionKeyConstructor == 0) {
293
        printf("LSA: Couldn't find EncryptionKey constructor\n");
294 295
        return JNI_ERR;
    }
296
    if (native_debug) {
297
        printf("LSA: Found EncryptionKey constructor\n");
298
    }
299 300 301 302

    ticketFlagsConstructor = (*env)->GetMethodID(env, ticketFlagsClass,
                                            "<init>", "(I[B)V");
    if (ticketFlagsConstructor == 0) {
303
        printf("LSA: Couldn't find TicketFlags constructor\n");
304 305
        return JNI_ERR;
    }
306
    if (native_debug) {
307
        printf("LSA: Found TicketFlags constructor\n");
308
    }
309 310 311 312

    kerberosTimeConstructor = (*env)->GetMethodID(env, kerberosTimeClass,
                                    "<init>", "(Ljava/lang/String;)V");
    if (kerberosTimeConstructor == 0) {
313
        printf("LSA: Couldn't find KerberosTime constructor\n");
314 315
        return JNI_ERR;
    }
316
    if (native_debug) {
317
        printf("LSA: Found KerberosTime constructor\n");
318
    }
319

320
    if (native_debug) {
321
        printf("LSA: Finished OnLoad processing\n");
322
    }
D
duke 已提交
323

324
    return JNI_VERSION_1_2;
D
duke 已提交
325 326 327 328 329 330 331 332
}

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

JNIEXPORT void JNICALL JNI_OnUnload(
333 334
        JavaVM  *jvm,
        void    *reserved) {
D
duke 已提交
335

336
    JNIEnv *env;
D
duke 已提交
337

338 339 340
    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
        return; /* Nothing else we can do */
    }
D
duke 已提交
341

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
    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 已提交
363

364
    return;
D
duke 已提交
365 366 367 368 369
}

/*
 * Class:     sun_security_krb5_Credentials
 * Method:    acquireDefaultNativeCreds
370
 * Signature: ([I])Lsun/security/krb5/Credentials;
D
duke 已提交
371 372
 */
JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds(
373
        JNIEnv *env,
374 375
        jclass krbcredsClass,
        jintArray jetypes) {
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390

    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;
391
    int found_in_cache = 0;
392 393
    FILETIME Now, EndTime, LocalEndTime;

394 395 396
    int i, netypes;
    jint *etypes = NULL;

397
    while (TRUE) {
D
duke 已提交
398 399

        if (krbcredsConstructor == 0) {
400
            krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>",
401 402 403 404 405 406 407 408 409 410
                    "(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 已提交
411
            if (krbcredsConstructor == 0) {
412
                printf("LSA: Couldn't find sun.security.krb5.Credentials constructor\n");
D
duke 已提交
413 414 415 416
                break;
            }
        }

417
        if (native_debug) {
418 419
            printf("LSA: Found KrbCreds constructor\n");
        }
D
duke 已提交
420 421 422 423 424 425 426 427

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

428
        if (native_debug) {
429
            printf("LSA: Got handle to Kerberos package\n");
430
        }
D
duke 已提交
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446

        // 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
                        );

447
        if (native_debug) {
448 449
            printf("LSA: Response size is %d\n", rspSize);
        }
D
duke 已提交
450 451 452 453 454 455 456 457 458 459 460 461 462

        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);

463 464 465
        netypes = (*env)->GetArrayLength(env, jetypes);
        etypes = (jint *) (*env)->GetIntArrayElements(env, jetypes, NULL);

D
duke 已提交
466
        // check TGT validity
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
        if (native_debug) {
            printf("LSA: TICKET SessionKey KeyType is %d\n", msticket->SessionKey.KeyType);
        }

        if ((msticket->TicketFlags & KERB_TICKET_FLAGS_invalid) == 0) {
            GetSystemTimeAsFileTime(&Now);
            EndTime.dwLowDateTime = msticket->EndTime.LowPart;
            EndTime.dwHighDateTime = msticket->EndTime.HighPart;
            FileTimeToLocalFileTime(&EndTime, &LocalEndTime);
            if (CompareFileTime(&Now, &LocalEndTime) < 0) {
                for (i=0; i<netypes; i++) {
                    if (etypes[i] == msticket->SessionKey.KeyType) {
                        found_in_cache = 1;
                        if (native_debug) {
                            printf("LSA: Valid etype found: %d\n", etypes[i]);
                        }
                        break;
                    }
D
duke 已提交
485
                }
486
            }
D
duke 已提交
487 488
        }

489
        if (!found_in_cache) {
490
            if (native_debug) {
491
                printf("LSA: MS TGT in cache is invalid/not supported; request new ticket\n");
492
            }
D
duke 已提交
493 494 495 496 497 498 499 500 501 502 503 504

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

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

505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
            for (i=0; i<netypes; i++) {
                pTicketRequest->EncryptionType = etypes[i];
                Status = LsaCallAuthenticationPackage(
                            LogonHandle,
                            PackageId,
                            pTicketRequest,
                            requestSize,
                            &pTicketResponse,
                            &responseSize,
                            &SubStatus
                            );

                if (native_debug) {
                    printf("LSA: Response size is %d for %d\n", responseSize, etypes[i]);
                }
D
duke 已提交
520

521 522 523 524 525 526 527
                if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {
                    if (!LSA_SUCCESS(Status)) {
                        ShowNTError("LsaCallAuthenticationPackage", Status);
                    } else {
                        ShowNTError("Protocol status", SubStatus);
                    }
                    continue;
D
duke 已提交
528
                }
529 530 531

                // got the native MS Kerberos TGT
                msticket = &(pTicketResponse->Ticket);
D
duke 已提交
532 533
                break;
            }
534
        }
D
duke 已提交
535

536 537
        if (etypes != NULL) {
            (*env)->ReleaseIntArrayElements(env, jetypes, etypes, 0);
D
duke 已提交
538 539
        }

540
        /*
D
duke 已提交
541

542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
        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 已提交
586 587 588 589
        // Build a com.sun.security.krb5.Ticket
        ticket = BuildTicket(env, msticket->EncodedTicket,
                                msticket->EncodedTicketSize);
        if (ticket == NULL) {
590
            break;
D
duke 已提交
591 592 593 594 595
        }
        // OK, have a Ticket, now need to get the client name
        clientPrincipal = BuildPrincipal(env, msticket->ClientName,
                                msticket->TargetDomainName); // mdu
        if (clientPrincipal == NULL) {
596
            break;
D
duke 已提交
597 598 599 600 601 602
        }

        // and the "name" of tgt
        targetPrincipal = BuildPrincipal(env, msticket->ServiceName,
                        msticket->DomainName);
        if (targetPrincipal == NULL) {
603
            break;
D
duke 已提交
604 605 606 607 608
        }

        // Get the encryption key
        encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey));
        if (encryptionKey == NULL) {
609
            break;
D
duke 已提交
610 611 612 613 614
        }

        // and the ticket flags
        ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags));
        if (ticketFlags == NULL) {
615
            break;
D
duke 已提交
616 617 618 619 620
        }

        // Get the start time
        startTime = BuildKerberosTime(env, &(msticket->StartTime));
        if (startTime == NULL) {
621
            break;
D
duke 已提交
622 623 624 625 626 627 628 629 630 631 632 633
        }

        /*
         * 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) {
634
            break;
D
duke 已提交
635 636 637 638 639
        }

        // Get the renew till time
        renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil));
        if (renewTillTime == NULL) {
640
            break;
D
duke 已提交
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
        }

        // 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;
660
    } // end of WHILE. This WHILE will never loop.
D
duke 已提交
661

662 663 664 665 666 667 668 669 670 671
    // clean up resources
    if (TktCacheResponse != NULL) {
        LsaFreeReturnBuffer(TktCacheResponse);
    }
    if (pTicketRequest) {
        LocalFree(pTicketRequest);
    }
    if (pTicketResponse != NULL) {
        LsaFreeReturnBuffer(pTicketResponse);
    }
D
duke 已提交
672

673
    return krbCreds;
D
duke 已提交
674 675 676 677 678 679
}

static NTSTATUS
ConstructTicketRequest(UNICODE_STRING DomainName,
                PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize)
{
680 681 682 683 684 685
    NTSTATUS Status;
    UNICODE_STRING TargetPrefix;
    USHORT TargetSize;
    ULONG RequestSize;
    ULONG Length;
    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
D
duke 已提交
686

687 688
    *outRequest = NULL;
    *outSize = 0;
D
duke 已提交
689

690 691 692 693
    //
    // Set up the "krbtgt/" target prefix into a UNICODE_STRING so we
    // can easily concatenate it later.
    //
D
duke 已提交
694

695 696 697 698
    TargetPrefix.Buffer = L"krbtgt/";
    Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);
    TargetPrefix.Length = (USHORT)Length;
    TargetPrefix.MaximumLength = TargetPrefix.Length;
D
duke 已提交
699

700 701 702 703 704 705 706 707
    //
    // 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 已提交
708

709
    TargetSize = TargetPrefix.Length + DomainName.Length;
D
duke 已提交
710

711 712 713 714
    //
    // The ticket request buffer needs to be a single buffer.  That buffer
    // needs to include the buffer for the target name.
    //
D
duke 已提交
715

716
    RequestSize = sizeof (*pTicketRequest) + TargetSize;
D
duke 已提交
717

718 719 720
    //
    // Allocate the request buffer and make sure it's zero-filled.
    //
D
duke 已提交
721

722 723 724 725
    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)
                    LocalAlloc(LMEM_ZEROINIT, RequestSize);
    if (!pTicketRequest)
        return GetLastError();
D
duke 已提交
726

727
    //
728
    // Concatenate the target prefix with the previous response's
729 730
    // target domain.
    //
D
duke 已提交
731

732 733 734 735 736 737 738 739 740
    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 已提交
741 742 743 744 745 746 747 748 749
}

DWORD
ConcatenateUnicodeStrings(
    UNICODE_STRING *pTarget,
    UNICODE_STRING Source1,
    UNICODE_STRING Source2
    )
{
750 751 752 753 754
    //
    // The buffers for Source1 and Source2 cannot overlap pTarget's
    // buffer.  Source1.Length + Source2.Length must be <= 0xFFFF,
    // otherwise we overflow...
    //
D
duke 已提交
755

756 757
    USHORT TotalSize = Source1.Length + Source2.Length;
    PBYTE buffer = (PBYTE) pTarget->Buffer;
D
duke 已提交
758

759 760
    if (TotalSize > pTarget->MaximumLength)
        return ERROR_INSUFFICIENT_BUFFER;
D
duke 已提交
761

762 763 764 765
    pTarget->Length = TotalSize;
    memcpy(buffer, Source1.Buffer, Source1.Length);
    memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);
    return ERROR_SUCCESS;
D
duke 已提交
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
}

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
        )
{
813 814 815 816 817
    #define MAX_MSG_SIZE 256

    static WCHAR szMsgBuf[MAX_MSG_SIZE];
    DWORD dwRes;

818
    if (native_debug) {
819 820
        printf("LSA: Error calling function %s: %lu\n", szAPI, dwError);
    }
821 822 823 824 825 826 827 828 829

    dwRes = FormatMessage (
            FORMAT_MESSAGE_FROM_SYSTEM,
            NULL,
            dwError,
            0,
            szMsgBuf,
            MAX_MSG_SIZE,
            NULL);
830
    if (native_debug) {
831 832 833 834 835 836
        if (0 == dwRes) {
            printf("LSA: FormatMessage failed with %d\n", GetLastError());
            // ExitProcess(EXIT_FAILURE);
        } else {
            printf("LSA: %S",szMsgBuf);
        }
837
    }
D
duke 已提交
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
}

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));
865
    }
D
duke 已提交
866 867 868
    else {
        DestinationString->MaximumLength = 0;
        DestinationString->Length = 0;
869
    }
D
duke 已提交
870 871 872 873
}

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

874 875 876
    /* 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 已提交
877

878 879
    jobject derValue, ticket;
    jbyteArray ary;
D
duke 已提交
880

881 882 883 884
    ary = (*env)->NewByteArray(env,encodedTicketSize);
    if ((*env)->ExceptionOccurred(env)) {
        return (jobject) NULL;
    }
D
duke 已提交
885

886 887 888 889 890 891
    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize,
                                    (jbyte *)encodedTicket);
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->DeleteLocalRef(env, ary);
        return (jobject) NULL;
    }
D
duke 已提交
892

893 894
    derValue = (*env)->NewObject(env, derValueClass, derValueConstructor, ary);
    if ((*env)->ExceptionOccurred(env)) {
D
duke 已提交
895
        (*env)->DeleteLocalRef(env, ary);
896 897 898 899 900 901
        return (jobject) NULL;
    }

    (*env)->DeleteLocalRef(env, ary);
    ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, derValue);
    if ((*env)->ExceptionOccurred(env)) {
D
duke 已提交
902
        (*env)->DeleteLocalRef(env, derValue);
903 904 905 906
        return (jobject) NULL;
    }
    (*env)->DeleteLocalRef(env, derValue);
    return ticket;
D
duke 已提交
907 908 909 910 911 912
}

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

913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
    /*
     * 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));

930
    if (native_debug) {
931 932 933 934
        printf("LSA: Principal domain is %S\n", realm);
        printf("LSA: Name type is %x\n", principalName->NameType);
        printf("LSA: Name count is %x\n", principalName->NameCount);
    }
935 936 937 938 939

    nameCount = principalName->NameCount;
    stringArray = (*env)->NewObjectArray(env, nameCount,
                            javaLangStringClass, NULL);
    if (stringArray == NULL) {
940
        if (native_debug) {
941 942
            printf("LSA: Can't allocate String array for Principal\n");
        }
943 944 945
        LocalFree(realm);
        return principal;
    }
D
duke 已提交
946

947 948 949
    for (i=0; i<nameCount; i++) {
        // get the principal name
        scanner = &(principalName->Names[i]);
D
duke 已提交
950

951 952 953 954 955
        // 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 已提交
956

957 958 959 960 961
        // Do I have to worry about storage reclamation here?
    }
    // now set the realm in the principal
    realmLen = (ULONG)wcslen((PWCHAR)realm);
    realmStr = (*env)->NewString(env, (PWCHAR)realm, (USHORT)realmLen);
962 963 964

    principal = (*env)->NewObject(env, principalNameClass,
                    principalNameConstructor, stringArray, realmStr);
D
duke 已提交
965

966 967
    // free local resources
    LocalFree(realm);
D
duke 已提交
968

969
    return principal;
D
duke 已提交
970 971 972
}

jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) {
973 974 975
    // First, need to build a byte array
    jbyteArray ary;
    jobject encryptionKey = NULL;
976 977 978 979 980 981
    unsigned int i;

    for (i=0; i<cryptoKey->Length; i++) {
        if (cryptoKey->Value[i]) break;
    }
    if (i == cryptoKey->Length) {
982
        if (native_debug) {
983 984 985 986
            printf("LSA: Session key all zero. Stop.\n");
        }
        return NULL;
    }
987 988 989 990 991 992 993 994 995 996

    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 已提交
997

998
    return encryptionKey;
D
duke 已提交
999 1000 1001
}

jobject BuildTicketFlags(JNIEnv *env, PULONG flags) {
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
    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 已提交
1019

1020
    return ticketFlags;
D
duke 已提交
1021 1022 1023
}

jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) {
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
    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.
1038 1039 1040 1041 1042 1043
        swprintf( (wchar_t *)month, 3, L"%2.2d", systemTime.wMonth);
        swprintf( (wchar_t *)day, 3, L"%2.2d", systemTime.wDay);
        swprintf( (wchar_t *)hour, 3, L"%2.2d", systemTime.wHour);
        swprintf( (wchar_t *)minute, 3, L"%2.2d", systemTime.wMinute);
        swprintf( (wchar_t *)second, 3, L"%2.2d", systemTime.wSecond);
        swprintf( (wchar_t *)timeString, 16,
1044
                L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",
D
duke 已提交
1045 1046 1047 1048 1049 1050
                systemTime.wYear,
                month,
                day,
                hour,
                minute,
                second );
1051
        if (native_debug) {
1052
            printf("LSA: %S\n", (wchar_t *)timeString);
1053
        }
1054 1055 1056 1057 1058
        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 已提交
1059
        }
1060 1061
    }
    return kerberosTime;
D
duke 已提交
1062
}