1/*
2 * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * ===========================================================================
28 * (C) Copyright IBM Corp. 2000 All Rights Reserved.
29 * ===========================================================================
30 */
31
32#define UNICODE
33#define _UNICODE
34
35#include <windows.h>
36#include <stdio.h>
37#include <string.h>
38#define SECURITY_WIN32
39#include <security.h>
40#include <ntsecapi.h>
41#include <dsgetdc.h>
42#include <lmcons.h>
43#include <lmapibuf.h>
44#include <jni.h>
45#include "jni_util.h"
46#include <winsock.h>
47
48#undef LSA_SUCCESS
49#define LSA_SUCCESS(Status) ((Status) >= 0)
50#define EXIT_FAILURE -1 // mdu
51
52/*
53 * Library-wide static references
54 */
55
56jclass derValueClass = NULL;
57jclass ticketClass = NULL;
58jclass principalNameClass = NULL;
59jclass encryptionKeyClass = NULL;
60jclass ticketFlagsClass = NULL;
61jclass kerberosTimeClass = NULL;
62jclass javaLangStringClass = NULL;
63
64jmethodID derValueConstructor = 0;
65jmethodID ticketConstructor = 0;
66jmethodID principalNameConstructor = 0;
67jmethodID encryptionKeyConstructor = 0;
68jmethodID ticketFlagsConstructor = 0;
69jmethodID kerberosTimeConstructor = 0;
70jmethodID krbcredsConstructor = 0;
71
72/*
73 * Function prototypes for internal routines
74 *
75 */
76BOOL native_debug = 0;
77
78BOOL PackageConnectLookup(PHANDLE,PULONG);
79
80NTSTATUS ConstructTicketRequest(UNICODE_STRING DomainName,
81                                PKERB_RETRIEVE_TKT_REQUEST *outRequest,
82                                ULONG *outSize);
83
84DWORD ConcatenateUnicodeStrings(UNICODE_STRING *pTarget,
85                                UNICODE_STRING Source1,
86                                UNICODE_STRING Source2);
87
88VOID ShowNTError(LPSTR,NTSTATUS);
89
90VOID
91InitUnicodeString(
92    PUNICODE_STRING DestinationString,
93    PCWSTR SourceString OPTIONAL
94);
95
96jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize);
97
98//mdu
99jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,
100                                UNICODE_STRING domainName);
101
102jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey);
103jobject BuildTicketFlags(JNIEnv *env, PULONG flags);
104jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime);
105
106/*
107 * Class:     sun_security_krb5_KrbCreds
108 * Method:    JNI_OnLoad
109 */
110
111JNIEXPORT jint JNICALL DEF_JNI_OnLoad(
112        JavaVM  *jvm,
113        void    *reserved) {
114
115    jclass cls;
116    JNIEnv *env;
117    jfieldID fldDEBUG;
118
119    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
120        return JNI_EVERSION; /* JNI version not supported */
121    }
122
123    cls = (*env)->FindClass(env,"sun/security/krb5/internal/Krb5");
124    if (cls == NULL) {
125        printf("LSA: Couldn't find Krb5\n");
126        return JNI_ERR;
127    }
128    fldDEBUG = (*env)->GetStaticFieldID(env, cls, "DEBUG", "Z");
129    if (fldDEBUG == NULL) {
130        printf("LSA: Krb5 has no DEBUG field\n");
131        return JNI_ERR;
132    }
133    native_debug = (*env)->GetStaticBooleanField(env, cls, fldDEBUG);
134
135    cls = (*env)->FindClass(env,"sun/security/krb5/internal/Ticket");
136
137    if (cls == NULL) {
138        printf("LSA: Couldn't find Ticket\n");
139        return JNI_ERR;
140    }
141    if (native_debug) {
142        printf("LSA: Found Ticket\n");
143    }
144
145    ticketClass = (*env)->NewWeakGlobalRef(env,cls);
146    if (ticketClass == NULL) {
147        return JNI_ERR;
148    }
149    if (native_debug) {
150        printf("LSA: Made NewWeakGlobalRef\n");
151    }
152
153    cls = (*env)->FindClass(env, "sun/security/krb5/PrincipalName");
154
155    if (cls == NULL) {
156        printf("LSA: Couldn't find PrincipalName\n");
157        return JNI_ERR;
158    }
159    if (native_debug) {
160        printf("LSA: Found PrincipalName\n");
161    }
162
163    principalNameClass = (*env)->NewWeakGlobalRef(env,cls);
164    if (principalNameClass == NULL) {
165        return JNI_ERR;
166    }
167    if (native_debug) {
168        printf("LSA: Made NewWeakGlobalRef\n");
169    }
170
171    cls = (*env)->FindClass(env,"sun/security/util/DerValue");
172
173    if (cls == NULL) {
174        printf("LSA: Couldn't find DerValue\n");
175        return JNI_ERR;
176    }
177    if (native_debug) {
178        printf("LSA: Found DerValue\n");
179    }
180
181    derValueClass = (*env)->NewWeakGlobalRef(env,cls);
182    if (derValueClass == NULL) {
183        return JNI_ERR;
184    }
185    if (native_debug) {
186        printf("LSA: Made NewWeakGlobalRef\n");
187    }
188
189    cls = (*env)->FindClass(env,"sun/security/krb5/EncryptionKey");
190
191    if (cls == NULL) {
192        printf("LSA: Couldn't find EncryptionKey\n");
193        return JNI_ERR;
194    }
195    if (native_debug) {
196        printf("LSA: Found EncryptionKey\n");
197    }
198
199    encryptionKeyClass = (*env)->NewWeakGlobalRef(env,cls);
200    if (encryptionKeyClass == NULL) {
201        return JNI_ERR;
202    }
203    if (native_debug) {
204        printf("LSA: Made NewWeakGlobalRef\n");
205    }
206
207    cls = (*env)->FindClass(env,"sun/security/krb5/internal/TicketFlags");
208
209    if (cls == NULL) {
210        printf("LSA: Couldn't find TicketFlags\n");
211        return JNI_ERR;
212    }
213    if (native_debug) {
214        printf("LSA: Found TicketFlags\n");
215    }
216
217    ticketFlagsClass = (*env)->NewWeakGlobalRef(env,cls);
218    if (ticketFlagsClass == NULL) {
219        return JNI_ERR;
220    }
221    if (native_debug) {
222        printf("LSA: Made NewWeakGlobalRef\n");
223    }
224
225    cls = (*env)->FindClass(env,"sun/security/krb5/internal/KerberosTime");
226
227    if (cls == NULL) {
228        printf("LSA: Couldn't find KerberosTime\n");
229        return JNI_ERR;
230    }
231    if (native_debug) {
232        printf("LSA: Found KerberosTime\n");
233    }
234
235    kerberosTimeClass = (*env)->NewWeakGlobalRef(env,cls);
236    if (kerberosTimeClass == NULL) {
237        return JNI_ERR;
238    }
239    if (native_debug) {
240        printf("LSA: Made NewWeakGlobalRef\n");
241    }
242
243    cls = (*env)->FindClass(env,"java/lang/String");
244
245    if (cls == NULL) {
246        printf("LSA: Couldn't find String\n");
247        return JNI_ERR;
248    }
249    if (native_debug) {
250        printf("LSA: Found String\n");
251    }
252
253    javaLangStringClass = (*env)->NewWeakGlobalRef(env,cls);
254    if (javaLangStringClass == NULL) {
255        return JNI_ERR;
256    }
257    if (native_debug) {
258        printf("LSA: Made NewWeakGlobalRef\n");
259    }
260
261    derValueConstructor = (*env)->GetMethodID(env, derValueClass,
262                                            "<init>", "([B)V");
263    if (derValueConstructor == 0) {
264        printf("LSA: Couldn't find DerValue constructor\n");
265        return JNI_ERR;
266    }
267    if (native_debug) {
268        printf("LSA: Found DerValue constructor\n");
269    }
270
271    ticketConstructor = (*env)->GetMethodID(env, ticketClass,
272                            "<init>", "(Lsun/security/util/DerValue;)V");
273    if (ticketConstructor == 0) {
274        printf("LSA: Couldn't find Ticket constructor\n");
275        return JNI_ERR;
276    }
277    if (native_debug) {
278        printf("LSA: Found Ticket constructor\n");
279    }
280
281    principalNameConstructor = (*env)->GetMethodID(env, principalNameClass,
282                        "<init>", "([Ljava/lang/String;Ljava/lang/String;)V");
283    if (principalNameConstructor == 0) {
284        printf("LSA: Couldn't find PrincipalName constructor\n");
285        return JNI_ERR;
286    }
287    if (native_debug) {
288        printf("LSA: Found PrincipalName constructor\n");
289    }
290
291    encryptionKeyConstructor = (*env)->GetMethodID(env, encryptionKeyClass,
292                                            "<init>", "(I[B)V");
293    if (encryptionKeyConstructor == 0) {
294        printf("LSA: Couldn't find EncryptionKey constructor\n");
295        return JNI_ERR;
296    }
297    if (native_debug) {
298        printf("LSA: Found EncryptionKey constructor\n");
299    }
300
301    ticketFlagsConstructor = (*env)->GetMethodID(env, ticketFlagsClass,
302                                            "<init>", "(I[B)V");
303    if (ticketFlagsConstructor == 0) {
304        printf("LSA: Couldn't find TicketFlags constructor\n");
305        return JNI_ERR;
306    }
307    if (native_debug) {
308        printf("LSA: Found TicketFlags constructor\n");
309    }
310
311    kerberosTimeConstructor = (*env)->GetMethodID(env, kerberosTimeClass,
312                                    "<init>", "(Ljava/lang/String;)V");
313    if (kerberosTimeConstructor == 0) {
314        printf("LSA: Couldn't find KerberosTime constructor\n");
315        return JNI_ERR;
316    }
317    if (native_debug) {
318        printf("LSA: Found KerberosTime constructor\n");
319    }
320
321    if (native_debug) {
322        printf("LSA: Finished OnLoad processing\n");
323    }
324
325    return JNI_VERSION_1_2;
326}
327
328/*
329 * Class:     sun_security_jgss_KrbCreds
330 * Method:    JNI_OnUnload
331 */
332
333JNIEXPORT void JNICALL DEF_JNI_OnUnload(
334        JavaVM  *jvm,
335        void    *reserved) {
336
337    JNIEnv *env;
338
339    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
340        return; /* Nothing else we can do */
341    }
342
343    if (ticketClass != NULL) {
344        (*env)->DeleteWeakGlobalRef(env,ticketClass);
345    }
346    if (derValueClass != NULL) {
347        (*env)->DeleteWeakGlobalRef(env,derValueClass);
348    }
349    if (principalNameClass != NULL) {
350        (*env)->DeleteWeakGlobalRef(env,principalNameClass);
351    }
352    if (encryptionKeyClass != NULL) {
353        (*env)->DeleteWeakGlobalRef(env,encryptionKeyClass);
354    }
355    if (ticketFlagsClass != NULL) {
356        (*env)->DeleteWeakGlobalRef(env,ticketFlagsClass);
357    }
358    if (kerberosTimeClass != NULL) {
359        (*env)->DeleteWeakGlobalRef(env,kerberosTimeClass);
360    }
361    if (javaLangStringClass != NULL) {
362        (*env)->DeleteWeakGlobalRef(env,javaLangStringClass);
363    }
364
365    return;
366}
367
368/*
369 * Class:     sun_security_krb5_Credentials
370 * Method:    acquireDefaultNativeCreds
371 * Signature: ([I])Lsun/security/krb5/Credentials;
372 */
373JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds(
374        JNIEnv *env,
375        jclass krbcredsClass,
376        jintArray jetypes) {
377
378    KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
379    PKERB_RETRIEVE_TKT_RESPONSE TktCacheResponse = NULL;
380    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
381    PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
382    NTSTATUS Status, SubStatus;
383    ULONG requestSize = 0;
384    ULONG responseSize = 0;
385    ULONG rspSize = 0;
386    HANDLE LogonHandle = NULL;
387    ULONG PackageId;
388    jobject ticket, clientPrincipal, targetPrincipal, encryptionKey;
389    jobject ticketFlags, startTime, endTime, krbCreds = NULL;
390    jobject authTime, renewTillTime, hostAddresses = NULL;
391    KERB_EXTERNAL_TICKET *msticket;
392    int found = 0;
393    FILETIME Now, EndTime;
394
395    int i, netypes;
396    jint *etypes = NULL;
397
398    while (TRUE) {
399
400        if (krbcredsConstructor == 0) {
401            krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>",
402                    "(Lsun/security/krb5/internal/Ticket;"
403                    "Lsun/security/krb5/PrincipalName;"
404                    "Lsun/security/krb5/PrincipalName;"
405                    "Lsun/security/krb5/EncryptionKey;"
406                    "Lsun/security/krb5/internal/TicketFlags;"
407                    "Lsun/security/krb5/internal/KerberosTime;"
408                    "Lsun/security/krb5/internal/KerberosTime;"
409                    "Lsun/security/krb5/internal/KerberosTime;"
410                    "Lsun/security/krb5/internal/KerberosTime;"
411                    "Lsun/security/krb5/internal/HostAddresses;)V");
412            if (krbcredsConstructor == 0) {
413                printf("LSA: Couldn't find sun.security.krb5.Credentials constructor\n");
414                break;
415            }
416        }
417
418        if (native_debug) {
419            printf("LSA: Found KrbCreds constructor\n");
420        }
421
422        //
423        // Get the logon handle and package ID from the
424        // Kerberos package
425        //
426        if (!PackageConnectLookup(&LogonHandle, &PackageId))
427            break;
428
429        if (native_debug) {
430            printf("LSA: Got handle to Kerberos package\n");
431        }
432
433        // Get the MS TGT from cache
434        CacheRequest.MessageType = KerbRetrieveTicketMessage;
435        CacheRequest.LogonId.LowPart = 0;
436        CacheRequest.LogonId.HighPart = 0;
437
438        Status = LsaCallAuthenticationPackage(
439                        LogonHandle,
440                        PackageId,
441                        &CacheRequest,
442                        sizeof(CacheRequest),
443                        &TktCacheResponse,
444                        &rspSize,
445                        &SubStatus
446                        );
447
448        if (native_debug) {
449            printf("LSA: Response size is %d\n", rspSize);
450        }
451
452        if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {
453            if (!LSA_SUCCESS(Status)) {
454                ShowNTError("LsaCallAuthenticationPackage", Status);
455            } else {
456                ShowNTError("Protocol status", SubStatus);
457            }
458            break;
459        }
460
461        // got the native MS TGT
462        msticket = &(TktCacheResponse->Ticket);
463
464        netypes = (*env)->GetArrayLength(env, jetypes);
465        etypes = (jint *) (*env)->GetIntArrayElements(env, jetypes, NULL);
466
467        if (etypes == NULL) {
468            break;
469        }
470
471        // check TGT validity
472        if (native_debug) {
473            printf("LSA: TICKET SessionKey KeyType is %d\n", msticket->SessionKey.KeyType);
474        }
475
476        if ((msticket->TicketFlags & KERB_TICKET_FLAGS_invalid) == 0) {
477            GetSystemTimeAsFileTime(&Now);
478            EndTime.dwLowDateTime = msticket->EndTime.LowPart;
479            EndTime.dwHighDateTime = msticket->EndTime.HighPart;
480            if (CompareFileTime(&Now, &EndTime) < 0) {
481                for (i=0; i<netypes; i++) {
482                    if (etypes[i] == msticket->SessionKey.KeyType) {
483                        found = 1;
484                        if (native_debug) {
485                            printf("LSA: Valid etype found: %d\n", etypes[i]);
486                        }
487                        break;
488                    }
489                }
490            }
491        }
492
493        if (!found) {
494            if (native_debug) {
495                printf("LSA: MS TGT in cache is invalid/not supported; request new ticket\n");
496            }
497
498            // use domain to request Ticket
499            Status = ConstructTicketRequest(msticket->TargetDomainName,
500                                &pTicketRequest, &requestSize);
501            if (!LSA_SUCCESS(Status)) {
502                ShowNTError("ConstructTicketRequest status", Status);
503                break;
504            }
505
506            pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
507            pTicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_DONT_USE_CACHE;
508
509            for (i=0; i<netypes; i++) {
510                pTicketRequest->EncryptionType = etypes[i];
511                Status = LsaCallAuthenticationPackage(
512                            LogonHandle,
513                            PackageId,
514                            pTicketRequest,
515                            requestSize,
516                            &pTicketResponse,
517                            &responseSize,
518                            &SubStatus
519                            );
520
521                if (native_debug) {
522                    printf("LSA: Response size is %d for %d\n", responseSize, etypes[i]);
523                }
524
525                if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {
526                    if (!LSA_SUCCESS(Status)) {
527                        ShowNTError("LsaCallAuthenticationPackage", Status);
528                    } else {
529                        ShowNTError("Protocol status", SubStatus);
530                    }
531                    continue;
532                }
533
534                // got the native MS Kerberos TGT
535                msticket = &(pTicketResponse->Ticket);
536
537                if (msticket->SessionKey.KeyType != etypes[i]) {
538                    if (native_debug) {
539                        printf("LSA: Response etype is %d for %d. Retry.\n", msticket->SessionKey.KeyType, etypes[i]);
540                    }
541                    continue;
542                }
543                found = 1;
544                break;
545            }
546        }
547
548        if (etypes != NULL) {
549            (*env)->ReleaseIntArrayElements(env, jetypes, etypes, 0);
550        }
551
552        /*
553
554        typedef struct _KERB_RETRIEVE_TKT_RESPONSE {
555            KERB_EXTERNAL_TICKET Ticket;
556        } KERB_RETRIEVE_TKT_RESPONSE, *PKERB_RETRIEVE_TKT_RESPONSE;
557
558        typedef struct _KERB_EXTERNAL_TICKET {
559            PKERB_EXTERNAL_NAME ServiceName;
560            PKERB_EXTERNAL_NAME TargetName;
561            PKERB_EXTERNAL_NAME ClientName;
562            UNICODE_STRING DomainName;
563            UNICODE_STRING TargetDomainName;
564            UNICODE_STRING AltTargetDomainName;
565            KERB_CRYPTO_KEY SessionKey;
566            ULONG TicketFlags;
567            ULONG Flags;
568            LARGE_INTEGER KeyExpirationTime;
569            LARGE_INTEGER StartTime;
570            LARGE_INTEGER EndTime;
571            LARGE_INTEGER RenewUntil;
572            LARGE_INTEGER TimeSkew;
573            ULONG EncodedTicketSize;
574            PUCHAR EncodedTicket; <========== Here's the good stuff
575        } KERB_EXTERNAL_TICKET, *PKERB_EXTERNAL_TICKET;
576
577        typedef struct _KERB_EXTERNAL_NAME {
578            SHORT NameType;
579            USHORT NameCount;
580            UNICODE_STRING Names[ANYSIZE_ARRAY];
581        } KERB_EXTERNAL_NAME, *PKERB_EXTERNAL_NAME;
582
583        typedef struct _LSA_UNICODE_STRING {
584            USHORT Length;
585            USHORT MaximumLength;
586            PWSTR  Buffer;
587        } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;
588
589        typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;
590
591        typedef struct KERB_CRYPTO_KEY {
592            LONG KeyType;
593            ULONG Length;
594            PUCHAR Value;
595        } KERB_CRYPTO_KEY, *PKERB_CRYPTO_KEY;
596
597        */
598        if (!found) {
599            break;
600        }
601
602        // Build a com.sun.security.krb5.Ticket
603        ticket = BuildTicket(env, msticket->EncodedTicket,
604                                msticket->EncodedTicketSize);
605        if (ticket == NULL) {
606            break;
607        }
608        // OK, have a Ticket, now need to get the client name
609        clientPrincipal = BuildPrincipal(env, msticket->ClientName,
610                                msticket->TargetDomainName); // mdu
611        if (clientPrincipal == NULL) {
612            break;
613        }
614
615        // and the "name" of tgt
616        targetPrincipal = BuildPrincipal(env, msticket->ServiceName,
617                        msticket->DomainName);
618        if (targetPrincipal == NULL) {
619            break;
620        }
621
622        // Get the encryption key
623        encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey));
624        if (encryptionKey == NULL) {
625            break;
626        }
627
628        // and the ticket flags
629        ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags));
630        if (ticketFlags == NULL) {
631            break;
632        }
633
634        // Get the start time
635        startTime = BuildKerberosTime(env, &(msticket->StartTime));
636        if (startTime == NULL) {
637            break;
638        }
639
640        /*
641         * mdu: No point storing the eky expiration time in the auth
642         * time field. Set it to be same as startTime. Looks like
643         * windows does not have post-dated tickets.
644         */
645        authTime = startTime;
646
647        // and the end time
648        endTime = BuildKerberosTime(env, &(msticket->EndTime));
649        if (endTime == NULL) {
650            break;
651        }
652
653        // Get the renew till time
654        renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil));
655        if (renewTillTime == NULL) {
656            break;
657        }
658
659        // and now go build a KrbCreds object
660        krbCreds = (*env)->NewObject(
661                env,
662                krbcredsClass,
663                krbcredsConstructor,
664                ticket,
665                clientPrincipal,
666                targetPrincipal,
667                encryptionKey,
668                ticketFlags,
669                authTime, // mdu
670                startTime,
671                endTime,
672                renewTillTime, //mdu
673                hostAddresses);
674
675        break;
676    } // end of WHILE. This WHILE will never loop.
677
678    // clean up resources
679    if (TktCacheResponse != NULL) {
680        LsaFreeReturnBuffer(TktCacheResponse);
681    }
682    if (pTicketRequest) {
683        LocalFree(pTicketRequest);
684    }
685    if (pTicketResponse != NULL) {
686        LsaFreeReturnBuffer(pTicketResponse);
687    }
688
689    return krbCreds;
690}
691
692static NTSTATUS
693ConstructTicketRequest(UNICODE_STRING DomainName,
694                PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize)
695{
696    NTSTATUS Status;
697    UNICODE_STRING TargetPrefix;
698    USHORT TargetSize;
699    ULONG RequestSize;
700    ULONG Length;
701    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
702
703    *outRequest = NULL;
704    *outSize = 0;
705
706    //
707    // Set up the "krbtgt/" target prefix into a UNICODE_STRING so we
708    // can easily concatenate it later.
709    //
710
711    TargetPrefix.Buffer = L"krbtgt/";
712    Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);
713    TargetPrefix.Length = (USHORT)Length;
714    TargetPrefix.MaximumLength = TargetPrefix.Length;
715
716    //
717    // We will need to concatenate the "krbtgt/" prefix and the
718    // Logon Session's DnsDomainName into our request's target name.
719    //
720    // Therefore, first compute the necessary buffer size for that.
721    //
722    // Note that we might theoretically have integer overflow.
723    //
724
725    TargetSize = TargetPrefix.Length + DomainName.Length;
726
727    //
728    // The ticket request buffer needs to be a single buffer.  That buffer
729    // needs to include the buffer for the target name.
730    //
731
732    RequestSize = sizeof (*pTicketRequest) + TargetSize;
733
734    //
735    // Allocate the request buffer and make sure it's zero-filled.
736    //
737
738    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)
739                    LocalAlloc(LMEM_ZEROINIT, RequestSize);
740    if (!pTicketRequest)
741        return GetLastError();
742
743    //
744    // Concatenate the target prefix with the previous response's
745    // target domain.
746    //
747
748    pTicketRequest->TargetName.Length = 0;
749    pTicketRequest->TargetName.MaximumLength = TargetSize;
750    pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
751    Status = ConcatenateUnicodeStrings(&(pTicketRequest->TargetName),
752                                    TargetPrefix,
753                                    DomainName);
754    *outRequest = pTicketRequest;
755    *outSize    = RequestSize;
756    return Status;
757}
758
759DWORD
760ConcatenateUnicodeStrings(
761    UNICODE_STRING *pTarget,
762    UNICODE_STRING Source1,
763    UNICODE_STRING Source2
764    )
765{
766    //
767    // The buffers for Source1 and Source2 cannot overlap pTarget's
768    // buffer.  Source1.Length + Source2.Length must be <= 0xFFFF,
769    // otherwise we overflow...
770    //
771
772    USHORT TotalSize = Source1.Length + Source2.Length;
773    PBYTE buffer = (PBYTE) pTarget->Buffer;
774
775    if (TotalSize > pTarget->MaximumLength)
776        return ERROR_INSUFFICIENT_BUFFER;
777
778    pTarget->Length = TotalSize;
779    memcpy(buffer, Source1.Buffer, Source1.Length);
780    memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);
781    return ERROR_SUCCESS;
782}
783
784BOOL
785PackageConnectLookup(
786    HANDLE *pLogonHandle,
787    ULONG *pPackageId
788    )
789{
790    LSA_STRING Name;
791    NTSTATUS Status;
792
793    Status = LsaConnectUntrusted(
794                pLogonHandle
795                );
796
797    if (!LSA_SUCCESS(Status))
798    {
799        ShowNTError("LsaConnectUntrusted", Status);
800        return FALSE;
801    }
802
803    Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
804    Name.Length = (USHORT)strlen(Name.Buffer);
805    Name.MaximumLength = Name.Length + 1;
806
807    Status = LsaLookupAuthenticationPackage(
808                *pLogonHandle,
809                &Name,
810                pPackageId
811                );
812
813    if (!LSA_SUCCESS(Status))
814    {
815        ShowNTError("LsaLookupAuthenticationPackage", Status);
816        return FALSE;
817    }
818
819    return TRUE;
820
821}
822
823VOID
824ShowLastError(
825        LPSTR szAPI,
826        DWORD dwError
827        )
828{
829    #define MAX_MSG_SIZE 256
830
831    static WCHAR szMsgBuf[MAX_MSG_SIZE];
832    DWORD dwRes;
833
834    if (native_debug) {
835        printf("LSA: Error calling function %s: %lu\n", szAPI, dwError);
836    }
837
838    dwRes = FormatMessage (
839            FORMAT_MESSAGE_FROM_SYSTEM,
840            NULL,
841            dwError,
842            0,
843            szMsgBuf,
844            MAX_MSG_SIZE,
845            NULL);
846    if (native_debug) {
847        if (0 == dwRes) {
848            printf("LSA: FormatMessage failed with %d\n", GetLastError());
849            // ExitProcess(EXIT_FAILURE);
850        } else {
851            printf("LSA: %S",szMsgBuf);
852        }
853    }
854}
855
856VOID
857ShowNTError(
858        LPSTR szAPI,
859        NTSTATUS Status
860        )
861{
862    //
863    // Convert the NTSTATUS to Winerror. Then call ShowLastError().
864    //
865    ShowLastError(szAPI, LsaNtStatusToWinError(Status));
866}
867
868VOID
869InitUnicodeString(
870        PUNICODE_STRING DestinationString,
871    PCWSTR SourceString OPTIONAL
872    )
873{
874    ULONG Length;
875
876    DestinationString->Buffer = (PWSTR)SourceString;
877    if (SourceString != NULL) {
878        Length = (ULONG)wcslen( SourceString ) * sizeof( WCHAR );
879        DestinationString->Length = (USHORT)Length;
880        DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
881    }
882    else {
883        DestinationString->MaximumLength = 0;
884        DestinationString->Length = 0;
885    }
886}
887
888jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize) {
889
890    /* To build a Ticket, we first need to build a DerValue out of the EncodedTicket.
891     * But before we can do that, we need to make a byte array out of the ET.
892     */
893
894    jobject derValue, ticket;
895    jbyteArray ary;
896
897    ary = (*env)->NewByteArray(env,encodedTicketSize);
898    if ((*env)->ExceptionOccurred(env)) {
899        return (jobject) NULL;
900    }
901
902    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize,
903                                    (jbyte *)encodedTicket);
904    if ((*env)->ExceptionOccurred(env)) {
905        (*env)->DeleteLocalRef(env, ary);
906        return (jobject) NULL;
907    }
908
909    derValue = (*env)->NewObject(env, derValueClass, derValueConstructor, ary);
910    if ((*env)->ExceptionOccurred(env)) {
911        (*env)->DeleteLocalRef(env, ary);
912        return (jobject) NULL;
913    }
914
915    (*env)->DeleteLocalRef(env, ary);
916    ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, derValue);
917    if ((*env)->ExceptionOccurred(env)) {
918        (*env)->DeleteLocalRef(env, derValue);
919        return (jobject) NULL;
920    }
921    (*env)->DeleteLocalRef(env, derValue);
922    return ticket;
923}
924
925// mdu
926jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,
927                                UNICODE_STRING domainName) {
928
929    /*
930     * To build the Principal, we need to get the names out of
931     * this goofy MS structure
932     */
933    jobject principal = NULL;
934    jobject realmStr = NULL;
935    jobjectArray stringArray;
936    jstring tempString;
937    int nameCount,i;
938    PUNICODE_STRING scanner;
939    WCHAR *realm;
940    ULONG realmLen;
941
942    realm = (WCHAR *) LocalAlloc(LMEM_ZEROINIT,
943            ((domainName.Length)*sizeof(WCHAR) + sizeof(UNICODE_NULL)));
944    wcsncpy(realm, domainName.Buffer, domainName.Length/sizeof(WCHAR));
945
946    if (native_debug) {
947        printf("LSA: Principal domain is %S\n", realm);
948        printf("LSA: Name type is %x\n", principalName->NameType);
949        printf("LSA: Name count is %x\n", principalName->NameCount);
950    }
951
952    nameCount = principalName->NameCount;
953    stringArray = (*env)->NewObjectArray(env, nameCount,
954                            javaLangStringClass, NULL);
955    if (stringArray == NULL) {
956        if (native_debug) {
957            printf("LSA: Can't allocate String array for Principal\n");
958        }
959        goto cleanup;
960    }
961
962    for (i=0; i<nameCount; i++) {
963        // get the principal name
964        scanner = &(principalName->Names[i]);
965
966        // OK, got a Char array, so construct a String
967        tempString = (*env)->NewString(env, (const jchar*)scanner->Buffer,
968                            scanner->Length/sizeof(WCHAR));
969
970        if (tempString == NULL) {
971            goto cleanup;
972        }
973
974        // Set the String into the StringArray
975        (*env)->SetObjectArrayElement(env, stringArray, i, tempString);
976
977        if ((*env)->ExceptionCheck(env)) {
978            goto cleanup;
979        }
980
981        // Do I have to worry about storage reclamation here?
982    }
983    // now set the realm in the principal
984    realmLen = (ULONG)wcslen((PWCHAR)realm);
985    realmStr = (*env)->NewString(env, (PWCHAR)realm, (USHORT)realmLen);
986
987    if (realmStr == NULL) {
988        goto cleanup;
989    }
990
991    principal = (*env)->NewObject(env, principalNameClass,
992                    principalNameConstructor, stringArray, realmStr);
993
994cleanup:
995    // free local resources
996    LocalFree(realm);
997
998    return principal;
999}
1000
1001jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) {
1002    // First, need to build a byte array
1003    jbyteArray ary;
1004    jobject encryptionKey = NULL;
1005    unsigned int i;
1006
1007    for (i=0; i<cryptoKey->Length; i++) {
1008        if (cryptoKey->Value[i]) break;
1009    }
1010    if (i == cryptoKey->Length) {
1011        if (native_debug) {
1012            printf("LSA: Session key all zero. Stop.\n");
1013        }
1014        return NULL;
1015    }
1016
1017    ary = (*env)->NewByteArray(env,cryptoKey->Length);
1018    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, cryptoKey->Length,
1019                                    (jbyte *)cryptoKey->Value);
1020    if ((*env)->ExceptionOccurred(env)) {
1021        (*env)->DeleteLocalRef(env, ary);
1022    } else {
1023        encryptionKey = (*env)->NewObject(env, encryptionKeyClass,
1024                encryptionKeyConstructor, cryptoKey->KeyType, ary);
1025    }
1026
1027    return encryptionKey;
1028}
1029
1030jobject BuildTicketFlags(JNIEnv *env, PULONG flags) {
1031    jobject ticketFlags = NULL;
1032    jbyteArray ary;
1033    /*
1034     * mdu: Convert the bytes to nework byte order before copying
1035     * them to a Java byte array.
1036     */
1037    ULONG nlflags = htonl(*flags);
1038
1039    ary = (*env)->NewByteArray(env, sizeof(*flags));
1040    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, sizeof(*flags),
1041                                    (jbyte *)&nlflags);
1042    if ((*env)->ExceptionOccurred(env)) {
1043        (*env)->DeleteLocalRef(env, ary);
1044    } else {
1045        ticketFlags = (*env)->NewObject(env, ticketFlagsClass,
1046                ticketFlagsConstructor, sizeof(*flags)*8, ary);
1047    }
1048
1049    return ticketFlags;
1050}
1051
1052jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) {
1053    jobject kerberosTime = NULL;
1054    jstring stringTime = NULL;
1055    SYSTEMTIME systemTime;
1056    WCHAR timeString[16];
1057    WCHAR month[3];
1058    WCHAR day[3];
1059    WCHAR hour[3];
1060    WCHAR minute[3];
1061    WCHAR second[3];
1062
1063    if (FileTimeToSystemTime((FILETIME *)kerbtime, &systemTime)) {
1064        // XXX Cannot use %02.2ld, because the leading 0 is ignored for integers.
1065        // So, print them to strings, and then print them to the master string with a
1066        // format pattern that makes it two digits and prefix with a 0 if necessary.
1067        swprintf( (wchar_t *)month, 3, L"%2.2d", systemTime.wMonth);
1068        swprintf( (wchar_t *)day, 3, L"%2.2d", systemTime.wDay);
1069        swprintf( (wchar_t *)hour, 3, L"%2.2d", systemTime.wHour);
1070        swprintf( (wchar_t *)minute, 3, L"%2.2d", systemTime.wMinute);
1071        swprintf( (wchar_t *)second, 3, L"%2.2d", systemTime.wSecond);
1072        swprintf( (wchar_t *)timeString, 16,
1073                L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",
1074                systemTime.wYear,
1075                month,
1076                day,
1077                hour,
1078                minute,
1079                second );
1080        if (native_debug) {
1081            printf("LSA: %S\n", (wchar_t *)timeString);
1082        }
1083        stringTime = (*env)->NewString(env, timeString,
1084                (sizeof(timeString)/sizeof(WCHAR))-1);
1085        if (stringTime != NULL) { // everything's OK so far
1086            kerberosTime = (*env)->NewObject(env, kerberosTimeClass,
1087                    kerberosTimeConstructor, stringTime);
1088        }
1089    }
1090    return kerberosTime;
1091}
1092