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

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

#define UNICODE
#define _UNICODE

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

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

/*
 * Library-wide static references
 */

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

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

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

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(
92
    PUNICODE_STRING DestinationString,
D
duke 已提交
93
    PCWSTR SourceString OPTIONAL
94
);
D
duke 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

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(
112 113
        JavaVM  *jvm,
        void    *reserved) {
D
duke 已提交
114

115 116
    jclass cls;
    JNIEnv *env;
117
    jfieldID fldDEBUG;
D
duke 已提交
118

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

123 124 125 126 127 128 129 130 131 132 133 134
    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;
    }
    DEBUG = (*env)->GetStaticBooleanField(env, cls, fldDEBUG);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

329 330 331
    if (DEBUG) {
        printf("LSA: Finished OnLoad processing\n");
    } /* DEBUG */
D
duke 已提交
332

333
    return JNI_VERSION_1_2;
D
duke 已提交
334 335 336 337 338 339 340 341
}

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

JNIEXPORT void JNICALL JNI_OnUnload(
342 343
        JavaVM  *jvm,
        void    *reserved) {
D
duke 已提交
344

345
    JNIEnv *env;
D
duke 已提交
346

347 348 349
    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
        return; /* Nothing else we can do */
    }
D
duke 已提交
350

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
    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 已提交
372

373
    return;
D
duke 已提交
374 375 376 377 378 379 380 381
}

/*
 * Class:     sun_security_krb5_Credentials
 * Method:    acquireDefaultNativeCreds
 * Signature: ()Lsun/security/krb5/Credentials;
 */
JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds(
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
        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 已提交
403 404

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

422 423 424
        if (DEBUG) {
            printf("LSA: Found KrbCreds constructor\n");
        }
D
duke 已提交
425 426 427 428 429 430 431 432

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

433 434 435
        if (DEBUG) {
            printf("LSA: Got handle to Kerberos package\n");
        } /* DEBUG */
D
duke 已提交
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451

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

452 453 454
        if (DEBUG) {
            printf("LSA: Response size is %d\n", rspSize);
        }
D
duke 已提交
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492

        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) {
493 494 495
            if (DEBUG) {
                printf("LSA: MS TGT in cache is invalid/not supported; request new ticket\n");
            } /* DEBUG */
D
duke 已提交
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518

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

519 520 521
            if (DEBUG) {
                printf("LSA: Response size is %d\n", responseSize);
            } /* DEBUG */
D
duke 已提交
522 523 524 525 526 527 528 529 530 531 532 533 534 535

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

536
        /*
D
duke 已提交
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 573 574 575 576 577 578 579 580 581
        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 已提交
582 583 584 585
        // Build a com.sun.security.krb5.Ticket
        ticket = BuildTicket(env, msticket->EncodedTicket,
                                msticket->EncodedTicketSize);
        if (ticket == NULL) {
586
            break;
D
duke 已提交
587 588 589 590 591
        }
        // OK, have a Ticket, now need to get the client name
        clientPrincipal = BuildPrincipal(env, msticket->ClientName,
                                msticket->TargetDomainName); // mdu
        if (clientPrincipal == NULL) {
592
            break;
D
duke 已提交
593 594 595 596 597 598
        }

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

        // Get the encryption key
        encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey));
        if (encryptionKey == NULL) {
605
            break;
D
duke 已提交
606 607 608 609 610
        }

        // and the ticket flags
        ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags));
        if (ticketFlags == NULL) {
611
            break;
D
duke 已提交
612 613 614 615 616
        }

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

        /*
         * 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) {
630
            break;
D
duke 已提交
631 632 633 634 635
        }

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

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

658 659 660 661 662 663 664 665 666 667
    // clean up resources
    if (TktCacheResponse != NULL) {
        LsaFreeReturnBuffer(TktCacheResponse);
    }
    if (pTicketRequest) {
        LocalFree(pTicketRequest);
    }
    if (pTicketResponse != NULL) {
        LsaFreeReturnBuffer(pTicketResponse);
    }
D
duke 已提交
668

669
    return krbCreds;
D
duke 已提交
670 671 672 673 674 675
}

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

683 684
    *outRequest = NULL;
    *outSize = 0;
D
duke 已提交
685

686 687 688 689
    //
    // Set up the "krbtgt/" target prefix into a UNICODE_STRING so we
    // can easily concatenate it later.
    //
D
duke 已提交
690

691 692 693 694
    TargetPrefix.Buffer = L"krbtgt/";
    Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);
    TargetPrefix.Length = (USHORT)Length;
    TargetPrefix.MaximumLength = TargetPrefix.Length;
D
duke 已提交
695

696 697 698 699 700 701 702 703
    //
    // 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 已提交
704

705
    TargetSize = TargetPrefix.Length + DomainName.Length;
D
duke 已提交
706

707 708 709 710
    //
    // The ticket request buffer needs to be a single buffer.  That buffer
    // needs to include the buffer for the target name.
    //
D
duke 已提交
711

712
    RequestSize = sizeof (*pTicketRequest) + TargetSize;
D
duke 已提交
713

714 715 716
    //
    // Allocate the request buffer and make sure it's zero-filled.
    //
D
duke 已提交
717

718 719 720 721
    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)
                    LocalAlloc(LMEM_ZEROINIT, RequestSize);
    if (!pTicketRequest)
        return GetLastError();
D
duke 已提交
722

723 724 725 726
    //
    // Concatenate the target prefix with the previous reponse's
    // target domain.
    //
D
duke 已提交
727

728 729 730 731 732 733 734 735 736
    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 已提交
737 738 739 740 741 742 743 744 745
}

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

752 753
    USHORT TotalSize = Source1.Length + Source2.Length;
    PBYTE buffer = (PBYTE) pTarget->Buffer;
D
duke 已提交
754

755 756
    if (TotalSize > pTarget->MaximumLength)
        return ERROR_INSUFFICIENT_BUFFER;
D
duke 已提交
757

758 759 760 761
    pTarget->Length = TotalSize;
    memcpy(buffer, Source1.Buffer, Source1.Length);
    memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);
    return ERROR_SUCCESS;
D
duke 已提交
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 800 801 802 803 804 805 806 807 808
}

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
        )
{
809 810 811 812 813
    #define MAX_MSG_SIZE 256

    static WCHAR szMsgBuf[MAX_MSG_SIZE];
    DWORD dwRes;

814 815 816
    if (DEBUG) {
        printf("LSA: Error calling function %s: %lu\n", szAPI, dwError);
    }
817 818 819 820 821 822 823 824 825

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

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));
861
    }
D
duke 已提交
862 863 864
    else {
        DestinationString->MaximumLength = 0;
        DestinationString->Length = 0;
865
    }
D
duke 已提交
866 867 868 869
}

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

870 871 872
    /* 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 已提交
873

874 875
    jobject derValue, ticket;
    jbyteArray ary;
D
duke 已提交
876

877 878 879 880
    ary = (*env)->NewByteArray(env,encodedTicketSize);
    if ((*env)->ExceptionOccurred(env)) {
        return (jobject) NULL;
    }
D
duke 已提交
881

882 883 884 885 886 887
    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize,
                                    (jbyte *)encodedTicket);
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->DeleteLocalRef(env, ary);
        return (jobject) NULL;
    }
D
duke 已提交
888

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

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

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

909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
    /*
     * 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));

926 927 928 929 930
    if (DEBUG) {
        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);
    }
931 932 933 934 935

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

943 944 945
    for (i=0; i<nameCount; i++) {
        // get the principal name
        scanner = &(principalName->Names[i]);
D
duke 已提交
946

947 948 949 950 951
        // 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 已提交
952

953 954 955 956
        // Do I have to worry about storage reclamation here?
    }
    principal = (*env)->NewObject(env, principalNameClass,
                    principalNameConstructor, stringArray);
D
duke 已提交
957

958 959 960 961
    // now set the realm in the principal
    realmLen = (ULONG)wcslen((PWCHAR)realm);
    realmStr = (*env)->NewString(env, (PWCHAR)realm, (USHORT)realmLen);
    (*env)->CallVoidMethod(env, principal, setRealmMethod, realmStr);
D
duke 已提交
962

963 964
    // free local resources
    LocalFree(realm);
D
duke 已提交
965

966
    return principal;
D
duke 已提交
967 968 969
}

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

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

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

995
    return encryptionKey;
D
duke 已提交
996 997 998
}

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

1017
    return ticketFlags;
D
duke 已提交
1018 1019 1020
}

jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) {
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
    jobject kerberosTime = NULL;
    jstring stringTime = NULL;
    SYSTEMTIME systemTime;
    WCHAR timeString[16];
    WCHAR month[3];
    WCHAR day[3];
    WCHAR hour[3];
    WCHAR minute[3];
    WCHAR second[3];

    if (FileTimeToSystemTime((FILETIME *)kerbtime, &systemTime)) {
        // XXX Cannot use %02.2ld, because the leading 0 is ignored for integers.
        // So, print them to strings, and then print them to the master string with a
        // format pattern that makes it two digits and prefix with a 0 if necessary.
        swprintf( (wchar_t *)month, L"%2.2d", systemTime.wMonth);
        swprintf( (wchar_t *)day, L"%2.2d", systemTime.wDay);
        swprintf( (wchar_t *)hour, L"%2.2d", systemTime.wHour);
        swprintf( (wchar_t *)minute, L"%2.2d", systemTime.wMinute);
        swprintf( (wchar_t *)second, L"%2.2d", systemTime.wSecond);
        swprintf( (wchar_t *)timeString,
                L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",
D
duke 已提交
1042 1043 1044 1045 1046 1047
                systemTime.wYear,
                month,
                day,
                hour,
                minute,
                second );
1048 1049 1050
        if (DEBUG) {
            printf("LSA: %S\n", (wchar_t *)timeString);
        } /* DEBUG */
1051 1052 1053 1054 1055
        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 已提交
1056
        }
1057 1058
    }
    return kerberosTime;
D
duke 已提交
1059
}