NativeCreds.c 31.2 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 370 371 372
}

/*
 * Class:     sun_security_krb5_Credentials
 * Method:    acquireDefaultNativeCreds
 * Signature: ()Lsun/security/krb5/Credentials;
 */
JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds(
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
        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 已提交
394 395

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

413
        if (native_debug) {
414 415
            printf("LSA: Found KrbCreds constructor\n");
        }
D
duke 已提交
416 417 418 419 420 421 422 423

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

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

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

443
        if (native_debug) {
444 445
            printf("LSA: Response size is %d\n", rspSize);
        }
D
duke 已提交
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

        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) {
484
            if (native_debug) {
485
                printf("LSA: MS TGT in cache is invalid/not supported; request new ticket\n");
486
            }
D
duke 已提交
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509

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

510
            if (native_debug) {
511
                printf("LSA: Response size is %d\n", responseSize);
512
            }
D
duke 已提交
513 514 515 516 517 518 519 520 521 522 523 524 525 526

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

527
        /*
D
duke 已提交
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 559 560 561 562 563 564 565 566 567 568 569 570 571 572
        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 已提交
573 574 575 576
        // Build a com.sun.security.krb5.Ticket
        ticket = BuildTicket(env, msticket->EncodedTicket,
                                msticket->EncodedTicketSize);
        if (ticket == NULL) {
577
            break;
D
duke 已提交
578 579 580 581 582
        }
        // OK, have a Ticket, now need to get the client name
        clientPrincipal = BuildPrincipal(env, msticket->ClientName,
                                msticket->TargetDomainName); // mdu
        if (clientPrincipal == NULL) {
583
            break;
D
duke 已提交
584 585 586 587 588 589
        }

        // and the "name" of tgt
        targetPrincipal = BuildPrincipal(env, msticket->ServiceName,
                        msticket->DomainName);
        if (targetPrincipal == NULL) {
590
            break;
D
duke 已提交
591 592 593 594 595
        }

        // Get the encryption key
        encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey));
        if (encryptionKey == NULL) {
596
            break;
D
duke 已提交
597 598 599 600 601
        }

        // and the ticket flags
        ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags));
        if (ticketFlags == NULL) {
602
            break;
D
duke 已提交
603 604 605 606 607
        }

        // Get the start time
        startTime = BuildKerberosTime(env, &(msticket->StartTime));
        if (startTime == NULL) {
608
            break;
D
duke 已提交
609 610 611 612 613 614 615 616 617 618 619 620
        }

        /*
         * 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) {
621
            break;
D
duke 已提交
622 623 624 625 626
        }

        // Get the renew till time
        renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil));
        if (renewTillTime == NULL) {
627
            break;
D
duke 已提交
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
        }

        // 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;
647
    } // end of WHILE
D
duke 已提交
648

649 650 651 652 653 654 655 656 657 658
    // clean up resources
    if (TktCacheResponse != NULL) {
        LsaFreeReturnBuffer(TktCacheResponse);
    }
    if (pTicketRequest) {
        LocalFree(pTicketRequest);
    }
    if (pTicketResponse != NULL) {
        LsaFreeReturnBuffer(pTicketResponse);
    }
D
duke 已提交
659

660
    return krbCreds;
D
duke 已提交
661 662 663 664 665 666
}

static NTSTATUS
ConstructTicketRequest(UNICODE_STRING DomainName,
                PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize)
{
667 668 669 670 671 672
    NTSTATUS Status;
    UNICODE_STRING TargetPrefix;
    USHORT TargetSize;
    ULONG RequestSize;
    ULONG Length;
    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
D
duke 已提交
673

674 675
    *outRequest = NULL;
    *outSize = 0;
D
duke 已提交
676

677 678 679 680
    //
    // Set up the "krbtgt/" target prefix into a UNICODE_STRING so we
    // can easily concatenate it later.
    //
D
duke 已提交
681

682 683 684 685
    TargetPrefix.Buffer = L"krbtgt/";
    Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);
    TargetPrefix.Length = (USHORT)Length;
    TargetPrefix.MaximumLength = TargetPrefix.Length;
D
duke 已提交
686

687 688 689 690 691 692 693 694
    //
    // 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 已提交
695

696
    TargetSize = TargetPrefix.Length + DomainName.Length;
D
duke 已提交
697

698 699 700 701
    //
    // The ticket request buffer needs to be a single buffer.  That buffer
    // needs to include the buffer for the target name.
    //
D
duke 已提交
702

703
    RequestSize = sizeof (*pTicketRequest) + TargetSize;
D
duke 已提交
704

705 706 707
    //
    // Allocate the request buffer and make sure it's zero-filled.
    //
D
duke 已提交
708

709 710 711 712
    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)
                    LocalAlloc(LMEM_ZEROINIT, RequestSize);
    if (!pTicketRequest)
        return GetLastError();
D
duke 已提交
713

714 715 716 717
    //
    // Concatenate the target prefix with the previous reponse's
    // target domain.
    //
D
duke 已提交
718

719 720 721 722 723 724 725 726 727
    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 已提交
728 729 730 731 732 733 734 735 736
}

DWORD
ConcatenateUnicodeStrings(
    UNICODE_STRING *pTarget,
    UNICODE_STRING Source1,
    UNICODE_STRING Source2
    )
{
737 738 739 740 741
    //
    // The buffers for Source1 and Source2 cannot overlap pTarget's
    // buffer.  Source1.Length + Source2.Length must be <= 0xFFFF,
    // otherwise we overflow...
    //
D
duke 已提交
742

743 744
    USHORT TotalSize = Source1.Length + Source2.Length;
    PBYTE buffer = (PBYTE) pTarget->Buffer;
D
duke 已提交
745

746 747
    if (TotalSize > pTarget->MaximumLength)
        return ERROR_INSUFFICIENT_BUFFER;
D
duke 已提交
748

749 750 751 752
    pTarget->Length = TotalSize;
    memcpy(buffer, Source1.Buffer, Source1.Length);
    memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);
    return ERROR_SUCCESS;
D
duke 已提交
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 786 787 788 789 790 791 792 793 794 795 796 797 798 799
}

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
        )
{
800 801 802 803 804
    #define MAX_MSG_SIZE 256

    static WCHAR szMsgBuf[MAX_MSG_SIZE];
    DWORD dwRes;

805
    if (native_debug) {
806 807
        printf("LSA: Error calling function %s: %lu\n", szAPI, dwError);
    }
808 809 810 811 812 813 814 815 816

    dwRes = FormatMessage (
            FORMAT_MESSAGE_FROM_SYSTEM,
            NULL,
            dwError,
            0,
            szMsgBuf,
            MAX_MSG_SIZE,
            NULL);
817
    if (native_debug) {
818 819 820 821 822 823
        if (0 == dwRes) {
            printf("LSA: FormatMessage failed with %d\n", GetLastError());
            // ExitProcess(EXIT_FAILURE);
        } else {
            printf("LSA: %S",szMsgBuf);
        }
824
    }
D
duke 已提交
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
}

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));
852
    }
D
duke 已提交
853 854 855
    else {
        DestinationString->MaximumLength = 0;
        DestinationString->Length = 0;
856
    }
D
duke 已提交
857 858 859 860
}

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

861 862 863
    /* 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 已提交
864

865 866
    jobject derValue, ticket;
    jbyteArray ary;
D
duke 已提交
867

868 869 870 871
    ary = (*env)->NewByteArray(env,encodedTicketSize);
    if ((*env)->ExceptionOccurred(env)) {
        return (jobject) NULL;
    }
D
duke 已提交
872

873 874 875 876 877 878
    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize,
                                    (jbyte *)encodedTicket);
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->DeleteLocalRef(env, ary);
        return (jobject) NULL;
    }
D
duke 已提交
879

880 881
    derValue = (*env)->NewObject(env, derValueClass, derValueConstructor, ary);
    if ((*env)->ExceptionOccurred(env)) {
D
duke 已提交
882
        (*env)->DeleteLocalRef(env, ary);
883 884 885 886 887 888
        return (jobject) NULL;
    }

    (*env)->DeleteLocalRef(env, ary);
    ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, derValue);
    if ((*env)->ExceptionOccurred(env)) {
D
duke 已提交
889
        (*env)->DeleteLocalRef(env, derValue);
890 891 892 893
        return (jobject) NULL;
    }
    (*env)->DeleteLocalRef(env, derValue);
    return ticket;
D
duke 已提交
894 895 896 897 898 899
}

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

900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
    /*
     * 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));

917
    if (native_debug) {
918 919 920 921
        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);
    }
922 923 924 925 926

    nameCount = principalName->NameCount;
    stringArray = (*env)->NewObjectArray(env, nameCount,
                            javaLangStringClass, NULL);
    if (stringArray == NULL) {
927
        if (native_debug) {
928 929
            printf("LSA: Can't allocate String array for Principal\n");
        }
930 931 932
        LocalFree(realm);
        return principal;
    }
D
duke 已提交
933

934 935 936
    for (i=0; i<nameCount; i++) {
        // get the principal name
        scanner = &(principalName->Names[i]);
D
duke 已提交
937

938 939 940 941 942
        // 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 已提交
943

944 945 946 947 948
        // 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);
949 950 951

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

953 954
    // free local resources
    LocalFree(realm);
D
duke 已提交
955

956
    return principal;
D
duke 已提交
957 958 959
}

jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) {
960 961 962
    // First, need to build a byte array
    jbyteArray ary;
    jobject encryptionKey = NULL;
963 964 965 966 967 968
    unsigned int i;

    for (i=0; i<cryptoKey->Length; i++) {
        if (cryptoKey->Value[i]) break;
    }
    if (i == cryptoKey->Length) {
969
        if (native_debug) {
970 971 972 973
            printf("LSA: Session key all zero. Stop.\n");
        }
        return NULL;
    }
974 975 976 977 978 979 980 981 982 983

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

985
    return encryptionKey;
D
duke 已提交
986 987 988
}

jobject BuildTicketFlags(JNIEnv *env, PULONG flags) {
989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
    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 已提交
1006

1007
    return ticketFlags;
D
duke 已提交
1008 1009 1010
}

jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) {
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
    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.
1025 1026 1027 1028 1029 1030
        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,
1031
                L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",
D
duke 已提交
1032 1033 1034 1035 1036 1037
                systemTime.wYear,
                month,
                day,
                hour,
                minute,
                second );
1038
        if (native_debug) {
1039
            printf("LSA: %S\n", (wchar_t *)timeString);
1040
        }
1041 1042 1043 1044 1045
        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 已提交
1046
        }
1047 1048
    }
    return kerberosTime;
D
duke 已提交
1049
}