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