1 /* 2 * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #import "sun_security_krb5_Credentials.h" 27 #import <Kerberos/Kerberos.h> 28 #import <string.h> 29 #import <time.h> 30 31 /* 32 * Based largely on klist.c, 33 * 34 * Created by Scott Kovatch on 8/12/04. 35 * 36 * See http://www.opensource.apple.com/darwinsource/10.3.3/Kerberos-47/KerberosClients/klist/Sources/klist.c 37 38 */ 39 40 /* 41 * Statics for this module 42 */ 43 44 static jclass derValueClass = NULL; 45 static jclass ticketClass = NULL; 46 static jclass principalNameClass = NULL; 47 static jclass encryptionKeyClass = NULL; 48 static jclass ticketFlagsClass = NULL; 49 static jclass kerberosTimeClass = NULL; 50 static jclass javaLangStringClass = NULL; 51 static jclass javaLangIntegerClass = NULL; 52 static jclass hostAddressClass = NULL; 53 static jclass hostAddressesClass = NULL; 54 55 static jmethodID derValueConstructor = 0; 56 static jmethodID ticketConstructor = 0; 57 static jmethodID principalNameConstructor = 0; 58 static jmethodID encryptionKeyConstructor = 0; 59 static jmethodID ticketFlagsConstructor = 0; 60 static jmethodID kerberosTimeConstructor = 0; 61 static jmethodID krbcredsConstructor = 0; 62 static jmethodID integerConstructor = 0; 63 static jmethodID hostAddressConstructor = 0; 64 static jmethodID hostAddressesConstructor = 0; 65 66 /* 67 * Function prototypes for internal routines 68 */ 69 70 static jobject BuildTicket(JNIEnv *env, krb5_data *encodedTicket); 71 static jobject BuildClientPrincipal(JNIEnv *env, krb5_context kcontext, krb5_principal principalName); 72 static jobject BuildEncryptionKey(JNIEnv *env, krb5_keyblock *cryptoKey); 73 static jobject BuildTicketFlags(JNIEnv *env, krb5_flags flags); 74 static jobject BuildKerberosTime(JNIEnv *env, krb5_timestamp kerbtime); 75 static jobject BuildAddressList(JNIEnv *env, krb5_address **kerbtime); 76 77 static void printiferr (errcode_t err, const char *format, ...); 78 79 static jclass FindClass(JNIEnv *env, char *className) 80 { 81 jclass cls = (*env)->FindClass(env, className); 82 83 if (cls == NULL) { 84 printf("Couldn't find %s\n", className); 85 return NULL; 86 } 87 #ifdef DEBUG 88 printf("Found %s\n", className); 89 #endif /* DEBUG */ 90 91 jobject returnValue = (*env)->NewWeakGlobalRef(env,cls); 92 return returnValue; 93 } 94 /* 95 * Class: sun_security_krb5_KrbCreds 96 * Method: JNI_OnLoad 97 */ 98 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) 99 { 100 JNIEnv *env; 101 102 if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) { 103 return JNI_EVERSION; /* JNI version not supported */ 104 } 105 106 ticketClass = FindClass(env, "sun/security/krb5/internal/Ticket"); 107 if (ticketClass == NULL) return JNI_ERR; 108 109 principalNameClass = FindClass(env, "sun/security/krb5/PrincipalName"); 110 if (principalNameClass == NULL) return JNI_ERR; 111 112 derValueClass = FindClass(env, "sun/security/util/DerValue"); 113 if (derValueClass == NULL) return JNI_ERR; 114 115 encryptionKeyClass = FindClass(env, "sun/security/krb5/EncryptionKey"); 116 if (encryptionKeyClass == NULL) return JNI_ERR; 117 118 ticketFlagsClass = FindClass(env,"sun/security/krb5/internal/TicketFlags"); 119 if (ticketFlagsClass == NULL) return JNI_ERR; 120 121 kerberosTimeClass = FindClass(env,"sun/security/krb5/internal/KerberosTime"); 122 if (kerberosTimeClass == NULL) return JNI_ERR; 123 124 javaLangStringClass = FindClass(env,"java/lang/String"); 125 if (javaLangStringClass == NULL) return JNI_ERR; 126 127 javaLangIntegerClass = FindClass(env,"java/lang/Integer"); 128 if (javaLangIntegerClass == NULL) return JNI_ERR; 129 130 hostAddressClass = FindClass(env,"sun/security/krb5/internal/HostAddress"); 131 if (hostAddressClass == NULL) return JNI_ERR; 132 133 hostAddressesClass = FindClass(env,"sun/security/krb5/internal/HostAddresses"); 134 if (hostAddressesClass == NULL) return JNI_ERR; 135 136 derValueConstructor = (*env)->GetMethodID(env, derValueClass, "<init>", "([B)V"); 137 if (derValueConstructor == 0) { 138 printf("Couldn't find DerValue constructor\n"); 139 return JNI_ERR; 140 } 141 #ifdef DEBUG 142 printf("Found DerValue constructor\n"); 143 #endif /* DEBUG */ 144 145 ticketConstructor = (*env)->GetMethodID(env, ticketClass, "<init>", "(Lsun/security/util/DerValue;)V"); 146 if (ticketConstructor == 0) { 147 printf("Couldn't find Ticket constructor\n"); 148 return JNI_ERR; 149 } 150 #ifdef DEBUG 151 printf("Found Ticket constructor\n"); 152 #endif /* DEBUG */ 153 154 principalNameConstructor = (*env)->GetMethodID(env, principalNameClass, "<init>", "(Ljava/lang/String;I)V"); 155 if (principalNameConstructor == 0) { 156 printf("Couldn't find PrincipalName constructor\n"); 157 return JNI_ERR; 158 } 159 #ifdef DEBUG 160 printf("Found PrincipalName constructor\n"); 161 #endif /* DEBUG */ 162 163 encryptionKeyConstructor = (*env)->GetMethodID(env, encryptionKeyClass, "<init>", "(I[B)V"); 164 if (encryptionKeyConstructor == 0) { 165 printf("Couldn't find EncryptionKey constructor\n"); 166 return JNI_ERR; 167 } 168 #ifdef DEBUG 169 printf("Found EncryptionKey constructor\n"); 170 #endif /* DEBUG */ 171 172 ticketFlagsConstructor = (*env)->GetMethodID(env, ticketFlagsClass, "<init>", "(I[B)V"); 173 if (ticketFlagsConstructor == 0) { 174 printf("Couldn't find TicketFlags constructor\n"); 175 return JNI_ERR; 176 } 177 #ifdef DEBUG 178 printf("Found TicketFlags constructor\n"); 179 #endif /* DEBUG */ 180 181 kerberosTimeConstructor = (*env)->GetMethodID(env, kerberosTimeClass, "<init>", "(J)V"); 182 if (kerberosTimeConstructor == 0) { 183 printf("Couldn't find KerberosTime constructor\n"); 184 return JNI_ERR; 185 } 186 #ifdef DEBUG 187 printf("Found KerberosTime constructor\n"); 188 #endif /* DEBUG */ 189 190 integerConstructor = (*env)->GetMethodID(env, javaLangIntegerClass, "<init>", "(I)V"); 191 if (integerConstructor == 0) { 192 printf("Couldn't find Integer constructor\n"); 193 return JNI_ERR; 194 } 195 #ifdef DEBUG 196 printf("Found Integer constructor\n"); 197 #endif /* DEBUG */ 198 199 hostAddressConstructor = (*env)->GetMethodID(env, hostAddressClass, "<init>", "(I[B)V"); 200 if (hostAddressConstructor == 0) { 201 printf("Couldn't find HostAddress constructor\n"); 202 return JNI_ERR; 203 } 204 #ifdef DEBUG 205 printf("Found HostAddress constructor\n"); 206 #endif /* DEBUG */ 207 208 hostAddressesConstructor = (*env)->GetMethodID(env, hostAddressesClass, "<init>", "([Lsun/security/krb5/internal/HostAddress;)V"); 209 if (hostAddressesConstructor == 0) { 210 printf("Couldn't find HostAddresses constructor\n"); 211 return JNI_ERR; 212 } 213 #ifdef DEBUG 214 printf("Found HostAddresses constructor\n"); 215 #endif /* DEBUG */ 216 217 #ifdef DEBUG 218 printf("Finished OnLoad processing\n"); 219 #endif /* DEBUG */ 220 221 return JNI_VERSION_1_2; 222 } 223 224 /* 225 * Class: sun_security_jgss_KrbCreds 226 * Method: JNI_OnUnload 227 */ 228 JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved) 229 { 230 JNIEnv *env; 231 232 if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) { 233 return; /* Nothing else we can do */ 234 } 235 236 if (ticketClass != NULL) { 237 (*env)->DeleteWeakGlobalRef(env,ticketClass); 238 } 239 if (derValueClass != NULL) { 240 (*env)->DeleteWeakGlobalRef(env,derValueClass); 241 } 242 if (principalNameClass != NULL) { 243 (*env)->DeleteWeakGlobalRef(env,principalNameClass); 244 } 245 if (encryptionKeyClass != NULL) { 246 (*env)->DeleteWeakGlobalRef(env,encryptionKeyClass); 247 } 248 if (ticketFlagsClass != NULL) { 249 (*env)->DeleteWeakGlobalRef(env,ticketFlagsClass); 250 } 251 if (kerberosTimeClass != NULL) { 252 (*env)->DeleteWeakGlobalRef(env,kerberosTimeClass); 253 } 254 if (javaLangStringClass != NULL) { 255 (*env)->DeleteWeakGlobalRef(env,javaLangStringClass); 256 } 257 if (javaLangIntegerClass != NULL) { 258 (*env)->DeleteWeakGlobalRef(env,javaLangIntegerClass); 259 } 260 if (hostAddressClass != NULL) { 261 (*env)->DeleteWeakGlobalRef(env,hostAddressClass); 262 } 263 if (hostAddressesClass != NULL) { 264 (*env)->DeleteWeakGlobalRef(env,hostAddressesClass); 265 } 266 267 } 268 269 int isIn(krb5_enctype e, int n, jint* etypes) 270 { 271 int i; 272 for (i=0; i<n; i++) { 273 if (e == etypes[i]) return 1; 274 } 275 return 0; 276 } 277 278 /* 279 * Class: sun_security_krb5_Credentials 280 * Method: acquireDefaultNativeCreds 281 * Signature: ([I])Lsun/security/krb5/Credentials; 282 */ 283 JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds 284 (JNIEnv *env, jclass krbcredsClass, jintArray jetypes) 285 { 286 jobject krbCreds = NULL; 287 krb5_error_code err = 0; 288 krb5_ccache ccache = NULL; 289 krb5_cc_cursor cursor = NULL; 290 krb5_creds creds; 291 krb5_flags flags = 0; 292 krb5_context kcontext = NULL; 293 294 int netypes; 295 jint *etypes = NULL; 296 int proxy_flag = 0; 297 298 /* Initialize the Kerberos 5 context */ 299 err = krb5_init_context (&kcontext); 300 301 if (!err) { 302 err = krb5_cc_default (kcontext, &ccache); 303 } 304 305 if (!err) { 306 err = krb5_cc_set_flags (kcontext, ccache, flags); /* turn off OPENCLOSE */ 307 } 308 309 // First round read. The proxy_impersonator config flag is not supported. 310 // This ccache will not be used if this flag exists. 311 if (!err) { 312 err = krb5_cc_start_seq_get (kcontext, ccache, &cursor); 313 } 314 315 if (!err) { 316 while ((err = krb5_cc_next_cred (kcontext, ccache, &cursor, &creds)) == 0) { 317 char *serverName = NULL; 318 319 if (!err) { 320 err = krb5_unparse_name (kcontext, creds.server, &serverName); 321 printiferr (err, "while unparsing server name"); 322 } 323 324 if (!err) { 325 if (!strcmp(serverName, "krb5_ccache_conf_data/proxy_impersonator@X-CACHECONF:")) { 326 proxy_flag = 1; 327 } 328 } 329 330 if (serverName != NULL) { krb5_free_unparsed_name (kcontext, serverName); } 331 332 krb5_free_cred_contents (kcontext, &creds); 333 334 if (proxy_flag) break; 335 } 336 337 if (err == KRB5_CC_END) { err = 0; } 338 printiferr (err, "while retrieving a ticket"); 339 } 340 341 if (!err) { 342 err = krb5_cc_end_seq_get (kcontext, ccache, &cursor); 343 printiferr (err, "while finishing ticket retrieval"); 344 } 345 346 if (proxy_flag) { 347 goto outer_cleanup; 348 } 349 // End of first round read 350 351 if (!err) { 352 err = krb5_cc_start_seq_get (kcontext, ccache, &cursor); 353 } 354 355 netypes = (*env)->GetArrayLength(env, jetypes); 356 etypes = (jint *) (*env)->GetIntArrayElements(env, jetypes, NULL); 357 358 if (etypes != NULL && !err) { 359 while ((err = krb5_cc_next_cred (kcontext, ccache, &cursor, &creds)) == 0) { 360 char *serverName = NULL; 361 362 if (!err) { 363 err = krb5_unparse_name (kcontext, creds.server, &serverName); 364 printiferr (err, "while unparsing server name"); 365 } 366 367 if (!err) { 368 char* slash = strchr(serverName, '/'); 369 char* at = strchr(serverName, '@'); 370 // Make sure the server's name is krbtgt/REALM@REALM, the etype 371 // is supported, and the ticket has not expired 372 if (slash && at && 373 strncmp (serverName, "krbtgt", slash-serverName) == 0 && 374 // the ablove line shows at must be after slash 375 strncmp (slash+1, at+1, at-slash-1) == 0 && 376 isIn (creds.keyblock.enctype, netypes, etypes) && 377 creds.times.endtime > time(0)) { 378 jobject ticket, clientPrincipal, targetPrincipal, encryptionKey; 379 jobject ticketFlags, startTime, endTime; 380 jobject authTime, renewTillTime, hostAddresses; 381 382 ticket = clientPrincipal = targetPrincipal = encryptionKey = NULL; 383 ticketFlags = startTime = endTime = NULL; 384 authTime = renewTillTime = hostAddresses = NULL; 385 386 // For the default credentials we're only interested in the krbtgt server. 387 clientPrincipal = BuildClientPrincipal(env, kcontext, creds.client); 388 if (clientPrincipal == NULL) goto cleanup; 389 390 targetPrincipal = BuildClientPrincipal(env, kcontext, creds.server); 391 if (targetPrincipal == NULL) goto cleanup; 392 393 // Build a sun/security/krb5/internal/Ticket 394 ticket = BuildTicket(env, &creds.ticket); 395 if (ticket == NULL) goto cleanup; 396 397 // Get the encryption key 398 encryptionKey = BuildEncryptionKey(env, &creds.keyblock); 399 if (encryptionKey == NULL) goto cleanup; 400 401 // and the ticket flags 402 ticketFlags = BuildTicketFlags(env, creds.ticket_flags); 403 if (ticketFlags == NULL) goto cleanup; 404 405 // Get the timestamps out. 406 startTime = BuildKerberosTime(env, creds.times.starttime); 407 if (startTime == NULL) goto cleanup; 408 409 authTime = BuildKerberosTime(env, creds.times.authtime); 410 if (authTime == NULL) goto cleanup; 411 412 endTime = BuildKerberosTime(env, creds.times.endtime); 413 if (endTime == NULL) goto cleanup; 414 415 renewTillTime = BuildKerberosTime(env, creds.times.renew_till); 416 if (renewTillTime == NULL) goto cleanup; 417 418 // Create the addresses object. 419 hostAddresses = BuildAddressList(env, creds.addresses); 420 421 if (krbcredsConstructor == 0) { 422 krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>", 423 "(Lsun/security/krb5/internal/Ticket;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;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"); 424 if (krbcredsConstructor == 0) { 425 printf("Couldn't find sun.security.krb5.internal.Ticket constructor\n"); 426 break; 427 } 428 } 429 430 // and now go build a KrbCreds object 431 krbCreds = (*env)->NewObject( 432 env, 433 krbcredsClass, 434 krbcredsConstructor, 435 ticket, 436 clientPrincipal, 437 NULL, 438 targetPrincipal, 439 NULL, 440 encryptionKey, 441 ticketFlags, 442 authTime, 443 startTime, 444 endTime, 445 renewTillTime, 446 hostAddresses); 447 cleanup: 448 if (ticket) (*env)->DeleteLocalRef(env, ticket); 449 if (clientPrincipal) (*env)->DeleteLocalRef(env, clientPrincipal); 450 if (targetPrincipal) (*env)->DeleteLocalRef(env, targetPrincipal); 451 if (encryptionKey) (*env)->DeleteLocalRef(env, encryptionKey); 452 if (ticketFlags) (*env)->DeleteLocalRef(env, ticketFlags); 453 if (authTime) (*env)->DeleteLocalRef(env, authTime); 454 if (startTime) (*env)->DeleteLocalRef(env, startTime); 455 if (endTime) (*env)->DeleteLocalRef(env, endTime); 456 if (renewTillTime) (*env)->DeleteLocalRef(env, renewTillTime); 457 if (hostAddresses) (*env)->DeleteLocalRef(env, hostAddresses); 458 459 // Stop if there is an exception or we already found the initial TGT 460 if ((*env)->ExceptionCheck(env) || krbCreds) { 461 break; 462 } 463 } 464 } 465 466 if (serverName != NULL) { krb5_free_unparsed_name (kcontext, serverName); } 467 468 krb5_free_cred_contents (kcontext, &creds); 469 } 470 471 if (err == KRB5_CC_END) { err = 0; } 472 printiferr (err, "while retrieving a ticket"); 473 } 474 475 if (!err) { 476 err = krb5_cc_end_seq_get (kcontext, ccache, &cursor); 477 printiferr (err, "while finishing ticket retrieval"); 478 } 479 480 outer_cleanup: 481 if (!err) { 482 flags = KRB5_TC_OPENCLOSE; /* restore OPENCLOSE mode */ 483 err = krb5_cc_set_flags (kcontext, ccache, flags); 484 printiferr (err, "while finishing ticket retrieval"); 485 } 486 487 if (etypes != NULL) { 488 (*env)->ReleaseIntArrayElements(env, jetypes, etypes, 0); 489 } 490 491 krb5_free_context (kcontext); 492 return krbCreds; 493 } 494 495 496 #pragma mark - 497 498 jobject BuildTicket(JNIEnv *env, krb5_data *encodedTicket) 499 { 500 /* To build a Ticket, we first need to build a DerValue out of the EncodedTicket. 501 * But before we can do that, we need to make a byte array out of the ET. 502 */ 503 504 jobject derValue, ticket; 505 jbyteArray ary; 506 507 ary = (*env)->NewByteArray(env, encodedTicket->length); 508 if ((*env)->ExceptionCheck(env)) { 509 return (jobject) NULL; 510 } 511 512 (*env)->SetByteArrayRegion(env, ary, (jsize) 0, encodedTicket->length, (jbyte *)encodedTicket->data); 513 if ((*env)->ExceptionCheck(env)) { 514 (*env)->DeleteLocalRef(env, ary); 515 return (jobject) NULL; 516 } 517 518 derValue = (*env)->NewObject(env, derValueClass, derValueConstructor, ary); 519 if ((*env)->ExceptionCheck(env)) { 520 (*env)->DeleteLocalRef(env, ary); 521 return (jobject) NULL; 522 } 523 524 (*env)->DeleteLocalRef(env, ary); 525 ticket = (*env)->NewObject(env, ticketClass, ticketConstructor, derValue); 526 if ((*env)->ExceptionCheck(env)) { 527 (*env)->DeleteLocalRef(env, derValue); 528 return (jobject) NULL; 529 } 530 (*env)->DeleteLocalRef(env, derValue); 531 return ticket; 532 } 533 534 jobject BuildClientPrincipal(JNIEnv *env, krb5_context kcontext, krb5_principal principalName) { 535 // Get the full principal string. 536 char *principalString = NULL; 537 jobject principal = NULL; 538 int err = krb5_unparse_name (kcontext, principalName, &principalString); 539 540 if (!err) { 541 // Make a PrincipalName from the full string and the type. Let the PrincipalName class parse it out. 542 jstring principalStringObj = (*env)->NewStringUTF(env, principalString); 543 if (principalStringObj == NULL) { 544 if (principalString != NULL) { krb5_free_unparsed_name (kcontext, principalString); } 545 return (jobject) NULL; 546 } 547 principal = (*env)->NewObject(env, principalNameClass, principalNameConstructor, principalStringObj, principalName->type); 548 if (principalString != NULL) { krb5_free_unparsed_name (kcontext, principalString); } 549 (*env)->DeleteLocalRef(env, principalStringObj); 550 } 551 552 return principal; 553 } 554 555 jobject BuildEncryptionKey(JNIEnv *env, krb5_keyblock *cryptoKey) { 556 // First, need to build a byte array 557 jbyteArray ary; 558 jobject encryptionKey = NULL; 559 560 ary = (*env)->NewByteArray(env,cryptoKey->length); 561 562 if (ary == NULL) { 563 return (jobject) NULL; 564 } 565 566 (*env)->SetByteArrayRegion(env, ary, (jsize) 0, cryptoKey->length, (jbyte *)cryptoKey->contents); 567 if (!(*env)->ExceptionCheck(env)) { 568 encryptionKey = (*env)->NewObject(env, encryptionKeyClass, encryptionKeyConstructor, cryptoKey->enctype, ary); 569 } 570 571 (*env)->DeleteLocalRef(env, ary); 572 return encryptionKey; 573 } 574 575 jobject BuildTicketFlags(JNIEnv *env, krb5_flags flags) { 576 jobject ticketFlags = NULL; 577 jbyteArray ary; 578 579 /* 580 * Convert the bytes to network byte order before copying 581 * them to a Java byte array. 582 */ 583 unsigned long nlflags = htonl(flags); 584 585 ary = (*env)->NewByteArray(env, sizeof(flags)); 586 587 if (ary == NULL) { 588 return (jobject) NULL; 589 } 590 591 (*env)->SetByteArrayRegion(env, ary, (jsize) 0, sizeof(flags), (jbyte *)&nlflags); 592 593 if (!(*env)->ExceptionCheck(env)) { 594 ticketFlags = (*env)->NewObject(env, ticketFlagsClass, ticketFlagsConstructor, sizeof(flags)*8, ary); 595 } 596 597 (*env)->DeleteLocalRef(env, ary); 598 return ticketFlags; 599 } 600 601 jobject BuildKerberosTime(JNIEnv *env, krb5_timestamp kerbtime) { 602 jlong time = kerbtime; 603 604 // Kerberos time is in seconds, but the KerberosTime class assumes milliseconds, so multiply by 1000. 605 time *= 1000; 606 return (*env)->NewObject(env, kerberosTimeClass, kerberosTimeConstructor, time); 607 } 608 609 jobject BuildAddressList(JNIEnv *env, krb5_address **addresses) { 610 611 if (addresses == NULL) { 612 return NULL; 613 } 614 615 int addressCount = 0; 616 617 // See how many we have. 618 krb5_address **p = addresses; 619 620 while (*p != 0) { 621 addressCount++; 622 p++; 623 } 624 625 jobject address_list = (*env)->NewObjectArray(env, addressCount, hostAddressClass, NULL); 626 627 if (address_list == NULL) { 628 return (jobject) NULL; 629 } 630 631 // Create a new HostAddress object for each address block. 632 // First, reset the iterator. 633 p = addresses; 634 jsize index = 0; 635 while (*p != 0) { 636 krb5_address *currAddress = *p; 637 638 // HostAddres needs a byte array of the host data. 639 jbyteArray ary = (*env)->NewByteArray(env, currAddress->length); 640 641 if (ary == NULL) return NULL; 642 643 (*env)->SetByteArrayRegion(env, ary, (jsize) 0, currAddress->length, (jbyte *)currAddress->contents); 644 jobject address = (*env)->NewObject(env, hostAddressClass, hostAddressConstructor, currAddress->length, ary); 645 646 (*env)->DeleteLocalRef(env, ary); 647 648 if (address == NULL) { 649 return (jobject) NULL; 650 } 651 // Add the HostAddress to the arrray. 652 (*env)->SetObjectArrayElement(env, address_list, index, address); 653 654 if ((*env)->ExceptionCheck(env)) { 655 return (jobject) NULL; 656 } 657 658 index++; 659 p++; 660 } 661 662 return address_list; 663 } 664 665 #pragma mark - Utility methods - 666 667 static void printiferr (errcode_t err, const char *format, ...) 668 { 669 if (err) { 670 va_list pvar; 671 672 va_start (pvar, format); 673 com_err_va ("ticketParser:", err, format, pvar); 674 va_end (pvar); 675 } 676 } 677