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
99NSDictionary *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
120void _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 */
136JNIEXPORT void JNICALL Java_sun_security_krb5_SCDynamicStoreConfig_installNotificationCallback(JNIEnv *env, jclass klass) {
137
138JNF_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
156JNF_COCOA_EXIT(env);
157
158}
159
160/*
161 * Class:     sun_security_krb5_SCDynamicStoreConfig
162 * Method:    getKerberosConfig
163 * Signature: ()Ljava/util/Hashtable;
164 */
165JNIEXPORT jobject JNICALL Java_sun_security_krb5_SCDynamicStoreConfig_getKerberosConfig(JNIEnv *env, jclass klass) {
166    jobject jHashTable = NULL;
167
168JNF_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
219JNF_COCOA_EXIT(env);
220
221    return jHashTable;
222}
223