1 /*
   2  * Copyright (c) 2011, 2012, 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 <JavaNativeFoundation/JavaNativeFoundation.h>
  28 #import <SystemConfiguration/SystemConfiguration.h>
  29 
  30 
  31 @interface JNFVectorCoercion : NSObject <JNFTypeCoercion> { }
  32 @end
  33 
  34 @implementation JNFVectorCoercion
  35 
  36 - (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
  37     static JNF_CLASS_CACHE(jc_Vector, "java/util/Vector");
  38     static JNF_CTOR_CACHE(jm_Vector_ctor, jc_Vector, "(I)V");
  39     static JNF_MEMBER_CACHE(jm_Vector_add, jc_Vector, "add", "(Ljava/lang/Object;)Z");
  40 
  41     NSArray *nsArray = (NSArray *)obj;
  42     jobject javaArray = JNFNewObject(env, jm_Vector_ctor, (jint)[nsArray count]);
  43 
  44     for (id obj in nsArray) {
  45         jobject jobj = [coercer coerceNSObject:obj withEnv:env usingCoercer:coercer];
  46         JNFCallBooleanMethod(env, javaArray, jm_Vector_add, jobj);
  47         if (jobj != NULL) (*env)->DeleteLocalRef(env, jobj);
  48     }
  49 
  50     return javaArray;
  51 }
  52 
  53 - (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
  54     return nil;
  55 }
  56 
  57 @end
  58 
  59 
  60 @interface JNFHashtableCoercion : NSObject <JNFTypeCoercion> { }
  61 @end
  62 
  63 @implementation JNFHashtableCoercion
  64 
  65 - (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
  66     static JNF_CLASS_CACHE(jc_Hashtable, "java/util/Hashtable");
  67     static JNF_CTOR_CACHE(jm_Hashtable_ctor, jc_Hashtable, "()V");
  68     static JNF_MEMBER_CACHE(jm_Hashtable_put, jc_Hashtable, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
  69 
  70     NSDictionary *nsDict = (NSDictionary *)obj;
  71     NSEnumerator *keyEnum = [nsDict keyEnumerator];
  72 
  73     jobject jHashTable = JNFNewObject(env, jm_Hashtable_ctor);
  74 
  75     id key = nil;
  76     while ((key = [keyEnum nextObject]) != nil) {
  77         jobject jkey = [coercer coerceNSObject:key withEnv:env usingCoercer:coercer];
  78 
  79         id value = [nsDict objectForKey:key];
  80         jobject jvalue = [coercer coerceNSObject:value withEnv:env usingCoercer:coercer];
  81 
  82         JNFCallObjectMethod(env, jHashTable, jm_Hashtable_put, jkey, jvalue);
  83 
  84         if (jkey != NULL) (*env)->DeleteLocalRef(env, jkey);
  85         if (jvalue != NULL) (*env)->DeleteLocalRef(env, jvalue);
  86     }
  87 
  88     return jHashTable;
  89 }
  90 
  91 - (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
  92     return nil;
  93 }
  94 
  95 @end
  96 
  97 
  98 
  99 NSDictionary *realmConfigsForRealms(SCDynamicStoreRef store, NSArray *realms) {
 100     NSMutableDictionary *dict = [NSMutableDictionary dictionary];
 101 
 102     for (NSString *realm in realms) {
 103         CFTypeRef realmInfo = SCDynamicStoreCopyValue(store, (CFStringRef) [NSString stringWithFormat:@"Kerberos:%@", realm]);
 104 
 105         if (CFGetTypeID(realmInfo) != CFDictionaryGetTypeID()) {
 106             return nil;
 107         }
 108 
 109         [dict setObject:(NSArray *)realmInfo forKey:realm];
 110         CFRelease(realmInfo);
 111     }
 112 
 113     return dict;
 114 }
 115 
 116 
 117 #define KERBEROS_DEFAULT_REALMS @"Kerberos-Default-Realms"
 118 #define KERBEROS_DEFAULT_REALM_MAPPINGS @"Kerberos-Domain-Realm-Mappings"
 119 
 120 void _SCDynamicStoreCallBack(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) {
 121    NSArray *keys = (NSArray *)changedKeys;
 122     if ([keys count] == 0) return;
 123     if (![keys containsObject:KERBEROS_DEFAULT_REALMS] && ![keys containsObject:KERBEROS_DEFAULT_REALM_MAPPINGS]) return;
 124 
 125     JNFPerformEnvBlock(JNFThreadDetachOnThreadDeath | JNFThreadSetSystemClassLoaderOnAttach | JNFThreadAttachAsDaemon, ^(JNIEnv *env) {
 126         static JNF_CLASS_CACHE(jc_Config, "sun/security/krb5/Config");
 127         static JNF_STATIC_MEMBER_CACHE(jm_Config_refresh, jc_Config, "refresh", "()V");
 128         JNFCallStaticVoidMethod(env, jm_Config_refresh);
 129     });
 130 }
 131 
 132 /*
 133  * Class:     sun_security_krb5_SCDynamicStoreConfig
 134  * Method:    installNotificationCallback
 135  */
 136 JNIEXPORT void JNICALL Java_sun_security_krb5_SCDynamicStoreConfig_installNotificationCallback(JNIEnv *env, jclass klass) {
 137 
 138 JNF_COCOA_ENTER(env);
 139 
 140     SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("java"), _SCDynamicStoreCallBack, NULL);
 141     if (store == NULL) {
 142         return;
 143     }
 144 
 145     NSArray *keys = [NSArray arrayWithObjects:KERBEROS_DEFAULT_REALMS, KERBEROS_DEFAULT_REALM_MAPPINGS, nil];
 146     SCDynamicStoreSetNotificationKeys(store, (CFArrayRef) keys, NULL);
 147 
 148     CFRunLoopSourceRef rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
 149     if (rls != NULL) {
 150         CFRunLoopAddSource(CFRunLoopGetMain(), rls, kCFRunLoopDefaultMode);
 151         CFRelease(rls);
 152     }
 153 
 154     CFRelease(store);
 155 
 156 JNF_COCOA_EXIT(env);
 157 
 158 }
 159 
 160 /*
 161  * Class:     sun_security_krb5_SCDynamicStoreConfig
 162  * Method:    getKerberosConfig
 163  * Signature: ()Ljava/util/Hashtable;
 164  */
 165 JNIEXPORT jobject JNICALL Java_sun_security_krb5_SCDynamicStoreConfig_getKerberosConfig(JNIEnv *env, jclass klass) {
 166     jobject jHashTable = NULL;
 167 
 168 JNF_COCOA_ENTER(env);
 169 
 170     SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("java-kerberos"), NULL, NULL);
 171     if (store == NULL) {
 172         return NULL;
 173     }
 174 
 175     CFTypeRef realms = SCDynamicStoreCopyValue(store, (CFStringRef) KERBEROS_DEFAULT_REALMS);
 176     if (realms == NULL || CFGetTypeID(realms) != CFArrayGetTypeID()) {
 177         if (realms) CFRelease(realms);
 178         CFRelease(store);
 179         return NULL;
 180     }
 181 
 182     CFTypeRef realmMappings = SCDynamicStoreCopyValue(store, (CFStringRef) KERBEROS_DEFAULT_REALM_MAPPINGS);
 183 
 184     if (realmMappings == NULL || CFGetTypeID(realmMappings) != CFArrayGetTypeID()) {
 185         if (realmMappings) CFRelease(realmMappings);
 186         CFRelease(realms);
 187         CFRelease(store);
 188         return NULL;
 189     }
 190 
 191     NSMutableDictionary *dict = [NSMutableDictionary dictionary];
 192 
 193     if (CFArrayGetCount(realms) > 0) {
 194         NSDictionary *defaultRealmsDict = [NSDictionary dictionaryWithObject:[(NSArray *)realms objectAtIndex:0] forKey:@"default_realm"];
 195         [dict setObject:defaultRealmsDict forKey:@"libdefaults"];
 196 
 197         NSDictionary *realmConfigs = realmConfigsForRealms(store, (NSArray *)realms);
 198         [dict setObject:realmConfigs forKey:@"realms"];
 199     }
 200     CFRelease(realms);
 201     CFRelease(store);
 202 
 203     if (CFArrayGetCount(realmMappings) > 0) {
 204         [dict setObject:[(NSArray *)realmMappings objectAtIndex:0] forKey:@"domain_realm"];
 205     }
 206     CFRelease(realmMappings);
 207 
 208 
 209     // create and load a coercer with all of the different coercions to convert each type of object
 210     JNFTypeCoercer *coercer = [[[JNFTypeCoercer alloc] init] autorelease];
 211     [JNFDefaultCoercions addStringCoercionTo:coercer];
 212     [JNFDefaultCoercions addNumberCoercionTo:coercer];
 213     [coercer addCoercion:[[[JNFHashtableCoercion alloc] init] autorelease] forNSClass:[NSDictionary class] javaClass:@"java/util/Map"];
 214     [coercer addCoercion:[[[JNFVectorCoercion alloc] init] autorelease] forNSClass:[NSArray class] javaClass:@"java/util/List"];
 215 
 216     // convert Cocoa graph to Java graph
 217     jHashTable = [coercer coerceNSObject:dict withEnv:env];
 218 
 219 JNF_COCOA_EXIT(env);
 220 
 221     return jHashTable;
 222 }