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