jdk

Форк
0
1077 строк · 32.2 Кб
1
/*
2
 * Copyright (c) 2000, 2024, 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
#include "sun_security_krb5_Credentials.h"
48

49
#undef LSA_SUCCESS
50
#define LSA_SUCCESS(Status) ((Status) >= 0)
51

52
/*
53
 * Library-wide static references
54
 */
55

56
jclass ticketClass = NULL;
57
jclass principalNameClass = NULL;
58
jclass encryptionKeyClass = NULL;
59
jclass ticketFlagsClass = NULL;
60
jclass kerberosTimeClass = NULL;
61
jclass javaLangStringClass = NULL;
62

63
jmethodID ticketConstructor = 0;
64
jmethodID principalNameConstructor = 0;
65
jmethodID encryptionKeyConstructor = 0;
66
jmethodID ticketFlagsConstructor = 0;
67
jmethodID kerberosTimeConstructor = 0;
68
jmethodID krbcredsConstructor = 0;
69

70
/*
71
 * Function prototypes for internal routines
72
 *
73
 */
74
BOOL native_debug = 0;
75

76
BOOL PackageConnectLookup(PHANDLE,PULONG);
77

78
static
79
NTSTATUS ConstructTicketRequest(JNIEnv *env,
80
                                UNICODE_STRING DomainName,
81
                                PKERB_RETRIEVE_TKT_REQUEST *outRequest,
82
                                ULONG *outSize);
83

84
DWORD ConcatenateUnicodeStrings(UNICODE_STRING *pTarget,
85
                                UNICODE_STRING Source1,
86
                                UNICODE_STRING Source2);
87

88
VOID ShowNTError(LPSTR,NTSTATUS);
89

90
VOID
91
InitUnicodeString(
92
    PUNICODE_STRING DestinationString,
93
    PCWSTR SourceString OPTIONAL
94
);
95

96
jobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize);
97

98
//mdu
99
jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,
100
                                UNICODE_STRING domainName);
101

102
jobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey);
103
jobject BuildTicketFlags(JNIEnv *env, PULONG flags);
104
jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime);
105

106
void ThrowOOME(JNIEnv *env, const char *szMessage);
107

108
/*
109
 * Class:     sun_security_krb5_KrbCreds
110
 * Method:    JNI_OnLoad
111
 */
112

113
JNIEXPORT jint JNICALL DEF_JNI_OnLoad(
114
        JavaVM  *jvm,
115
        void    *reserved) {
116

117
    jclass cls;
118
    JNIEnv *env;
119
    jfieldID fldDEBUG;
120

121
    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
122
        return JNI_EVERSION; /* JNI version not supported */
123
    }
124

125
    cls = (*env)->FindClass(env,"sun/security/krb5/internal/Krb5");
126
    if (cls == NULL) {
127
        fprintf(stderr, "LSA: Couldn't find Krb5\n");
128
        return JNI_ERR;
129
    }
130
    fldDEBUG = (*env)->GetStaticFieldID(env, cls, "DEBUG", "Lsun/security/util/Debug;");
131
    if (fldDEBUG == NULL) {
132
        fprintf(stderr, "LSA: Krb5 has no DEBUG field\n");
133
        return JNI_ERR;
134
    }
135
    native_debug = (*env)->GetStaticObjectField(env, cls, fldDEBUG) != NULL;
136

137
    cls = (*env)->FindClass(env,"sun/security/krb5/internal/Ticket");
138

139
    if (cls == NULL) {
140
        fprintf(stderr, "LSA: Couldn't find Ticket\n");
141
        return JNI_ERR;
142
    }
143
    if (native_debug) {
144
        fprintf(stderr, "LSA: Found Ticket\n");
145
    }
146

147
    ticketClass = (*env)->NewWeakGlobalRef(env,cls);
148
    if (ticketClass == NULL) {
149
        return JNI_ERR;
150
    }
151
    if (native_debug) {
152
        fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");
153
    }
154

155
    cls = (*env)->FindClass(env, "sun/security/krb5/PrincipalName");
156

157
    if (cls == NULL) {
158
        fprintf(stderr, "LSA: Couldn't find PrincipalName\n");
159
        return JNI_ERR;
160
    }
161
    if (native_debug) {
162
        fprintf(stderr, "LSA: Found PrincipalName\n");
163
    }
164

165
    principalNameClass = (*env)->NewWeakGlobalRef(env,cls);
166
    if (principalNameClass == NULL) {
167
        return JNI_ERR;
168
    }
169
    if (native_debug) {
170
        fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");
171
    }
172

173
    cls = (*env)->FindClass(env,"sun/security/krb5/EncryptionKey");
174

175
    if (cls == NULL) {
176
        fprintf(stderr, "LSA: Couldn't find EncryptionKey\n");
177
        return JNI_ERR;
178
    }
179
    if (native_debug) {
180
        fprintf(stderr, "LSA: Found EncryptionKey\n");
181
    }
182

183
    encryptionKeyClass = (*env)->NewWeakGlobalRef(env,cls);
184
    if (encryptionKeyClass == NULL) {
185
        return JNI_ERR;
186
    }
187
    if (native_debug) {
188
        fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");
189
    }
190

191
    cls = (*env)->FindClass(env,"sun/security/krb5/internal/TicketFlags");
192

193
    if (cls == NULL) {
194
        fprintf(stderr, "LSA: Couldn't find TicketFlags\n");
195
        return JNI_ERR;
196
    }
197
    if (native_debug) {
198
        fprintf(stderr, "LSA: Found TicketFlags\n");
199
    }
200

201
    ticketFlagsClass = (*env)->NewWeakGlobalRef(env,cls);
202
    if (ticketFlagsClass == NULL) {
203
        return JNI_ERR;
204
    }
205
    if (native_debug) {
206
        fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");
207
    }
208

209
    cls = (*env)->FindClass(env,"sun/security/krb5/internal/KerberosTime");
210

211
    if (cls == NULL) {
212
        fprintf(stderr, "LSA: Couldn't find KerberosTime\n");
213
        return JNI_ERR;
214
    }
215
    if (native_debug) {
216
        fprintf(stderr, "LSA: Found KerberosTime\n");
217
    }
218

219
    kerberosTimeClass = (*env)->NewWeakGlobalRef(env,cls);
220
    if (kerberosTimeClass == NULL) {
221
        return JNI_ERR;
222
    }
223
    if (native_debug) {
224
        fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");
225
    }
226

227
    cls = (*env)->FindClass(env,"java/lang/String");
228

229
    if (cls == NULL) {
230
        fprintf(stderr, "LSA: Couldn't find String\n");
231
        return JNI_ERR;
232
    }
233
    if (native_debug) {
234
        fprintf(stderr, "LSA: Found String\n");
235
    }
236

237
    javaLangStringClass = (*env)->NewWeakGlobalRef(env,cls);
238
    if (javaLangStringClass == NULL) {
239
        return JNI_ERR;
240
    }
241
    if (native_debug) {
242
        fprintf(stderr, "LSA: Made NewWeakGlobalRef\n");
243
    }
244

245
    ticketConstructor = (*env)->GetMethodID(env, ticketClass,
246
                            "<init>", "([B)V");
247
    if (ticketConstructor == 0) {
248
        fprintf(stderr, "LSA: Couldn't find Ticket constructor\n");
249
        return JNI_ERR;
250
    }
251
    if (native_debug) {
252
        fprintf(stderr, "LSA: Found Ticket constructor\n");
253
    }
254

255
    principalNameConstructor = (*env)->GetMethodID(env, principalNameClass,
256
                        "<init>", "([Ljava/lang/String;Ljava/lang/String;)V");
257
    if (principalNameConstructor == 0) {
258
        fprintf(stderr, "LSA: Couldn't find PrincipalName constructor\n");
259
        return JNI_ERR;
260
    }
261
    if (native_debug) {
262
        fprintf(stderr, "LSA: Found PrincipalName constructor\n");
263
    }
264

265
    encryptionKeyConstructor = (*env)->GetMethodID(env, encryptionKeyClass,
266
                                            "<init>", "(I[B)V");
267
    if (encryptionKeyConstructor == 0) {
268
        fprintf(stderr, "LSA: Couldn't find EncryptionKey constructor\n");
269
        return JNI_ERR;
270
    }
271
    if (native_debug) {
272
        fprintf(stderr, "LSA: Found EncryptionKey constructor\n");
273
    }
274

275
    ticketFlagsConstructor = (*env)->GetMethodID(env, ticketFlagsClass,
276
                                            "<init>", "(I[B)V");
277
    if (ticketFlagsConstructor == 0) {
278
        fprintf(stderr, "LSA: Couldn't find TicketFlags constructor\n");
279
        return JNI_ERR;
280
    }
281
    if (native_debug) {
282
        fprintf(stderr, "LSA: Found TicketFlags constructor\n");
283
    }
284

285
    kerberosTimeConstructor = (*env)->GetMethodID(env, kerberosTimeClass,
286
                                    "<init>", "(Ljava/lang/String;)V");
287
    if (kerberosTimeConstructor == 0) {
288
        fprintf(stderr, "LSA: Couldn't find KerberosTime constructor\n");
289
        return JNI_ERR;
290
    }
291
    if (native_debug) {
292
        fprintf(stderr, "LSA: Found KerberosTime constructor\n");
293
    }
294

295
    if (native_debug) {
296
        fprintf(stderr, "LSA: Finished OnLoad processing\n");
297
    }
298

299
    return JNI_VERSION_1_2;
300
}
301

302
/*
303
 * Class:     sun_security_jgss_KrbCreds
304
 * Method:    JNI_OnUnload
305
 */
306

307
JNIEXPORT void JNICALL DEF_JNI_OnUnload(
308
        JavaVM  *jvm,
309
        void    *reserved) {
310

311
    JNIEnv *env;
312

313
    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
314
        return; /* Nothing else we can do */
315
    }
316

317
    if (ticketClass != NULL) {
318
        (*env)->DeleteWeakGlobalRef(env,ticketClass);
319
    }
320
    if (principalNameClass != NULL) {
321
        (*env)->DeleteWeakGlobalRef(env,principalNameClass);
322
    }
323
    if (encryptionKeyClass != NULL) {
324
        (*env)->DeleteWeakGlobalRef(env,encryptionKeyClass);
325
    }
326
    if (ticketFlagsClass != NULL) {
327
        (*env)->DeleteWeakGlobalRef(env,ticketFlagsClass);
328
    }
329
    if (kerberosTimeClass != NULL) {
330
        (*env)->DeleteWeakGlobalRef(env,kerberosTimeClass);
331
    }
332
    if (javaLangStringClass != NULL) {
333
        (*env)->DeleteWeakGlobalRef(env,javaLangStringClass);
334
    }
335

336
    return;
337
}
338

339
/*
340
 * Class:     sun_security_krb5_Credentials
341
 * Method:    acquireDefaultNativeCreds
342
 * Signature: ([I])Lsun/security/krb5/Credentials;
343
 */
344
JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds(
345
        JNIEnv *env,
346
        jclass krbcredsClass,
347
        jintArray jetypes) {
348

349
    KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
350
    PKERB_RETRIEVE_TKT_RESPONSE TktCacheResponse = NULL;
351
    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
352
    PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
353
    NTSTATUS Status, SubStatus;
354
    ULONG requestSize = 0;
355
    ULONG responseSize = 0;
356
    ULONG rspSize = 0;
357
    HANDLE LogonHandle = NULL;
358
    ULONG PackageId;
359
    jobject ticket, clientPrincipal, targetPrincipal, encryptionKey;
360
    jobject ticketFlags, startTime, endTime, krbCreds = NULL;
361
    jobject authTime, renewTillTime, hostAddresses = NULL;
362
    KERB_EXTERNAL_TICKET *msticket;
363
    int found = 0;
364
    FILETIME Now, EndTime;
365

366
    int i, netypes;
367
    jint *etypes = NULL;
368

369
    while (TRUE) {
370

371
        if (krbcredsConstructor == 0) {
372
            krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>",
373
                    "(Lsun/security/krb5/internal/Ticket;"
374
                    "Lsun/security/krb5/PrincipalName;"
375
                    "Lsun/security/krb5/PrincipalName;"
376
                    "Lsun/security/krb5/PrincipalName;"
377
                    "Lsun/security/krb5/PrincipalName;"
378
                    "Lsun/security/krb5/EncryptionKey;"
379
                    "Lsun/security/krb5/internal/TicketFlags;"
380
                    "Lsun/security/krb5/internal/KerberosTime;"
381
                    "Lsun/security/krb5/internal/KerberosTime;"
382
                    "Lsun/security/krb5/internal/KerberosTime;"
383
                    "Lsun/security/krb5/internal/KerberosTime;"
384
                    "Lsun/security/krb5/internal/HostAddresses;)V");
385
            if (krbcredsConstructor == 0) {
386
                fprintf(stderr, "LSA: Couldn't find sun.security.krb5.Credentials constructor\n");
387
                break;
388
            }
389
        }
390

391
        if (native_debug) {
392
            fprintf(stderr, "LSA: Found KrbCreds constructor\n");
393
        }
394

395
        //
396
        // Get the logon handle and package ID from the
397
        // Kerberos package
398
        //
399
        if (!PackageConnectLookup(&LogonHandle, &PackageId))
400
            break;
401

402
        if (native_debug) {
403
            fprintf(stderr, "LSA: Got handle to Kerberos package\n");
404
        }
405

406
        // Get the MS TGT from cache
407
        CacheRequest.MessageType = KerbRetrieveTicketMessage;
408
        CacheRequest.LogonId.LowPart = 0;
409
        CacheRequest.LogonId.HighPart = 0;
410

411
        Status = LsaCallAuthenticationPackage(
412
                        LogonHandle,
413
                        PackageId,
414
                        &CacheRequest,
415
                        sizeof(CacheRequest),
416
                        &TktCacheResponse,
417
                        &rspSize,
418
                        &SubStatus
419
                        );
420

421
        if (native_debug) {
422
            fprintf(stderr, "LSA: Response size is %d\n", rspSize);
423
        }
424

425
        if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {
426
            if (!LSA_SUCCESS(Status)) {
427
                ShowNTError("LsaCallAuthenticationPackage", Status);
428
            } else {
429
                ShowNTError("Protocol status", SubStatus);
430
            }
431
            break;
432
        }
433

434
        // got the native MS TGT
435
        msticket = &(TktCacheResponse->Ticket);
436

437
        netypes = (*env)->GetArrayLength(env, jetypes);
438
        etypes = (jint *) (*env)->GetIntArrayElements(env, jetypes, NULL);
439

440
        if (etypes == NULL) {
441
            break;
442
        }
443

444
        // check TGT validity
445
        if (native_debug) {
446
            fprintf(stderr, "LSA: TICKET SessionKey KeyType is %d\n", msticket->SessionKey.KeyType);
447
        }
448

449
        if ((msticket->TicketFlags & KERB_TICKET_FLAGS_invalid) == 0) {
450
            GetSystemTimeAsFileTime(&Now);
451
            EndTime.dwLowDateTime = msticket->EndTime.LowPart;
452
            EndTime.dwHighDateTime = msticket->EndTime.HighPart;
453
            if (CompareFileTime(&Now, &EndTime) < 0) {
454
                for (i=0; i<netypes; i++) {
455
                    if (etypes[i] == msticket->SessionKey.KeyType) {
456
                        found = 1;
457
                        if (native_debug) {
458
                            fprintf(stderr, "LSA: Valid etype found: %d\n", etypes[i]);
459
                        }
460
                        break;
461
                    }
462
                }
463
            }
464
        }
465

466
        if (!found) {
467
            if (native_debug) {
468
                fprintf(stderr, "LSA: MS TGT in cache is invalid/not supported; request new ticket\n");
469
            }
470

471
            // use domain to request Ticket
472
            Status = ConstructTicketRequest(env, msticket->TargetDomainName,
473
                                &pTicketRequest, &requestSize);
474
            if (!LSA_SUCCESS(Status)) {
475
                ShowNTError("ConstructTicketRequest status", Status);
476
                break;
477
            }
478

479
            pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
480
            pTicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_DONT_USE_CACHE;
481

482
            for (i=0; i<netypes; i++) {
483
                pTicketRequest->EncryptionType = etypes[i];
484
                Status = LsaCallAuthenticationPackage(
485
                            LogonHandle,
486
                            PackageId,
487
                            pTicketRequest,
488
                            requestSize,
489
                            &pTicketResponse,
490
                            &responseSize,
491
                            &SubStatus
492
                            );
493

494
                if (native_debug) {
495
                    fprintf(stderr, "LSA: Response size is %d for %d\n", responseSize, etypes[i]);
496
                }
497

498
                if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {
499
                    if (!LSA_SUCCESS(Status)) {
500
                        ShowNTError("LsaCallAuthenticationPackage", Status);
501
                    } else {
502
                        ShowNTError("Protocol status", SubStatus);
503
                    }
504
                    continue;
505
                }
506

507
                // got the native MS Kerberos TGT
508
                msticket = &(pTicketResponse->Ticket);
509

510
                if (msticket->SessionKey.KeyType != etypes[i]) {
511
                    if (native_debug) {
512
                        fprintf(stderr, "LSA: Response etype is %d for %d. Retry.\n", msticket->SessionKey.KeyType, etypes[i]);
513
                    }
514
                    continue;
515
                }
516
                found = 1;
517
                break;
518
            }
519
        }
520

521
        if (etypes != NULL) {
522
            (*env)->ReleaseIntArrayElements(env, jetypes, etypes, 0);
523
        }
524

525
        /*
526

527
        typedef struct _KERB_RETRIEVE_TKT_RESPONSE {
528
            KERB_EXTERNAL_TICKET Ticket;
529
        } KERB_RETRIEVE_TKT_RESPONSE, *PKERB_RETRIEVE_TKT_RESPONSE;
530

531
        typedef struct _KERB_EXTERNAL_TICKET {
532
            PKERB_EXTERNAL_NAME ServiceName;
533
            PKERB_EXTERNAL_NAME TargetName;
534
            PKERB_EXTERNAL_NAME ClientName;
535
            UNICODE_STRING DomainName;
536
            UNICODE_STRING TargetDomainName;
537
            UNICODE_STRING AltTargetDomainName;
538
            KERB_CRYPTO_KEY SessionKey;
539
            ULONG TicketFlags;
540
            ULONG Flags;
541
            LARGE_INTEGER KeyExpirationTime;
542
            LARGE_INTEGER StartTime;
543
            LARGE_INTEGER EndTime;
544
            LARGE_INTEGER RenewUntil;
545
            LARGE_INTEGER TimeSkew;
546
            ULONG EncodedTicketSize;
547
            PUCHAR EncodedTicket; <========== Here's the good stuff
548
        } KERB_EXTERNAL_TICKET, *PKERB_EXTERNAL_TICKET;
549

550
        typedef struct _KERB_EXTERNAL_NAME {
551
            SHORT NameType;
552
            USHORT NameCount;
553
            UNICODE_STRING Names[ANYSIZE_ARRAY];
554
        } KERB_EXTERNAL_NAME, *PKERB_EXTERNAL_NAME;
555

556
        typedef struct _LSA_UNICODE_STRING {
557
            USHORT Length;
558
            USHORT MaximumLength;
559
            PWSTR  Buffer;
560
        } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;
561

562
        typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;
563

564
        typedef struct KERB_CRYPTO_KEY {
565
            LONG KeyType;
566
            ULONG Length;
567
            PUCHAR Value;
568
        } KERB_CRYPTO_KEY, *PKERB_CRYPTO_KEY;
569

570
        */
571
        if (!found) {
572
            break;
573
        }
574

575
        // Build a com.sun.security.krb5.Ticket
576
        ticket = BuildTicket(env, msticket->EncodedTicket,
577
                                msticket->EncodedTicketSize);
578
        if (ticket == NULL) {
579
            break;
580
        }
581
        // OK, have a Ticket, now need to get the client name
582
        clientPrincipal = BuildPrincipal(env, msticket->ClientName,
583
                                msticket->TargetDomainName); // mdu
584
        if (clientPrincipal == NULL) {
585
            break;
586
        }
587

588
        // and the "name" of tgt
589
        targetPrincipal = BuildPrincipal(env, msticket->ServiceName,
590
                        msticket->DomainName);
591
        if (targetPrincipal == NULL) {
592
            break;
593
        }
594

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

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

607
        // Get the start time
608
        startTime = BuildKerberosTime(env, &(msticket->StartTime));
609
        if (startTime == NULL) {
610
            break;
611
        }
612

613
        /*
614
         * mdu: No point storing the eky expiration time in the auth
615
         * time field. Set it to be same as startTime. Looks like
616
         * windows does not have post-dated tickets.
617
         */
618
        authTime = startTime;
619

620
        // and the end time
621
        endTime = BuildKerberosTime(env, &(msticket->EndTime));
622
        if (endTime == NULL) {
623
            break;
624
        }
625

626
        // Get the renew till time
627
        renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil));
628
        if (renewTillTime == NULL) {
629
            break;
630
        }
631

632
        // and now go build a KrbCreds object
633
        krbCreds = (*env)->NewObject(
634
                env,
635
                krbcredsClass,
636
                krbcredsConstructor,
637
                ticket,
638
                clientPrincipal,
639
                NULL,
640
                targetPrincipal,
641
                NULL,
642
                encryptionKey,
643
                ticketFlags,
644
                authTime, // mdu
645
                startTime,
646
                endTime,
647
                renewTillTime, //mdu
648
                hostAddresses);
649

650
        break;
651
    } // end of WHILE. This WHILE will never loop.
652

653
    // clean up resources
654
    if (TktCacheResponse != NULL) {
655
        LsaFreeReturnBuffer(TktCacheResponse);
656
    }
657
    if (pTicketRequest) {
658
        LocalFree(pTicketRequest);
659
    }
660
    if (pTicketResponse != NULL) {
661
        LsaFreeReturnBuffer(pTicketResponse);
662
    }
663

664
    return krbCreds;
665
}
666

667
static NTSTATUS
668
ConstructTicketRequest(JNIEnv *env, UNICODE_STRING DomainName,
669
                PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize)
670
{
671
    NTSTATUS Status;
672
    UNICODE_STRING TargetPrefix;
673
    USHORT TargetSize;
674
    ULONG RequestSize;
675
    ULONG Length;
676
    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
677

678
    *outRequest = NULL;
679
    *outSize = 0;
680

681
    //
682
    // Set up the "krbtgt/" target prefix into a UNICODE_STRING so we
683
    // can easily concatenate it later.
684
    //
685

686
    TargetPrefix.Buffer = L"krbtgt/";
687
    Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);
688
    TargetPrefix.Length = (USHORT)Length;
689
    TargetPrefix.MaximumLength = TargetPrefix.Length;
690

691
    //
692
    // We will need to concatenate the "krbtgt/" prefix and the
693
    // Logon Session's DnsDomainName into our request's target name.
694
    //
695
    // Therefore, first compute the necessary buffer size for that.
696
    //
697
    // Note that we might theoretically have integer overflow.
698
    //
699

700
    TargetSize = TargetPrefix.Length + DomainName.Length;
701

702
    //
703
    // The ticket request buffer needs to be a single buffer.  That buffer
704
    // needs to include the buffer for the target name.
705
    //
706

707
    RequestSize = sizeof (*pTicketRequest) + TargetSize;
708

709
    //
710
    // Allocate the request buffer and make sure it's zero-filled.
711
    //
712

713
    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)
714
                    LocalAlloc(LMEM_ZEROINIT, RequestSize);
715
    if (!pTicketRequest) {
716
        ThrowOOME(env, "Can't allocate memory for ticket");
717
        return GetLastError();
718
    }
719

720
    //
721
    // Concatenate the target prefix with the previous response's
722
    // target domain.
723
    //
724

725
    pTicketRequest->TargetName.Length = 0;
726
    pTicketRequest->TargetName.MaximumLength = TargetSize;
727
    pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
728
    Status = ConcatenateUnicodeStrings(&(pTicketRequest->TargetName),
729
                                    TargetPrefix,
730
                                    DomainName);
731
    *outRequest = pTicketRequest;
732
    *outSize    = RequestSize;
733
    return Status;
734
}
735

736
DWORD
737
ConcatenateUnicodeStrings(
738
    UNICODE_STRING *pTarget,
739
    UNICODE_STRING Source1,
740
    UNICODE_STRING Source2
741
    )
742
{
743
    //
744
    // The buffers for Source1 and Source2 cannot overlap pTarget's
745
    // buffer.  Source1.Length + Source2.Length must be <= 0xFFFF,
746
    // otherwise we overflow...
747
    //
748

749
    USHORT TotalSize = Source1.Length + Source2.Length;
750
    PBYTE buffer = (PBYTE) pTarget->Buffer;
751

752
    if (TotalSize > pTarget->MaximumLength)
753
        return ERROR_INSUFFICIENT_BUFFER;
754

755
    pTarget->Length = TotalSize;
756
    memcpy(buffer, Source1.Buffer, Source1.Length);
757
    memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);
758
    return ERROR_SUCCESS;
759
}
760

761
BOOL
762
PackageConnectLookup(
763
    HANDLE *pLogonHandle,
764
    ULONG *pPackageId
765
    )
766
{
767
    LSA_STRING Name;
768
    NTSTATUS Status;
769

770
    Status = LsaConnectUntrusted(
771
                pLogonHandle
772
                );
773

774
    if (!LSA_SUCCESS(Status))
775
    {
776
        ShowNTError("LsaConnectUntrusted", Status);
777
        return FALSE;
778
    }
779

780
    Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
781
    Name.Length = (USHORT)strlen(Name.Buffer);
782
    Name.MaximumLength = Name.Length + 1;
783

784
    Status = LsaLookupAuthenticationPackage(
785
                *pLogonHandle,
786
                &Name,
787
                pPackageId
788
                );
789

790
    if (!LSA_SUCCESS(Status))
791
    {
792
        ShowNTError("LsaLookupAuthenticationPackage", Status);
793
        return FALSE;
794
    }
795

796
    return TRUE;
797

798
}
799

800
VOID
801
ShowLastError(
802
        LPSTR szAPI,
803
        DWORD dwError
804
        )
805
{
806
    #define MAX_MSG_SIZE 256
807

808
    static WCHAR szMsgBuf[MAX_MSG_SIZE];
809
    DWORD dwRes;
810

811
    if (native_debug) {
812
        fprintf(stderr, "LSA: Error calling function %s: %lu\n", szAPI, dwError);
813
    }
814

815
    dwRes = FormatMessage (
816
            FORMAT_MESSAGE_FROM_SYSTEM,
817
            NULL,
818
            dwError,
819
            0,
820
            szMsgBuf,
821
            MAX_MSG_SIZE,
822
            NULL);
823
    if (native_debug) {
824
        if (0 == dwRes) {
825
            fprintf(stderr, "LSA: FormatMessage failed with %d\n", GetLastError());
826
            // #define EXIT_FAILURE -1 // mdu
827
            // ExitProcess(EXIT_FAILURE);
828
        } else {
829
            fprintf(stderr, "LSA: %S",szMsgBuf);
830
        }
831
    }
832
}
833

834
VOID
835
ShowNTError(
836
        LPSTR szAPI,
837
        NTSTATUS Status
838
        )
839
{
840
    //
841
    // Convert the NTSTATUS to Winerror. Then call ShowLastError().
842
    //
843
    ShowLastError(szAPI, LsaNtStatusToWinError(Status));
844
}
845

846
VOID
847
InitUnicodeString(
848
        PUNICODE_STRING DestinationString,
849
    PCWSTR SourceString OPTIONAL
850
    )
851
{
852
    ULONG Length;
853

854
    DestinationString->Buffer = (PWSTR)SourceString;
855
    if (SourceString != NULL) {
856
        Length = (ULONG)wcslen( SourceString ) * sizeof( WCHAR );
857
        DestinationString->Length = (USHORT)Length;
858
        DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
859
    }
860
    else {
861
        DestinationString->MaximumLength = 0;
862
        DestinationString->Length = 0;
863
    }
864
}
865

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

868
    // To build a Ticket, we need to make a byte array out of the EncodedTicket.
869

870
    jobject ticket;
871
    jbyteArray ary;
872

873
    ary = (*env)->NewByteArray(env,encodedTicketSize);
874
    if (ary == NULL) {
875
        return (jobject) NULL;
876
    }
877

878
    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize,
879
                                    (jbyte *)encodedTicket);
880
    if ((*env)->ExceptionOccurred(env)) {
881
        (*env)->DeleteLocalRef(env, ary);
882
        return (jobject) NULL;
883
    }
884

885
    ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, ary);
886
    if ((*env)->ExceptionOccurred(env)) {
887
        (*env)->DeleteLocalRef(env, ary);
888
        return (jobject) NULL;
889
    }
890
    (*env)->DeleteLocalRef(env, ary);
891
    return ticket;
892
}
893

894
// mdu
895
jobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,
896
                                UNICODE_STRING domainName) {
897

898
    /*
899
     * To build the Principal, we need to get the names out of
900
     * this goofy MS structure
901
     */
902
    jobject principal = NULL;
903
    jobject realmStr = NULL;
904
    jobjectArray stringArray;
905
    jstring tempString;
906
    int nameCount,i;
907
    PUNICODE_STRING scanner;
908
    WCHAR *realm;
909
    ULONG realmLen;
910

911
    realm = (WCHAR *) LocalAlloc(LMEM_ZEROINIT,
912
            ((domainName.Length)*sizeof(WCHAR) + sizeof(UNICODE_NULL)));
913
    if (realm == NULL) {
914
        ThrowOOME(env, "Can't allocate memory for realm");
915
        return NULL;
916
    }
917
    wcsncpy(realm, domainName.Buffer, domainName.Length/sizeof(WCHAR));
918

919
    if (native_debug) {
920
        fprintf(stderr, "LSA: Principal domain is %S\n", realm);
921
        fprintf(stderr, "LSA: Name type is %x\n", principalName->NameType);
922
        fprintf(stderr, "LSA: Name count is %x\n", principalName->NameCount);
923
    }
924

925
    nameCount = principalName->NameCount;
926
    stringArray = (*env)->NewObjectArray(env, nameCount,
927
                            javaLangStringClass, NULL);
928
    if (stringArray == NULL) {
929
        if (native_debug) {
930
            fprintf(stderr, "LSA: Can't allocate String array for Principal\n");
931
        }
932
        goto cleanup;
933
    }
934

935
    for (i=0; i<nameCount; i++) {
936
        // get the principal name
937
        scanner = &(principalName->Names[i]);
938

939
        // OK, got a Char array, so construct a String
940
        tempString = (*env)->NewString(env, (const jchar*)scanner->Buffer,
941
                            scanner->Length/sizeof(WCHAR));
942

943
        if (tempString == NULL) {
944
            goto cleanup;
945
        }
946

947
        // Set the String into the StringArray
948
        (*env)->SetObjectArrayElement(env, stringArray, i, tempString);
949

950
        if ((*env)->ExceptionCheck(env)) {
951
            goto cleanup;
952
        }
953

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

960
    if (realmStr == NULL) {
961
        goto cleanup;
962
    }
963

964
    principal = (*env)->NewObject(env, principalNameClass,
965
                    principalNameConstructor, stringArray, realmStr);
966

967
cleanup:
968
    // free local resources
969
    LocalFree(realm);
970

971
    return principal;
972
}
973

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

980
    for (i=0; i<cryptoKey->Length; i++) {
981
        if (cryptoKey->Value[i]) break;
982
    }
983
    if (i == cryptoKey->Length) {
984
        if (native_debug) {
985
            fprintf(stderr, "LSA: Session key all zero. Stop.\n");
986
        }
987
        return NULL;
988
    }
989

990
    ary = (*env)->NewByteArray(env,cryptoKey->Length);
991
    if (ary == NULL) {
992
        return (jobject) NULL;
993
    }
994
    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, cryptoKey->Length,
995
                                    (jbyte *)cryptoKey->Value);
996
    if ((*env)->ExceptionOccurred(env)) {
997
        (*env)->DeleteLocalRef(env, ary);
998
    } else {
999
        encryptionKey = (*env)->NewObject(env, encryptionKeyClass,
1000
                encryptionKeyConstructor, cryptoKey->KeyType, ary);
1001
    }
1002

1003
    return encryptionKey;
1004
}
1005

1006
jobject BuildTicketFlags(JNIEnv *env, PULONG flags) {
1007
    jobject ticketFlags = NULL;
1008
    jbyteArray ary;
1009
    /*
1010
     * mdu: Convert the bytes to network byte order before copying
1011
     * them to a Java byte array.
1012
     */
1013
    ULONG nlflags = htonl(*flags);
1014

1015
    ary = (*env)->NewByteArray(env, sizeof(*flags));
1016
    if (ary == NULL) {
1017
        return (jobject) NULL;
1018
    }
1019
    (*env)->SetByteArrayRegion(env, ary, (jsize) 0, sizeof(*flags),
1020
                                    (jbyte *)&nlflags);
1021
    if ((*env)->ExceptionOccurred(env)) {
1022
        (*env)->DeleteLocalRef(env, ary);
1023
    } else {
1024
        ticketFlags = (*env)->NewObject(env, ticketFlagsClass,
1025
                ticketFlagsConstructor, sizeof(*flags)*8, ary);
1026
    }
1027

1028
    return ticketFlags;
1029
}
1030

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

1042
    if (FileTimeToSystemTime((FILETIME *)kerbtime, &systemTime)) {
1043
        // XXX Cannot use %02.2ld, because the leading 0 is ignored for integers.
1044
        // So, print them to strings, and then print them to the master string with a
1045
        // format pattern that makes it two digits and prefix with a 0 if necessary.
1046
        swprintf( (wchar_t *)month, 3, L"%2.2d", systemTime.wMonth);
1047
        swprintf( (wchar_t *)day, 3, L"%2.2d", systemTime.wDay);
1048
        swprintf( (wchar_t *)hour, 3, L"%2.2d", systemTime.wHour);
1049
        swprintf( (wchar_t *)minute, 3, L"%2.2d", systemTime.wMinute);
1050
        swprintf( (wchar_t *)second, 3, L"%2.2d", systemTime.wSecond);
1051
        swprintf( (wchar_t *)timeString, 16,
1052
                L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",
1053
                systemTime.wYear,
1054
                month,
1055
                day,
1056
                hour,
1057
                minute,
1058
                second );
1059
        if (native_debug) {
1060
            fprintf(stderr, "LSA: %S\n", (wchar_t *)timeString);
1061
        }
1062
        stringTime = (*env)->NewString(env, timeString,
1063
                (sizeof(timeString)/sizeof(WCHAR))-1);
1064
        if (stringTime != NULL) { // everything's OK so far
1065
            kerberosTime = (*env)->NewObject(env, kerberosTimeClass,
1066
                    kerberosTimeConstructor, stringTime);
1067
        }
1068
    }
1069
    return kerberosTime;
1070
}
1071

1072
void ThrowOOME(JNIEnv *env, const char *szMessage) {
1073
    jclass exceptionClazz = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
1074
    if (exceptionClazz != NULL) {
1075
        (*env)->ThrowNew(env, exceptionClazz, szMessage);
1076
    }
1077
}
1078

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.