0N/A/*
3752N/A * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A * ===========================================================================
0N/A * (C) Copyright IBM Corp. 2000 All Rights Reserved.
0N/A * ===========================================================================
0N/A */
0N/A
0N/A#define UNICODE
0N/A#define _UNICODE
0N/A
0N/A#include <windows.h>
0N/A#include <stdio.h>
0N/A#include <string.h>
0N/A#define SECURITY_WIN32
0N/A#include <security.h>
0N/A#include <ntsecapi.h>
0N/A#include <dsgetdc.h>
0N/A#include <lmcons.h>
0N/A#include <lmapibuf.h>
0N/A#include <jni.h>
0N/A#include <winsock.h>
0N/A
0N/A#undef LSA_SUCCESS
0N/A#define LSA_SUCCESS(Status) ((Status) >= 0)
0N/A#define EXIT_FAILURE -1 // mdu
0N/A
0N/A/*
0N/A * Library-wide static references
0N/A */
0N/A
0N/Ajclass derValueClass = NULL;
0N/Ajclass ticketClass = NULL;
0N/Ajclass principalNameClass = NULL;
0N/Ajclass encryptionKeyClass = NULL;
0N/Ajclass ticketFlagsClass = NULL;
0N/Ajclass kerberosTimeClass = NULL;
0N/Ajclass javaLangStringClass = NULL;
0N/A
0N/AjmethodID derValueConstructor = 0;
0N/AjmethodID ticketConstructor = 0;
0N/AjmethodID principalNameConstructor = 0;
0N/AjmethodID encryptionKeyConstructor = 0;
0N/AjmethodID ticketFlagsConstructor = 0;
0N/AjmethodID kerberosTimeConstructor = 0;
0N/AjmethodID krbcredsConstructor = 0;
0N/AjmethodID setRealmMethod = 0;
0N/A
0N/A/*
0N/A * Function prototypes for internal routines
0N/A *
0N/A */
1106N/ABOOL native_debug = 0;
0N/A
0N/ABOOL PackageConnectLookup(PHANDLE,PULONG);
0N/A
0N/ANTSTATUS ConstructTicketRequest(UNICODE_STRING DomainName,
0N/A PKERB_RETRIEVE_TKT_REQUEST *outRequest,
0N/A ULONG *outSize);
0N/A
0N/ADWORD ConcatenateUnicodeStrings(UNICODE_STRING *pTarget,
0N/A UNICODE_STRING Source1,
0N/A UNICODE_STRING Source2);
0N/A
0N/AVOID ShowNTError(LPSTR,NTSTATUS);
0N/A
0N/AVOID
0N/AInitUnicodeString(
50N/A PUNICODE_STRING DestinationString,
0N/A PCWSTR SourceString OPTIONAL
50N/A);
0N/A
0N/Ajobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize);
0N/A
0N/A//mdu
0N/Ajobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,
0N/A UNICODE_STRING domainName);
0N/A
0N/Ajobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey);
0N/Ajobject BuildTicketFlags(JNIEnv *env, PULONG flags);
0N/Ajobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime);
0N/A
0N/A/*
0N/A * Class: sun_security_krb5_KrbCreds
0N/A * Method: JNI_OnLoad
0N/A */
0N/A
0N/AJNIEXPORT jint JNICALL JNI_OnLoad(
50N/A JavaVM *jvm,
50N/A void *reserved) {
0N/A
50N/A jclass cls;
50N/A JNIEnv *env;
1103N/A jfieldID fldDEBUG;
0N/A
50N/A if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
50N/A return JNI_EVERSION; /* JNI version not supported */
50N/A }
0N/A
1103N/A cls = (*env)->FindClass(env,"sun/security/krb5/internal/Krb5");
1103N/A if (cls == NULL) {
1103N/A printf("LSA: Couldn't find Krb5\n");
1103N/A return JNI_ERR;
1103N/A }
1103N/A fldDEBUG = (*env)->GetStaticFieldID(env, cls, "DEBUG", "Z");
1103N/A if (fldDEBUG == NULL) {
1103N/A printf("LSA: Krb5 has no DEBUG field\n");
1103N/A return JNI_ERR;
1103N/A }
1106N/A native_debug = (*env)->GetStaticBooleanField(env, cls, fldDEBUG);
1103N/A
50N/A cls = (*env)->FindClass(env,"sun/security/krb5/internal/Ticket");
0N/A
50N/A if (cls == NULL) {
1103N/A printf("LSA: Couldn't find Ticket\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found Ticket\n");
1106N/A }
0N/A
50N/A ticketClass = (*env)->NewWeakGlobalRef(env,cls);
50N/A if (ticketClass == NULL) {
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Made NewWeakGlobalRef\n");
1106N/A }
0N/A
50N/A cls = (*env)->FindClass(env, "sun/security/krb5/PrincipalName");
0N/A
50N/A if (cls == NULL) {
1103N/A printf("LSA: Couldn't find PrincipalName\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found PrincipalName\n");
1106N/A }
0N/A
50N/A principalNameClass = (*env)->NewWeakGlobalRef(env,cls);
50N/A if (principalNameClass == NULL) {
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Made NewWeakGlobalRef\n");
1106N/A }
0N/A
50N/A cls = (*env)->FindClass(env,"sun/security/util/DerValue");
0N/A
50N/A if (cls == NULL) {
1103N/A printf("LSA: Couldn't find DerValue\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found DerValue\n");
1106N/A }
0N/A
50N/A derValueClass = (*env)->NewWeakGlobalRef(env,cls);
50N/A if (derValueClass == NULL) {
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Made NewWeakGlobalRef\n");
1106N/A }
0N/A
50N/A cls = (*env)->FindClass(env,"sun/security/krb5/EncryptionKey");
0N/A
50N/A if (cls == NULL) {
1103N/A printf("LSA: Couldn't find EncryptionKey\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found EncryptionKey\n");
1106N/A }
0N/A
50N/A encryptionKeyClass = (*env)->NewWeakGlobalRef(env,cls);
50N/A if (encryptionKeyClass == NULL) {
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Made NewWeakGlobalRef\n");
1106N/A }
0N/A
50N/A cls = (*env)->FindClass(env,"sun/security/krb5/internal/TicketFlags");
0N/A
50N/A if (cls == NULL) {
1103N/A printf("LSA: Couldn't find TicketFlags\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found TicketFlags\n");
1106N/A }
0N/A
50N/A ticketFlagsClass = (*env)->NewWeakGlobalRef(env,cls);
50N/A if (ticketFlagsClass == NULL) {
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Made NewWeakGlobalRef\n");
1106N/A }
0N/A
50N/A cls = (*env)->FindClass(env,"sun/security/krb5/internal/KerberosTime");
0N/A
50N/A if (cls == NULL) {
1103N/A printf("LSA: Couldn't find KerberosTime\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found KerberosTime\n");
1106N/A }
0N/A
50N/A kerberosTimeClass = (*env)->NewWeakGlobalRef(env,cls);
50N/A if (kerberosTimeClass == NULL) {
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Made NewWeakGlobalRef\n");
1106N/A }
0N/A
50N/A cls = (*env)->FindClass(env,"java/lang/String");
0N/A
50N/A if (cls == NULL) {
1103N/A printf("LSA: Couldn't find String\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found String\n");
1106N/A }
0N/A
50N/A javaLangStringClass = (*env)->NewWeakGlobalRef(env,cls);
50N/A if (javaLangStringClass == NULL) {
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Made NewWeakGlobalRef\n");
1106N/A }
0N/A
50N/A derValueConstructor = (*env)->GetMethodID(env, derValueClass,
50N/A "<init>", "([B)V");
50N/A if (derValueConstructor == 0) {
1103N/A printf("LSA: Couldn't find DerValue constructor\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found DerValue constructor\n");
1106N/A }
0N/A
50N/A ticketConstructor = (*env)->GetMethodID(env, ticketClass,
50N/A "<init>", "(Lsun/security/util/DerValue;)V");
50N/A if (ticketConstructor == 0) {
1103N/A printf("LSA: Couldn't find Ticket constructor\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found Ticket constructor\n");
1106N/A }
0N/A
50N/A principalNameConstructor = (*env)->GetMethodID(env, principalNameClass,
50N/A "<init>", "([Ljava/lang/String;)V");
50N/A if (principalNameConstructor == 0) {
1103N/A printf("LSA: Couldn't find PrincipalName constructor\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found PrincipalName constructor\n");
1106N/A }
0N/A
50N/A encryptionKeyConstructor = (*env)->GetMethodID(env, encryptionKeyClass,
50N/A "<init>", "(I[B)V");
50N/A if (encryptionKeyConstructor == 0) {
1103N/A printf("LSA: Couldn't find EncryptionKey constructor\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found EncryptionKey constructor\n");
1106N/A }
0N/A
50N/A ticketFlagsConstructor = (*env)->GetMethodID(env, ticketFlagsClass,
50N/A "<init>", "(I[B)V");
50N/A if (ticketFlagsConstructor == 0) {
1103N/A printf("LSA: Couldn't find TicketFlags constructor\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found TicketFlags constructor\n");
1106N/A }
0N/A
50N/A kerberosTimeConstructor = (*env)->GetMethodID(env, kerberosTimeClass,
50N/A "<init>", "(Ljava/lang/String;)V");
50N/A if (kerberosTimeConstructor == 0) {
1103N/A printf("LSA: Couldn't find KerberosTime constructor\n");
50N/A return JNI_ERR;
50N/A }
1106N/A if (native_debug) {
1103N/A printf("LSA: Found KerberosTime constructor\n");
1106N/A }
0N/A
50N/A // load the setRealm method in PrincipalName
50N/A setRealmMethod = (*env)->GetMethodID(env, principalNameClass,
50N/A "setRealm", "(Ljava/lang/String;)V");
50N/A if (setRealmMethod == 0) {
1103N/A printf("LSA: Couldn't find setRealm in PrincipalName\n");
50N/A return JNI_ERR;
50N/A }
0N/A
1106N/A if (native_debug) {
1103N/A printf("LSA: Finished OnLoad processing\n");
1106N/A }
0N/A
50N/A return JNI_VERSION_1_2;
0N/A}
0N/A
0N/A/*
0N/A * Class: sun_security_jgss_KrbCreds
0N/A * Method: JNI_OnUnload
0N/A */
0N/A
0N/AJNIEXPORT void JNICALL JNI_OnUnload(
50N/A JavaVM *jvm,
50N/A void *reserved) {
0N/A
50N/A JNIEnv *env;
0N/A
50N/A if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
50N/A return; /* Nothing else we can do */
50N/A }
0N/A
50N/A if (ticketClass != NULL) {
50N/A (*env)->DeleteWeakGlobalRef(env,ticketClass);
50N/A }
50N/A if (derValueClass != NULL) {
50N/A (*env)->DeleteWeakGlobalRef(env,derValueClass);
50N/A }
50N/A if (principalNameClass != NULL) {
50N/A (*env)->DeleteWeakGlobalRef(env,principalNameClass);
50N/A }
50N/A if (encryptionKeyClass != NULL) {
50N/A (*env)->DeleteWeakGlobalRef(env,encryptionKeyClass);
50N/A }
50N/A if (ticketFlagsClass != NULL) {
50N/A (*env)->DeleteWeakGlobalRef(env,ticketFlagsClass);
50N/A }
50N/A if (kerberosTimeClass != NULL) {
50N/A (*env)->DeleteWeakGlobalRef(env,kerberosTimeClass);
50N/A }
50N/A if (javaLangStringClass != NULL) {
50N/A (*env)->DeleteWeakGlobalRef(env,javaLangStringClass);
50N/A }
0N/A
50N/A return;
0N/A}
0N/A
0N/A/*
0N/A * Class: sun_security_krb5_Credentials
0N/A * Method: acquireDefaultNativeCreds
0N/A * Signature: ()Lsun/security/krb5/Credentials;
0N/A */
0N/AJNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds(
50N/A JNIEnv *env,
50N/A jclass krbcredsClass) {
0N/A
50N/A KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
50N/A PKERB_RETRIEVE_TKT_RESPONSE TktCacheResponse = NULL;
50N/A PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
50N/A PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
50N/A NTSTATUS Status, SubStatus;
50N/A ULONG requestSize = 0;
50N/A ULONG responseSize = 0;
50N/A ULONG rspSize = 0;
50N/A HANDLE LogonHandle = NULL;
50N/A ULONG PackageId;
50N/A jobject ticket, clientPrincipal, targetPrincipal, encryptionKey;
50N/A jobject ticketFlags, startTime, endTime, krbCreds = NULL;
50N/A jobject authTime, renewTillTime, hostAddresses = NULL;
50N/A KERB_EXTERNAL_TICKET *msticket;
50N/A int ignore_cache = 0;
50N/A FILETIME Now, EndTime, LocalEndTime;
0N/A
50N/A while (TRUE) {
0N/A
0N/A if (krbcredsConstructor == 0) {
50N/A krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>",
1103N/A "(Lsun/security/krb5/internal/Ticket;"
1103N/A "Lsun/security/krb5/PrincipalName;"
1103N/A "Lsun/security/krb5/PrincipalName;"
1103N/A "Lsun/security/krb5/EncryptionKey;"
1103N/A "Lsun/security/krb5/internal/TicketFlags;"
1103N/A "Lsun/security/krb5/internal/KerberosTime;"
1103N/A "Lsun/security/krb5/internal/KerberosTime;"
1103N/A "Lsun/security/krb5/internal/KerberosTime;"
1103N/A "Lsun/security/krb5/internal/KerberosTime;"
1103N/A "Lsun/security/krb5/internal/HostAddresses;)V");
0N/A if (krbcredsConstructor == 0) {
1103N/A printf("LSA: Couldn't find sun.security.krb5.Credentials constructor\n");
0N/A break;
0N/A }
0N/A }
0N/A
1106N/A if (native_debug) {
1103N/A printf("LSA: Found KrbCreds constructor\n");
1103N/A }
0N/A
0N/A //
0N/A // Get the logon handle and package ID from the
0N/A // Kerberos package
0N/A //
0N/A if (!PackageConnectLookup(&LogonHandle, &PackageId))
0N/A break;
0N/A
1106N/A if (native_debug) {
1103N/A printf("LSA: Got handle to Kerberos package\n");
1106N/A }
0N/A
0N/A // Get the MS TGT from cache
0N/A CacheRequest.MessageType = KerbRetrieveTicketMessage;
0N/A CacheRequest.LogonId.LowPart = 0;
0N/A CacheRequest.LogonId.HighPart = 0;
0N/A
0N/A Status = LsaCallAuthenticationPackage(
0N/A LogonHandle,
0N/A PackageId,
0N/A &CacheRequest,
0N/A sizeof(CacheRequest),
0N/A &TktCacheResponse,
0N/A &rspSize,
0N/A &SubStatus
0N/A );
0N/A
1106N/A if (native_debug) {
1103N/A printf("LSA: Response size is %d\n", rspSize);
1103N/A }
0N/A
0N/A if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {
0N/A if (!LSA_SUCCESS(Status)) {
0N/A ShowNTError("LsaCallAuthenticationPackage", Status);
0N/A } else {
0N/A ShowNTError("Protocol status", SubStatus);
0N/A }
0N/A break;
0N/A }
0N/A
0N/A // got the native MS TGT
0N/A msticket = &(TktCacheResponse->Ticket);
0N/A
0N/A // check TGT validity
0N/A switch (msticket->SessionKey.KeyType) {
0N/A case KERB_ETYPE_DES_CBC_CRC:
0N/A case KERB_ETYPE_DES_CBC_MD5:
0N/A case KERB_ETYPE_NULL:
0N/A case KERB_ETYPE_RC4_HMAC_NT:
0N/A GetSystemTimeAsFileTime(&Now);
0N/A EndTime.dwLowDateTime = msticket->EndTime.LowPart;
0N/A EndTime.dwHighDateTime = msticket->EndTime.HighPart;
0N/A FileTimeToLocalFileTime(&EndTime, &LocalEndTime);
0N/A if (CompareFileTime(&Now, &LocalEndTime) >= 0) {
0N/A ignore_cache = 1;
0N/A }
0N/A if (msticket->TicketFlags & KERB_TICKET_FLAGS_invalid) {
0N/A ignore_cache = 1;
0N/A }
0N/A break;
0N/A case KERB_ETYPE_RC4_MD4:
0N/A default:
0N/A // not supported
0N/A ignore_cache = 1;
0N/A break;
0N/A }
0N/A
0N/A if (ignore_cache) {
1106N/A if (native_debug) {
1103N/A printf("LSA: MS TGT in cache is invalid/not supported; request new ticket\n");
1106N/A }
0N/A
0N/A // use domain to request Ticket
0N/A Status = ConstructTicketRequest(msticket->TargetDomainName,
0N/A &pTicketRequest, &requestSize);
0N/A if (!LSA_SUCCESS(Status)) {
0N/A ShowNTError("ConstructTicketRequest status", Status);
0N/A break;
0N/A }
0N/A
0N/A pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
0N/A pTicketRequest->EncryptionType = KERB_ETYPE_DES_CBC_MD5;
0N/A pTicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_DONT_USE_CACHE;
0N/A
0N/A Status = LsaCallAuthenticationPackage(
0N/A LogonHandle,
0N/A PackageId,
0N/A pTicketRequest,
0N/A requestSize,
0N/A &pTicketResponse,
0N/A &responseSize,
0N/A &SubStatus
0N/A );
0N/A
1106N/A if (native_debug) {
1103N/A printf("LSA: Response size is %d\n", responseSize);
1106N/A }
0N/A
0N/A if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {
0N/A if (!LSA_SUCCESS(Status)) {
0N/A ShowNTError("LsaCallAuthenticationPackage", Status);
0N/A } else {
0N/A ShowNTError("Protocol status", SubStatus);
0N/A }
0N/A break;
0N/A }
0N/A
0N/A // got the native MS Kerberos TGT
0N/A msticket = &(pTicketResponse->Ticket);
0N/A }
0N/A
50N/A /*
0N/A
50N/A typedef struct _KERB_RETRIEVE_TKT_RESPONSE {
50N/A KERB_EXTERNAL_TICKET Ticket;
50N/A } KERB_RETRIEVE_TKT_RESPONSE, *PKERB_RETRIEVE_TKT_RESPONSE;
0N/A
50N/A typedef struct _KERB_EXTERNAL_TICKET {
50N/A PKERB_EXTERNAL_NAME ServiceName;
50N/A PKERB_EXTERNAL_NAME TargetName;
50N/A PKERB_EXTERNAL_NAME ClientName;
50N/A UNICODE_STRING DomainName;
50N/A UNICODE_STRING TargetDomainName;
50N/A UNICODE_STRING AltTargetDomainName;
50N/A KERB_CRYPTO_KEY SessionKey;
50N/A ULONG TicketFlags;
50N/A ULONG Flags;
50N/A LARGE_INTEGER KeyExpirationTime;
50N/A LARGE_INTEGER StartTime;
50N/A LARGE_INTEGER EndTime;
50N/A LARGE_INTEGER RenewUntil;
50N/A LARGE_INTEGER TimeSkew;
50N/A ULONG EncodedTicketSize;
50N/A PUCHAR EncodedTicket; <========== Here's the good stuff
50N/A } KERB_EXTERNAL_TICKET, *PKERB_EXTERNAL_TICKET;
0N/A
50N/A typedef struct _KERB_EXTERNAL_NAME {
50N/A SHORT NameType;
50N/A USHORT NameCount;
50N/A UNICODE_STRING Names[ANYSIZE_ARRAY];
50N/A } KERB_EXTERNAL_NAME, *PKERB_EXTERNAL_NAME;
0N/A
50N/A typedef struct _LSA_UNICODE_STRING {
50N/A USHORT Length;
50N/A USHORT MaximumLength;
50N/A PWSTR Buffer;
50N/A } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;
0N/A
50N/A typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;
0N/A
50N/A typedef struct KERB_CRYPTO_KEY {
50N/A LONG KeyType;
50N/A ULONG Length;
50N/A PUCHAR Value;
50N/A } KERB_CRYPTO_KEY, *PKERB_CRYPTO_KEY;
0N/A
50N/A */
0N/A // Build a com.sun.security.krb5.Ticket
0N/A ticket = BuildTicket(env, msticket->EncodedTicket,
0N/A msticket->EncodedTicketSize);
0N/A if (ticket == NULL) {
50N/A break;
0N/A }
0N/A // OK, have a Ticket, now need to get the client name
0N/A clientPrincipal = BuildPrincipal(env, msticket->ClientName,
0N/A msticket->TargetDomainName); // mdu
0N/A if (clientPrincipal == NULL) {
50N/A break;
0N/A }
0N/A
0N/A // and the "name" of tgt
0N/A targetPrincipal = BuildPrincipal(env, msticket->ServiceName,
0N/A msticket->DomainName);
0N/A if (targetPrincipal == NULL) {
50N/A break;
0N/A }
0N/A
0N/A // Get the encryption key
0N/A encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey));
0N/A if (encryptionKey == NULL) {
50N/A break;
0N/A }
0N/A
0N/A // and the ticket flags
0N/A ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags));
0N/A if (ticketFlags == NULL) {
50N/A break;
0N/A }
0N/A
0N/A // Get the start time
0N/A startTime = BuildKerberosTime(env, &(msticket->StartTime));
0N/A if (startTime == NULL) {
50N/A break;
0N/A }
0N/A
0N/A /*
0N/A * mdu: No point storing the eky expiration time in the auth
0N/A * time field. Set it to be same as startTime. Looks like
0N/A * windows does not have post-dated tickets.
0N/A */
0N/A authTime = startTime;
0N/A
0N/A // and the end time
0N/A endTime = BuildKerberosTime(env, &(msticket->EndTime));
0N/A if (endTime == NULL) {
50N/A break;
0N/A }
0N/A
0N/A // Get the renew till time
0N/A renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil));
0N/A if (renewTillTime == NULL) {
50N/A break;
0N/A }
0N/A
0N/A // and now go build a KrbCreds object
0N/A krbCreds = (*env)->NewObject(
0N/A env,
0N/A krbcredsClass,
0N/A krbcredsConstructor,
0N/A ticket,
0N/A clientPrincipal,
0N/A targetPrincipal,
0N/A encryptionKey,
0N/A ticketFlags,
0N/A authTime, // mdu
0N/A startTime,
0N/A endTime,
0N/A renewTillTime, //mdu
0N/A hostAddresses);
0N/A
0N/A break;
50N/A } // end of WHILE
0N/A
50N/A // clean up resources
50N/A if (TktCacheResponse != NULL) {
50N/A LsaFreeReturnBuffer(TktCacheResponse);
50N/A }
50N/A if (pTicketRequest) {
50N/A LocalFree(pTicketRequest);
50N/A }
50N/A if (pTicketResponse != NULL) {
50N/A LsaFreeReturnBuffer(pTicketResponse);
50N/A }
0N/A
50N/A return krbCreds;
0N/A}
0N/A
0N/Astatic NTSTATUS
0N/AConstructTicketRequest(UNICODE_STRING DomainName,
0N/A PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize)
0N/A{
50N/A NTSTATUS Status;
50N/A UNICODE_STRING TargetPrefix;
50N/A USHORT TargetSize;
50N/A ULONG RequestSize;
50N/A ULONG Length;
50N/A PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
0N/A
50N/A *outRequest = NULL;
50N/A *outSize = 0;
0N/A
50N/A //
50N/A // Set up the "krbtgt/" target prefix into a UNICODE_STRING so we
50N/A // can easily concatenate it later.
50N/A //
0N/A
50N/A TargetPrefix.Buffer = L"krbtgt/";
50N/A Length = (ULONG)wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);
50N/A TargetPrefix.Length = (USHORT)Length;
50N/A TargetPrefix.MaximumLength = TargetPrefix.Length;
0N/A
50N/A //
50N/A // We will need to concatenate the "krbtgt/" prefix and the
50N/A // Logon Session's DnsDomainName into our request's target name.
50N/A //
50N/A // Therefore, first compute the necessary buffer size for that.
50N/A //
50N/A // Note that we might theoretically have integer overflow.
50N/A //
0N/A
50N/A TargetSize = TargetPrefix.Length + DomainName.Length;
0N/A
50N/A //
50N/A // The ticket request buffer needs to be a single buffer. That buffer
50N/A // needs to include the buffer for the target name.
50N/A //
0N/A
50N/A RequestSize = sizeof (*pTicketRequest) + TargetSize;
0N/A
50N/A //
50N/A // Allocate the request buffer and make sure it's zero-filled.
50N/A //
0N/A
50N/A pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)
50N/A LocalAlloc(LMEM_ZEROINIT, RequestSize);
50N/A if (!pTicketRequest)
50N/A return GetLastError();
0N/A
50N/A //
50N/A // Concatenate the target prefix with the previous reponse's
50N/A // target domain.
50N/A //
0N/A
50N/A pTicketRequest->TargetName.Length = 0;
50N/A pTicketRequest->TargetName.MaximumLength = TargetSize;
50N/A pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
50N/A Status = ConcatenateUnicodeStrings(&(pTicketRequest->TargetName),
50N/A TargetPrefix,
50N/A DomainName);
50N/A *outRequest = pTicketRequest;
50N/A *outSize = RequestSize;
50N/A return Status;
0N/A}
0N/A
0N/ADWORD
0N/AConcatenateUnicodeStrings(
0N/A UNICODE_STRING *pTarget,
0N/A UNICODE_STRING Source1,
0N/A UNICODE_STRING Source2
0N/A )
0N/A{
50N/A //
50N/A // The buffers for Source1 and Source2 cannot overlap pTarget's
50N/A // buffer. Source1.Length + Source2.Length must be <= 0xFFFF,
50N/A // otherwise we overflow...
50N/A //
0N/A
50N/A USHORT TotalSize = Source1.Length + Source2.Length;
50N/A PBYTE buffer = (PBYTE) pTarget->Buffer;
0N/A
50N/A if (TotalSize > pTarget->MaximumLength)
50N/A return ERROR_INSUFFICIENT_BUFFER;
0N/A
50N/A pTarget->Length = TotalSize;
50N/A memcpy(buffer, Source1.Buffer, Source1.Length);
50N/A memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);
50N/A return ERROR_SUCCESS;
0N/A}
0N/A
0N/ABOOL
0N/APackageConnectLookup(
0N/A HANDLE *pLogonHandle,
0N/A ULONG *pPackageId
0N/A )
0N/A{
0N/A LSA_STRING Name;
0N/A NTSTATUS Status;
0N/A
0N/A Status = LsaConnectUntrusted(
0N/A pLogonHandle
0N/A );
0N/A
0N/A if (!LSA_SUCCESS(Status))
0N/A {
0N/A ShowNTError("LsaConnectUntrusted", Status);
0N/A return FALSE;
0N/A }
0N/A
0N/A Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
0N/A Name.Length = (USHORT)strlen(Name.Buffer);
0N/A Name.MaximumLength = Name.Length + 1;
0N/A
0N/A Status = LsaLookupAuthenticationPackage(
0N/A *pLogonHandle,
0N/A &Name,
0N/A pPackageId
0N/A );
0N/A
0N/A if (!LSA_SUCCESS(Status))
0N/A {
0N/A ShowNTError("LsaLookupAuthenticationPackage", Status);
0N/A return FALSE;
0N/A }
0N/A
0N/A return TRUE;
0N/A
0N/A}
0N/A
0N/AVOID
0N/AShowLastError(
0N/A LPSTR szAPI,
0N/A DWORD dwError
0N/A )
0N/A{
50N/A #define MAX_MSG_SIZE 256
0N/A
50N/A static WCHAR szMsgBuf[MAX_MSG_SIZE];
50N/A DWORD dwRes;
0N/A
1106N/A if (native_debug) {
1103N/A printf("LSA: Error calling function %s: %lu\n", szAPI, dwError);
1103N/A }
0N/A
50N/A dwRes = FormatMessage (
50N/A FORMAT_MESSAGE_FROM_SYSTEM,
50N/A NULL,
50N/A dwError,
50N/A 0,
50N/A szMsgBuf,
50N/A MAX_MSG_SIZE,
50N/A NULL);
1106N/A if (native_debug) {
1103N/A if (0 == dwRes) {
1103N/A printf("LSA: FormatMessage failed with %d\n", GetLastError());
1103N/A // ExitProcess(EXIT_FAILURE);
1103N/A } else {
1103N/A printf("LSA: %S",szMsgBuf);
1103N/A }
50N/A }
0N/A}
0N/A
0N/AVOID
0N/AShowNTError(
0N/A LPSTR szAPI,
0N/A NTSTATUS Status
0N/A )
0N/A{
0N/A //
0N/A // Convert the NTSTATUS to Winerror. Then call ShowLastError().
0N/A //
0N/A ShowLastError(szAPI, LsaNtStatusToWinError(Status));
0N/A}
0N/A
0N/AVOID
0N/AInitUnicodeString(
0N/A PUNICODE_STRING DestinationString,
0N/A PCWSTR SourceString OPTIONAL
0N/A )
0N/A{
0N/A ULONG Length;
0N/A
0N/A DestinationString->Buffer = (PWSTR)SourceString;
0N/A if (SourceString != NULL) {
0N/A Length = (ULONG)wcslen( SourceString ) * sizeof( WCHAR );
0N/A DestinationString->Length = (USHORT)Length;
0N/A DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
50N/A }
0N/A else {
0N/A DestinationString->MaximumLength = 0;
0N/A DestinationString->Length = 0;
50N/A }
0N/A}
0N/A
0N/Ajobject BuildTicket(JNIEnv *env, PUCHAR encodedTicket, ULONG encodedTicketSize) {
0N/A
50N/A /* To build a Ticket, we first need to build a DerValue out of the EncodedTicket.
50N/A * But before we can do that, we need to make a byte array out of the ET.
50N/A */
0N/A
50N/A jobject derValue, ticket;
50N/A jbyteArray ary;
0N/A
50N/A ary = (*env)->NewByteArray(env,encodedTicketSize);
50N/A if ((*env)->ExceptionOccurred(env)) {
50N/A return (jobject) NULL;
50N/A }
0N/A
50N/A (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicketSize,
50N/A (jbyte *)encodedTicket);
50N/A if ((*env)->ExceptionOccurred(env)) {
50N/A (*env)->DeleteLocalRef(env, ary);
50N/A return (jobject) NULL;
50N/A }
0N/A
50N/A derValue = (*env)->NewObject(env, derValueClass, derValueConstructor, ary);
50N/A if ((*env)->ExceptionOccurred(env)) {
0N/A (*env)->DeleteLocalRef(env, ary);
50N/A return (jobject) NULL;
50N/A }
50N/A
50N/A (*env)->DeleteLocalRef(env, ary);
50N/A ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, derValue);
50N/A if ((*env)->ExceptionOccurred(env)) {
0N/A (*env)->DeleteLocalRef(env, derValue);
50N/A return (jobject) NULL;
50N/A }
50N/A (*env)->DeleteLocalRef(env, derValue);
50N/A return ticket;
0N/A}
0N/A
0N/A// mdu
0N/Ajobject BuildPrincipal(JNIEnv *env, PKERB_EXTERNAL_NAME principalName,
0N/A UNICODE_STRING domainName) {
0N/A
50N/A /*
50N/A * To build the Principal, we need to get the names out of
50N/A * this goofy MS structure
50N/A */
50N/A jobject principal = NULL;
50N/A jobject realmStr = NULL;
50N/A jobjectArray stringArray;
50N/A jstring tempString;
50N/A int nameCount,i;
50N/A PUNICODE_STRING scanner;
50N/A WCHAR *realm;
50N/A ULONG realmLen;
0N/A
50N/A realm = (WCHAR *) LocalAlloc(LMEM_ZEROINIT,
50N/A ((domainName.Length)*sizeof(WCHAR) + sizeof(UNICODE_NULL)));
50N/A wcsncpy(realm, domainName.Buffer, domainName.Length/sizeof(WCHAR));
0N/A
1106N/A if (native_debug) {
1103N/A printf("LSA: Principal domain is %S\n", realm);
1103N/A printf("LSA: Name type is %x\n", principalName->NameType);
1103N/A printf("LSA: Name count is %x\n", principalName->NameCount);
1103N/A }
0N/A
50N/A nameCount = principalName->NameCount;
50N/A stringArray = (*env)->NewObjectArray(env, nameCount,
50N/A javaLangStringClass, NULL);
50N/A if (stringArray == NULL) {
1106N/A if (native_debug) {
1103N/A printf("LSA: Can't allocate String array for Principal\n");
1103N/A }
50N/A LocalFree(realm);
50N/A return principal;
50N/A }
0N/A
50N/A for (i=0; i<nameCount; i++) {
50N/A // get the principal name
50N/A scanner = &(principalName->Names[i]);
0N/A
50N/A // OK, got a Char array, so construct a String
50N/A tempString = (*env)->NewString(env, (const jchar*)scanner->Buffer,
50N/A scanner->Length/sizeof(WCHAR));
50N/A // Set the String into the StringArray
50N/A (*env)->SetObjectArrayElement(env, stringArray, i, tempString);
0N/A
50N/A // Do I have to worry about storage reclamation here?
50N/A }
50N/A principal = (*env)->NewObject(env, principalNameClass,
50N/A principalNameConstructor, stringArray);
0N/A
50N/A // now set the realm in the principal
50N/A realmLen = (ULONG)wcslen((PWCHAR)realm);
50N/A realmStr = (*env)->NewString(env, (PWCHAR)realm, (USHORT)realmLen);
50N/A (*env)->CallVoidMethod(env, principal, setRealmMethod, realmStr);
0N/A
50N/A // free local resources
50N/A LocalFree(realm);
0N/A
50N/A return principal;
0N/A}
0N/A
0N/Ajobject BuildEncryptionKey(JNIEnv *env, PKERB_CRYPTO_KEY cryptoKey) {
50N/A // First, need to build a byte array
50N/A jbyteArray ary;
50N/A jobject encryptionKey = NULL;
1103N/A unsigned int i;
1103N/A
1103N/A for (i=0; i<cryptoKey->Length; i++) {
1103N/A if (cryptoKey->Value[i]) break;
1103N/A }
1103N/A if (i == cryptoKey->Length) {
1106N/A if (native_debug) {
1103N/A printf("LSA: Session key all zero. Stop.\n");
1103N/A }
1103N/A return NULL;
1103N/A }
0N/A
50N/A ary = (*env)->NewByteArray(env,cryptoKey->Length);
50N/A (*env)->SetByteArrayRegion(env, ary, (jsize) 0, cryptoKey->Length,
50N/A (jbyte *)cryptoKey->Value);
50N/A if ((*env)->ExceptionOccurred(env)) {
50N/A (*env)->DeleteLocalRef(env, ary);
50N/A } else {
50N/A encryptionKey = (*env)->NewObject(env, encryptionKeyClass,
50N/A encryptionKeyConstructor, cryptoKey->KeyType, ary);
50N/A }
0N/A
50N/A return encryptionKey;
0N/A}
0N/A
0N/Ajobject BuildTicketFlags(JNIEnv *env, PULONG flags) {
50N/A jobject ticketFlags = NULL;
50N/A jbyteArray ary;
50N/A /*
50N/A * mdu: Convert the bytes to nework byte order before copying
50N/A * them to a Java byte array.
50N/A */
50N/A ULONG nlflags = htonl(*flags);
0N/A
50N/A ary = (*env)->NewByteArray(env, sizeof(*flags));
50N/A (*env)->SetByteArrayRegion(env, ary, (jsize) 0, sizeof(*flags),
50N/A (jbyte *)&nlflags);
50N/A if ((*env)->ExceptionOccurred(env)) {
50N/A (*env)->DeleteLocalRef(env, ary);
50N/A } else {
50N/A ticketFlags = (*env)->NewObject(env, ticketFlagsClass,
50N/A ticketFlagsConstructor, sizeof(*flags)*8, ary);
50N/A }
0N/A
50N/A return ticketFlags;
0N/A}
0N/A
0N/Ajobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) {
50N/A jobject kerberosTime = NULL;
50N/A jstring stringTime = NULL;
50N/A SYSTEMTIME systemTime;
50N/A WCHAR timeString[16];
50N/A WCHAR month[3];
50N/A WCHAR day[3];
50N/A WCHAR hour[3];
50N/A WCHAR minute[3];
50N/A WCHAR second[3];
0N/A
50N/A if (FileTimeToSystemTime((FILETIME *)kerbtime, &systemTime)) {
50N/A // XXX Cannot use %02.2ld, because the leading 0 is ignored for integers.
50N/A // So, print them to strings, and then print them to the master string with a
50N/A // format pattern that makes it two digits and prefix with a 0 if necessary.
3752N/A swprintf( (wchar_t *)month, 3, L"%2.2d", systemTime.wMonth);
3752N/A swprintf( (wchar_t *)day, 3, L"%2.2d", systemTime.wDay);
3752N/A swprintf( (wchar_t *)hour, 3, L"%2.2d", systemTime.wHour);
3752N/A swprintf( (wchar_t *)minute, 3, L"%2.2d", systemTime.wMinute);
3752N/A swprintf( (wchar_t *)second, 3, L"%2.2d", systemTime.wSecond);
3752N/A swprintf( (wchar_t *)timeString, 16,
50N/A L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",
0N/A systemTime.wYear,
0N/A month,
0N/A day,
0N/A hour,
0N/A minute,
0N/A second );
1106N/A if (native_debug) {
1103N/A printf("LSA: %S\n", (wchar_t *)timeString);
1106N/A }
50N/A stringTime = (*env)->NewString(env, timeString,
50N/A (sizeof(timeString)/sizeof(WCHAR))-1);
50N/A if (stringTime != NULL) { // everything's OK so far
50N/A kerberosTime = (*env)->NewObject(env, kerberosTimeClass,
50N/A kerberosTimeConstructor, stringTime);
0N/A }
50N/A }
50N/A return kerberosTime;
0N/A}