experiment with service ticket from LSA
diff -r a498d2817bef src/share/classes/sun/security/krb5/Credentials.java
--- a/src/share/classes/sun/security/krb5/Credentials.java Fri Apr 17 09:21:27 2009 -0700
+++ b/src/share/classes/sun/security/krb5/Credentials.java Mon May 04 10:55:39 2009 +0800
@@ -68,6 +68,8 @@
static boolean alreadyLoaded = false;
private static boolean alreadyTried = false;
private static native Credentials acquireDefaultNativeCreds();
+ public static native Credentials acquireServiceNativeCreds(
+ String service, int flag);
public Credentials(Ticket new_ticket,
PrincipalName new_client,
@@ -553,7 +555,16 @@
public static Credentials acquireServiceCreds(String service,
Credentials ccreds)
throws KrbException, IOException {
- return CredentialsUtil.acquireServiceCreds(service, ccreds);
+ if (ccreds.isZero()) {
+ Credentials creds = Credentials.acquireServiceNativeCreds(service, 0);
+ if (creds != null) {
+ return creds;
+ }
+ throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED,
+ "No service creds");
+ } else {
+ return CredentialsUtil.acquireServiceCreds(service, ccreds);
+ }
}
@@ -603,6 +614,9 @@
System.out.println(" ----Credentials end----");
}
+ public boolean isZero() {
+ return key == null || key.isZero();
+ }
static void ensureLoaded() {
java.security.AccessController.doPrivileged(
diff -r a498d2817bef src/share/classes/sun/security/krb5/EncryptionKey.java
--- a/src/share/classes/sun/security/krb5/EncryptionKey.java Fri Apr 17 09:21:27 2009 -0700
+++ b/src/share/classes/sun/security/krb5/EncryptionKey.java Mon May 04 10:55:39 2009 +0800
@@ -535,4 +535,11 @@
}
return null;
}
+
+ public boolean isZero() {
+ for (int i=0; i<keyValue.length; i++) {
+ if (keyValue[i] != 0) return false;
+ }
+ return true;
+ }
}
diff -r a498d2817bef src/share/classes/sun/security/krb5/KrbCred.java
--- a/src/share/classes/sun/security/krb5/KrbCred.java Fri Apr 17 09:21:27 2009 -0700
+++ b/src/share/classes/sun/security/krb5/KrbCred.java Mon May 04 10:55:39 2009 +0800
@@ -54,37 +54,44 @@
private Credentials creds = null;
private KerberosTime timeStamp = null;
- // Used in InitialToken with null key
+ // Used in InitialToken with null key
+ // tgt might be null
public KrbCred(Credentials tgt,
Credentials serviceTicket,
EncryptionKey key)
throws KrbException, IOException {
- PrincipalName client = tgt.getClient();
- PrincipalName tgService = tgt.getServer();
- PrincipalName server = serviceTicket.getServer();
- if (!serviceTicket.getClient().equals(client))
- throw new KrbException(Krb5.KRB_ERR_GENERIC,
- "Client principal does not match");
-
- // XXX Check Windows flag OK-TO-FORWARD-TO
-
- // Invoke TGS-REQ to get a forwarded TGT for the peer
-
+ Credentials delegatedCreds;
KDCOptions options = new KDCOptions();
options.set(KDCOptions.FORWARDED, true);
options.set(KDCOptions.FORWARDABLE, true);
- HostAddresses sAddrs = null;
- // XXX Also NT_GSS_KRB5_PRINCIPAL can be a host based principal
- // GSSName.NT_HOSTBASED_SERVICE should display with KRB_NT_SRV_HST
- if (server.getNameType() == PrincipalName.KRB_NT_SRV_HST)
- sAddrs= new HostAddresses(server);
+ if (!tgt.isZero()) {
+ PrincipalName client = tgt.getClient();
+ PrincipalName tgService = tgt.getServer();
+ PrincipalName server = serviceTicket.getServer();
+ if (!serviceTicket.getClient().equals(client))
+ throw new KrbException(Krb5.KRB_ERR_GENERIC,
+ "Client principal does not match");
- KrbTgsReq tgsReq = new KrbTgsReq(options, tgt, tgService,
- null, null, null, null, sAddrs, null, null, null);
- credMessg = createMessage(tgsReq.sendAndGetCreds(), key);
+ // XXX Check Windows flag OK-TO-FORWARD-TO
+ // Invoke TGS-REQ to get a forwarded TGT for the peer
+
+ HostAddresses sAddrs = null;
+ // XXX Also NT_GSS_KRB5_PRINCIPAL can be a host based principal
+ // GSSName.NT_HOSTBASED_SERVICE should display with KRB_NT_SRV_HST
+ if (server.getNameType() == PrincipalName.KRB_NT_SRV_HST)
+ sAddrs= new HostAddresses(server);
+
+ KrbTgsReq tgsReq = new KrbTgsReq(options, tgt, tgService,
+ null, null, null, null, sAddrs, null, null, null);
+ delegatedCreds = tgsReq.sendAndGetCreds();
+ } else {
+ delegatedCreds = Credentials.acquireServiceNativeCreds("krbtgt/MAD.LOCAL",
+ options.getInteger());
+ }
+ credMessg = createMessage(delegatedCreds, key);
obuf = credMessg.asn1Encode();
}
diff -r a498d2817bef src/share/classes/sun/security/krb5/internal/util/KerberosFlags.java
--- a/src/share/classes/sun/security/krb5/internal/util/KerberosFlags.java Fri Apr 17 09:21:27 2009 -0700
+++ b/src/share/classes/sun/security/krb5/internal/util/KerberosFlags.java Mon May 04 10:55:39 2009 +0800
@@ -89,6 +89,17 @@
return bits.toBooleanArray();
}
+ public int getInteger() {
+ int out = 0;
+ int mask = 1 << 31;
+ for (boolean b: bits.toBooleanArray()) {
+ if (b) {
+ out |= mask;
+ }
+ mask = mask >>> 1;
+ }
+ return out;
+ }
/**
* Writes the encoded data.
*
diff -r a498d2817bef src/windows/native/sun/security/krb5/NativeCreds.c
--- a/src/windows/native/sun/security/krb5/NativeCreds.c Fri Apr 17 09:21:27 2009 -0700
+++ b/src/windows/native/sun/security/krb5/NativeCreds.c Mon May 04 10:55:39 2009 +0800
@@ -373,6 +373,86 @@
return;
}
+
+jobject NativeTicketToCreds(JNIEnv *env, jclass krbcredsClass, KERB_EXTERNAL_TICKET *msticket) {
+ jobject ticket, clientPrincipal, targetPrincipal, encryptionKey;
+ jobject ticketFlags, startTime, endTime;
+ jobject authTime, renewTillTime, hostAddresses = NULL;
+
+ // Build a com.sun.security.krb5.Ticket
+ ticket = BuildTicket(env, msticket->EncodedTicket,
+ msticket->EncodedTicketSize);
+ if (ticket == NULL) {
+ return NULL;
+ }
+ // OK, have a Ticket, now need to get the client name
+ clientPrincipal = BuildPrincipal(env, msticket->ClientName,
+ msticket->TargetDomainName); // mdu
+ if (clientPrincipal == NULL) {
+ return NULL;
+ }
+
+ // and the "name" of tgt
+ targetPrincipal = BuildPrincipal(env, msticket->ServiceName,
+ msticket->DomainName);
+ if (targetPrincipal == NULL) {
+ return NULL;
+ }
+
+ // Get the encryption key
+ encryptionKey = BuildEncryptionKey(env, &(msticket->SessionKey));
+ if (encryptionKey == NULL) {
+ return NULL;
+ }
+
+ // and the ticket flags
+ ticketFlags = BuildTicketFlags(env, &(msticket->TicketFlags));
+ if (ticketFlags == NULL) {
+ return NULL;
+ }
+
+ // Get the start time
+ startTime = BuildKerberosTime(env, &(msticket->StartTime));
+ if (startTime == NULL) {
+ return NULL;
+ }
+
+ /*
+ * 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) {
+ return NULL;
+ }
+
+ // Get the renew till time
+ renewTillTime = BuildKerberosTime(env, &(msticket->RenewUntil));
+ if (renewTillTime == NULL) {
+ return NULL;
+ }
+
+ // and now go build a KrbCreds object
+ return (*env)->NewObject(
+ env,
+ krbcredsClass,
+ krbcredsConstructor,
+ ticket,
+ clientPrincipal,
+ targetPrincipal,
+ encryptionKey,
+ ticketFlags,
+ authTime, // mdu
+ startTime,
+ endTime,
+ renewTillTime, //mdu
+ hostAddresses);
+}
+
/*
* Class: sun_security_krb5_Credentials
* Method: acquireDefaultNativeCreds
@@ -392,9 +472,7 @@
ULONG rspSize = 0;
HANDLE LogonHandle = NULL;
ULONG PackageId;
- jobject ticket, clientPrincipal, targetPrincipal, encryptionKey;
- jobject ticketFlags, startTime, endTime, krbCreds = NULL;
- jobject authTime, renewTillTime, hostAddresses = NULL;
+ jobject krbCreds = NULL;
KERB_EXTERNAL_TICKET *msticket;
int ignore_cache = 0;
FILETIME Now, EndTime, LocalEndTime;
@@ -471,6 +549,7 @@
case KERB_ETYPE_DES_CBC_MD5:
case KERB_ETYPE_NULL:
case KERB_ETYPE_RC4_HMAC_NT:
+ case 17: case 18:
GetSystemTimeAsFileTime(&Now);
EndTime.dwLowDateTime = msticket->EndTime.LowPart;
EndTime.dwHighDateTime = msticket->EndTime.HighPart;
@@ -503,7 +582,7 @@
}
pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
- pTicketRequest->EncryptionType = KERB_ETYPE_DES_CBC_MD5;
+ pTicketRequest->EncryptionType = 0;//KERB_ETYPE_DES_CBC_MD5;
pTicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_DONT_USE_CACHE;
Status = LsaCallAuthenticationPackage(
@@ -533,124 +612,7 @@
msticket = &(pTicketResponse->Ticket);
}
- /*
-
- 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;
-
- */
- // 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);
+ krbCreds = NativeTicketToCreds(env, krbcredsClass, msticket);
break;
} // end of WHILE
@@ -669,6 +631,118 @@
return krbCreds;
}
+JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireServiceNativeCreds(
+ JNIEnv *env,
+ jclass krbcredsClass,
+ jstring principal,
+ jint flag) {
+
+ 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;
+ KERB_EXTERNAL_TICKET *msticket;
+ jobject krbCreds = NULL;
+ PWSTR pName;
+ ULONG Length;
+
+ 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;
+ }
+ }
+
+ //
+ // Get the logon handle and package ID from the
+ // Kerberos package
+ //
+ if (!PackageConnectLookup(&LogonHandle, &PackageId))
+ break;
+
+ pName = (PWSTR)((*env)->GetStringChars(env, principal, NULL));
+ Length = (ULONG)wcslen(pName) * sizeof(WCHAR);
+
+ requestSize = sizeof (*pTicketRequest) + Length;
+ pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST)
+ LocalAlloc(LMEM_ZEROINIT, requestSize);
+
+ pTicketRequest->TicketFlags = flag;
+ pTicketRequest->TargetName.Length = (USHORT)Length;
+ pTicketRequest->TargetName.MaximumLength = (USHORT)Length;
+ pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
+ memcpy(pTicketRequest->TargetName.Buffer, pName, Length);
+
+ (*env)->ReleaseStringChars(env, principal, pName);
+
+ pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
+ pTicketRequest->EncryptionType = 0;//KERB_ETYPE_RC4_HMAC_NT;
+ pTicketRequest->CacheOptions = 0;
+
+ if (native_debug) {
+ printf("LSA: LsaCallAuthenticationPackage for service ticket\n");
+ }
+ Status = LsaCallAuthenticationPackage(
+ LogonHandle,
+ PackageId,
+ pTicketRequest,
+ requestSize,
+ &pTicketResponse,
+ &responseSize,
+ &SubStatus
+ );
+
+ if (native_debug) {
+ printf("LSA: Response size is %d\n", responseSize);
+ }
+
+ if (!LSA_SUCCESS(Status) || !LSA_SUCCESS(SubStatus)) {
+ if (!LSA_SUCCESS(Status)) {
+ ShowNTError("LsaCallAuthenticationPackage", Status);
+ } else {
+ ShowNTError("Protocol status", SubStatus);
+ }
+ break;
+ }
+
+ msticket = &(pTicketResponse->Ticket);
+ krbCreds = NativeTicketToCreds(env, krbcredsClass, msticket);
+
+ if (native_debug) {
+ printf("LSA: native service ticket OK\n");
+ }
+
+ break;
+ } // end of WHILE
+
+ // clean up resources
+ if (pTicketRequest) {
+ LocalFree(pTicketRequest);
+ }
+ if (pTicketResponse != NULL) {
+ LsaFreeReturnBuffer(pTicketResponse);
+ }
+
+ return krbCreds;
+}
+
static NTSTATUS
ConstructTicketRequest(UNICODE_STRING DomainName,
PKERB_RETRIEVE_TKT_REQUEST *outRequest, ULONG *outSize)
@@ -972,16 +1046,6 @@
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);