NativeCreds.c 32.2 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2000, 2013, 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 = 0;
392
    FILETIME Now, EndTime;
393

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

466 467 468 469
        if (etypes == NULL) {
            break;
        }

D
duke 已提交
470
        // check TGT validity
471 472 473 474 475 476 477 478
        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;
479
            if (CompareFileTime(&Now, &EndTime) < 0) {
480 481
                for (i=0; i<netypes; i++) {
                    if (etypes[i] == msticket->SessionKey.KeyType) {
482
                        found = 1;
483 484 485 486 487
                        if (native_debug) {
                            printf("LSA: Valid etype found: %d\n", etypes[i]);
                        }
                        break;
                    }
D
duke 已提交
488
                }
489
            }
D
duke 已提交
490 491
        }

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

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

508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
            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 已提交
523

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

                // got the native MS Kerberos TGT
                msticket = &(pTicketResponse->Ticket);
535 536 537 538 539 540 541 542

                if (msticket->SessionKey.KeyType != etypes[i]) {
                    if (native_debug) {
                        printf("LSA: Response etype is %d for %d. Retry.\n", msticket->SessionKey.KeyType, etypes[i]);
                    }
                    continue;
                }
                found = 1;
D
duke 已提交
543 544
                break;
            }
545
        }
D
duke 已提交
546

547 548
        if (etypes != NULL) {
            (*env)->ReleaseIntArrayElements(env, jetypes, etypes, 0);
D
duke 已提交
549 550
        }

551
        /*
D
duke 已提交
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 586 587 588 589 590 591 592 593 594 595 596
        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;

        */
597 598 599 600
        if (!found) {
            break;
        }

D
duke 已提交
601 602 603 604
        // Build a com.sun.security.krb5.Ticket
        ticket = BuildTicket(env, msticket->EncodedTicket,
                                msticket->EncodedTicketSize);
        if (ticket == NULL) {
605
            break;
D
duke 已提交
606 607 608 609 610
        }
        // OK, have a Ticket, now need to get the client name
        clientPrincipal = BuildPrincipal(env, msticket->ClientName,
                                msticket->TargetDomainName); // mdu
        if (clientPrincipal == NULL) {
611
            break;
D
duke 已提交
612 613 614 615 616 617
        }

        // and the "name" of tgt
        targetPrincipal = BuildPrincipal(env, msticket->ServiceName,
                        msticket->DomainName);
        if (targetPrincipal == NULL) {
618
            break;
D
duke 已提交
619 620 621 622 623
        }

        // Get the encryption key
        encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey));
        if (encryptionKey == NULL) {
624
            break;
D
duke 已提交
625 626 627 628 629
        }

        // and the ticket flags
        ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags));
        if (ticketFlags == NULL) {
630
            break;
D
duke 已提交
631 632 633 634 635
        }

        // Get the start time
        startTime = BuildKerberosTime(env, &(msticket->StartTime));
        if (startTime == NULL) {
636
            break;
D
duke 已提交
637 638 639 640 641 642 643 644 645 646 647 648
        }

        /*
         * 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) {
649
            break;
D
duke 已提交
650 651 652 653 654
        }

        // Get the renew till time
        renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil));
        if (renewTillTime == NULL) {
655
            break;
D
duke 已提交
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
        }

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

677 678 679 680 681 682 683 684 685 686
    // clean up resources
    if (TktCacheResponse != NULL) {
        LsaFreeReturnBuffer(TktCacheResponse);
    }
    if (pTicketRequest) {
        LocalFree(pTicketRequest);
    }
    if (pTicketResponse != NULL) {
        LsaFreeReturnBuffer(pTicketResponse);
    }
D
duke 已提交
687

688
    return krbCreds;
D
duke 已提交
689 690 691 692 693 694
}

static NTSTATUS
ConstructTicketRequest(UNICODE_STRING DomainName,
                PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize)
{
695 696 697 698 699 700
    NTSTATUS Status;
    UNICODE_STRING TargetPrefix;
    USHORT TargetSize;
    ULONG RequestSize;
    ULONG Length;
    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
D
duke 已提交
701

702 703
    *outRequest = NULL;
    *outSize = 0;
D
duke 已提交
704

705 706 707 708
    //
    // Set up the "krbtgt/" target prefix into a UNICODE_STRING so we
    // can easily concatenate it later.
    //
D
duke 已提交
709

710 711 712 713
    TargetPrefix.Buffer = L"krbtgt/";
    Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);
    TargetPrefix.Length = (USHORT)Length;
    TargetPrefix.MaximumLength = TargetPrefix.Length;
D
duke 已提交
714

715 716 717 718 719 720 721 722
    //
    // 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 已提交
723

724
    TargetSize = TargetPrefix.Length + DomainName.Length;
D
duke 已提交
725

726 727 728 729
    //
    // The ticket request buffer needs to be a single buffer.  That buffer
    // needs to include the buffer for the target name.
    //
D
duke 已提交
730

731
    RequestSize = sizeof (*pTicketRequest) + TargetSize;
D
duke 已提交
732

733 734 735
    //
    // Allocate the request buffer and make sure it's zero-filled.
    //
D
duke 已提交
736

737 738 739 740
    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)
                    LocalAlloc(LMEM_ZEROINIT, RequestSize);
    if (!pTicketRequest)
        return GetLastError();
D
duke 已提交
741

742
    //
743
    // Concatenate the target prefix with the previous response's
744 745
    // target domain.
    //
D
duke 已提交
746

747 748 749 750 751 752 753 754 755
    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 已提交
756 757 758 759 760 761 762 763 764
}

DWORD
ConcatenateUnicodeStrings(
    UNICODE_STRING *pTarget,
    UNICODE_STRING Source1,
    UNICODE_STRING Source2
    )
{
765 766 767 768 769
    //
    // The buffers for Source1 and Source2 cannot overlap pTarget's
    // buffer.  Source1.Length + Source2.Length must be <= 0xFFFF,
    // otherwise we overflow...
    //
D
duke 已提交
770

771 772
    USHORT TotalSize = Source1.Length + Source2.Length;
    PBYTE buffer = (PBYTE) pTarget->Buffer;
D
duke 已提交
773

774 775
    if (TotalSize > pTarget->MaximumLength)
        return ERROR_INSUFFICIENT_BUFFER;
D
duke 已提交
776

777 778 779 780
    pTarget->Length = TotalSize;
    memcpy(buffer, Source1.Buffer, Source1.Length);
    memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);
    return ERROR_SUCCESS;
D
duke 已提交
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 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
}

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
        )
{
828 829 830 831 832
    #define MAX_MSG_SIZE 256

    static WCHAR szMsgBuf[MAX_MSG_SIZE];
    DWORD dwRes;

833
    if (native_debug) {
834 835
        printf("LSA: Error calling function %s: %lu\n", szAPI, dwError);
    }
836 837 838 839 840 841 842 843 844

    dwRes = FormatMessage (
            FORMAT_MESSAGE_FROM_SYSTEM,
            NULL,
            dwError,
            0,
            szMsgBuf,
            MAX_MSG_SIZE,
            NULL);
845
    if (native_debug) {
846 847 848 849 850 851
        if (0 == dwRes) {
            printf("LSA: FormatMessage failed with %d\n", GetLastError());
            // ExitProcess(EXIT_FAILURE);
        } else {
            printf("LSA: %S",szMsgBuf);
        }
852
    }
D
duke 已提交
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
}

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));
880
    }
D
duke 已提交
881 882 883
    else {
        DestinationString->MaximumLength = 0;
        DestinationString->Length = 0;
884
    }
D
duke 已提交
885 886 887 888
}

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

889 890 891
    /* 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 已提交
892

893 894
    jobject derValue, ticket;
    jbyteArray ary;
D
duke 已提交
895

896 897 898 899
    ary = (*env)->NewByteArray(env,encodedTicketSize);
    if ((*env)->ExceptionOccurred(env)) {
        return (jobject) NULL;
    }
D
duke 已提交
900

901 902 903 904 905 906
    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize,
                                    (jbyte *)encodedTicket);
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->DeleteLocalRef(env, ary);
        return (jobject) NULL;
    }
D
duke 已提交
907

908 909
    derValue = (*env)->NewObject(env, derValueClass, derValueConstructor, ary);
    if ((*env)->ExceptionOccurred(env)) {
D
duke 已提交
910
        (*env)->DeleteLocalRef(env, ary);
911 912 913 914 915 916
        return (jobject) NULL;
    }

    (*env)->DeleteLocalRef(env, ary);
    ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, derValue);
    if ((*env)->ExceptionOccurred(env)) {
D
duke 已提交
917
        (*env)->DeleteLocalRef(env, derValue);
918 919 920 921
        return (jobject) NULL;
    }
    (*env)->DeleteLocalRef(env, derValue);
    return ticket;
D
duke 已提交
922 923 924 925 926 927
}

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

928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
    /*
     * 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));

945
    if (native_debug) {
946 947 948 949
        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);
    }
950 951 952 953 954

    nameCount = principalName->NameCount;
    stringArray = (*env)->NewObjectArray(env, nameCount,
                            javaLangStringClass, NULL);
    if (stringArray == NULL) {
955
        if (native_debug) {
956 957
            printf("LSA: Can't allocate String array for Principal\n");
        }
958
        goto cleanup;
959
    }
D
duke 已提交
960

961 962 963
    for (i=0; i<nameCount; i++) {
        // get the principal name
        scanner = &(principalName->Names[i]);
D
duke 已提交
964

965 966 967
        // OK, got a Char array, so construct a String
        tempString = (*env)->NewString(env, (const jchar*)scanner->Buffer,
                            scanner->Length/sizeof(WCHAR));
968 969 970 971 972

        if (tempString == NULL) {
            goto cleanup;
        }

973 974
        // Set the String into the StringArray
        (*env)->SetObjectArrayElement(env, stringArray, i, tempString);
D
duke 已提交
975

976 977 978 979
        if ((*env)->ExceptionCheck(env)) {
            goto cleanup;
        }

980 981 982 983 984
        // 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);
985

986 987 988 989
    if (realmStr == NULL) {
        goto cleanup;
    }

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

993
cleanup:
994 995
    // free local resources
    LocalFree(realm);
D
duke 已提交
996

997
    return principal;
D
duke 已提交
998 999 1000
}

jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) {
1001 1002 1003
    // First, need to build a byte array
    jbyteArray ary;
    jobject encryptionKey = NULL;
1004 1005 1006 1007 1008 1009
    unsigned int i;

    for (i=0; i<cryptoKey->Length; i++) {
        if (cryptoKey->Value[i]) break;
    }
    if (i == cryptoKey->Length) {
1010
        if (native_debug) {
1011 1012 1013 1014
            printf("LSA: Session key all zero. Stop.\n");
        }
        return NULL;
    }
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024

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

1026
    return encryptionKey;
D
duke 已提交
1027 1028 1029
}

jobject BuildTicketFlags(JNIEnv *env, PULONG flags) {
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
    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 已提交
1047

1048
    return ticketFlags;
D
duke 已提交
1049 1050 1051
}

jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) {
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
    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.
1066 1067 1068 1069 1070 1071
        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,
1072
                L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",
D
duke 已提交
1073 1074 1075 1076 1077 1078
                systemTime.wYear,
                month,
                day,
                hour,
                minute,
                second );
1079
        if (native_debug) {
1080
            printf("LSA: %S\n", (wchar_t *)timeString);
1081
        }
1082 1083 1084 1085 1086
        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 已提交
1087
        }
1088 1089
    }
    return kerberosTime;
D
duke 已提交
1090
}