1 /* 2 * Copyright (c) 2011, 2021, 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 <Cocoa/Cocoa.h> 27 #import <SystemConfiguration/SystemConfiguration.h> 28 #import "jni_util.h" 29 30 #define KERBEROS_DEFAULT_REALMS @"Kerberos-Default-Realms" 31 #define KERBEROS_DEFAULT_REALM_MAPPINGS @"Kerberos-Domain-Realm-Mappings" 32 #define KERBEROS_REALM_INFO @"Kerberos:%@" 33 34 JavaVM *localVM; 35 36 void _SCDynamicStoreCallBack(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) { 37 NSArray *keys = (NSArray *)changedKeys; 38 if ([keys count] == 0) return; 39 if (![keys containsObject:KERBEROS_DEFAULT_REALMS] && ![keys containsObject:KERBEROS_DEFAULT_REALM_MAPPINGS]) return; 40 41 JNIEnv *env; 42 bool createdFromAttach = FALSE; 43 jint status = (*localVM)->GetEnv(localVM, (void**)&env, JNI_VERSION_1_2); 44 if (status == JNI_EDETACHED) { 45 status = (*localVM)->AttachCurrentThreadAsDaemon(localVM, (void**)&env, NULL); 46 createdFromAttach = TRUE; 47 } 48 if (status == 0) { 49 jclass jc_Config = (*env)->FindClass(env, "sun/security/krb5/Config"); 50 CHECK_NULL(jc_Config); 51 jmethodID jm_Config_refresh = (*env)->GetStaticMethodID(env, jc_Config, "refresh", "()V"); 52 CHECK_NULL(jm_Config_refresh); 53 (*env)->CallStaticVoidMethod(env, jc_Config, jm_Config_refresh); 54 if ((*env)->ExceptionOccurred(env) != NULL) { 55 (*env)->ExceptionClear(env); 56 } 57 if (createdFromAttach) { 58 (*localVM)->DetachCurrentThread(localVM); 59 } 60 } 61 } 62 63 /* 64 * Class: sun_security_krb5_SCDynamicStoreConfig 65 * Method: installNotificationCallback 66 */ 67 JNIEXPORT void JNICALL Java_sun_security_krb5_SCDynamicStoreConfig_installNotificationCallback(JNIEnv *env, jclass klass) { 68 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \ 69 @try { 70 (*env)->GetJavaVM(env, &localVM); 71 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("java"), _SCDynamicStoreCallBack, NULL); 72 if (store == NULL) { 73 return; 74 } 75 76 NSArray *keys = [NSArray arrayWithObjects:KERBEROS_DEFAULT_REALMS, KERBEROS_DEFAULT_REALM_MAPPINGS, nil]; 77 SCDynamicStoreSetNotificationKeys(store, (CFArrayRef) keys, NULL); 78 79 CFRunLoopSourceRef rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); 80 if (rls != NULL) { 81 CFRunLoopAddSource(CFRunLoopGetMain(), rls, kCFRunLoopDefaultMode); 82 CFRelease(rls); 83 } 84 85 CFRelease(store); 86 } @catch (NSException *e) { 87 NSLog(@"%@", [e callStackSymbols]); 88 } @finally { 89 [pool drain]; 90 } 91 } 92 93 #define ADD(list, str) { \ 94 jobject localeObj = (*env)->NewStringUTF(env, [str UTF8String]); \ 95 (*env)->CallBooleanMethod(env, list, jm_listAdd, localeObj); \ 96 (*env)->DeleteLocalRef(env, localeObj); \ 97 } 98 99 #define ADDNULL(list) (*env)->CallBooleanMethod(env, list, jm_listAdd, NULL) 100 101 /* 102 * Class: sun_security_krb5_SCDynamicStoreConfig 103 * Method: getKerberosConfig 104 * Signature: ()Ljava/util/List; 105 */ 106 JNIEXPORT jobject JNICALL Java_sun_security_krb5_SCDynamicStoreConfig_getKerberosConfig(JNIEnv *env, jclass klass) { 107 108 jobject newList = 0; 109 110 SCDynamicStoreRef store = NULL; 111 CFTypeRef realms = NULL; 112 CFTypeRef realmMappings = NULL; 113 CFTypeRef realmInfo = NULL; 114 115 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \ 116 @try { 117 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("java-kerberos"), NULL, NULL); 118 if (store == NULL) { 119 return NULL; 120 } 121 122 CFTypeRef realms = SCDynamicStoreCopyValue(store, (CFStringRef) KERBEROS_DEFAULT_REALMS); 123 if (realms == NULL || CFGetTypeID(realms) != CFArrayGetTypeID()) { 124 return NULL; 125 } 126 127 // This methods returns a ArrayList<String>: 128 // (realm kdc* null) null (mapping-domain mapping-realm)* 129 jclass jc_arrayListClass = (*env)->FindClass(env, "java/util/ArrayList"); 130 CHECK_NULL_RETURN(jc_arrayListClass, NULL); 131 jmethodID jm_arrayListCons = (*env)->GetMethodID(env, jc_arrayListClass, "<init>", "()V"); 132 CHECK_NULL_RETURN(jm_arrayListCons, NULL); 133 jmethodID jm_listAdd = (*env)->GetMethodID(env, jc_arrayListClass, "add", "(Ljava/lang/Object;)Z"); 134 CHECK_NULL_RETURN(jm_listAdd, NULL); 135 newList = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons); 136 CHECK_NULL_RETURN(newList, NULL); 137 138 for (NSString *realm in (NSArray*)realms) { 139 if (realmInfo) CFRelease(realmInfo); // for the previous realm 140 realmInfo = SCDynamicStoreCopyValue(store, (CFStringRef) [NSString stringWithFormat:KERBEROS_REALM_INFO, realm]); 141 if (realmInfo == NULL || CFGetTypeID(realmInfo) != CFDictionaryGetTypeID()) { 142 continue; 143 } 144 145 ADD(newList, realm); 146 NSDictionary* ri = (NSDictionary*)realmInfo; 147 for (NSDictionary* k in (NSArray*)ri[@"kdc"]) { 148 ADD(newList, k[@"host"]); 149 } 150 ADDNULL(newList); 151 } 152 ADDNULL(newList); 153 154 CFTypeRef realmMappings = SCDynamicStoreCopyValue(store, (CFStringRef) KERBEROS_DEFAULT_REALM_MAPPINGS); 155 if (realmMappings != NULL && CFGetTypeID(realmMappings) == CFArrayGetTypeID()) { 156 for (NSDictionary* d in (NSArray *)realmMappings) { 157 for (NSString* s in d) { 158 ADD(newList, s); 159 ADD(newList, d[s]); 160 } 161 } 162 } 163 } @catch (NSException *e) { 164 NSLog(@"%@", [e callStackSymbols]); 165 } @finally { 166 [pool drain]; 167 if (realmInfo) CFRelease(realmInfo); 168 if (realmMappings) CFRelease(realmMappings); 169 if (realms) CFRelease(realms); 170 if (store) CFRelease(store); 171 } 172 return newList; 173 }