1/*
2 * Copyright (c) 2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * EAPOLControlPrefs.c
26 * - definitions for accessing EAPOL preferences
27 */
28
29/*
30 * Modification History
31 *
32 * January 9, 2013	Dieter Siegmund (dieter@apple)
33 * - created
34 */
35
36#include <SystemConfiguration/SCPreferences.h>
37#include <SystemConfiguration/SCPrivate.h>
38#include <SystemConfiguration/scprefs_observer.h>
39#include <TargetConditionals.h>
40#include "EAPOLControlPrefs.h"
41#include "symbol_scope.h"
42#include "myCFUtil.h"
43
44/*
45 * kEAPOLClientPrefsID
46 * - identifies the eapolclient preferences file that contains
47 *   LogFlags and other control variables
48 */
49#define kEAPOLClientPrefsID		CFSTR("com.apple.eapolclient.plist")
50
51
52/*
53 * kEAPOLControlPrefsID, kEAPOLControlPrefsIDStr
54 * - identifies the managed preferences ID used to apply control
55 *   settings on iOS via configuration profile
56 */
57
58#define kEAPOLControlPrefsIDStr		"com.apple.eapol.control.plist"
59#define kEAPOLControlPrefsID		CFSTR(kEAPOLControlPrefsIDStr)
60
61/*
62 * kLogFlags
63 * - indicates how verbose the eapolclient logging will be
64 */
65#define kLogFlags			CFSTR("LogFlags")
66
67STATIC SCPreferencesRef			S_prefs;
68STATIC EAPOLControlPrefsCallBack	S_callback;
69
70STATIC SCPreferencesRef
71EAPOLControlPrefsGet(void)
72{
73    if (S_prefs == NULL) {
74	EAPOLControlPrefsInit(NULL, NULL);
75    }
76    return (S_prefs);
77}
78
79STATIC void
80prefs_changed(__unused void * arg)
81{
82    if (S_callback != NULL) {
83	(*S_callback)(S_prefs);
84    }
85    return;
86}
87
88#if TARGET_OS_EMBEDDED
89/*
90 * kEAPOLControlManangedPrefsID
91 * - identifies the location of the managed preferences file
92 */
93#define kManagedPrefsDirStr		"/Library/Managed Preferences/mobile/"
94#define kEAPOLControlManagedPrefsID	CFSTR(kManagedPrefsDirStr	\
95					      kEAPOLControlPrefsIDStr)
96STATIC SCPreferencesRef		S_managed_prefs;
97
98STATIC SCPreferencesRef
99EAPOLControlManagedPrefsGet(void)
100{
101    if (S_managed_prefs == NULL) {
102	S_managed_prefs
103	    = SCPreferencesCreate(NULL, CFSTR("EAPOLControlPrefs"),
104				  kEAPOLControlManagedPrefsID);
105    }
106    return (S_managed_prefs);
107}
108
109STATIC void
110enable_prefs_observer(CFRunLoopRef runloop)
111{
112    CFRunLoopSourceContext 	context;
113    dispatch_block_t		handler;
114    CFRunLoopSourceRef		source;
115    dispatch_queue_t		queue;
116
117    bzero(&context, sizeof(context));
118    context.perform = prefs_changed;
119    source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
120    CFRunLoopAddSource(runloop, source, kCFRunLoopCommonModes);
121    queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
122    handler = ^{
123	if (source != NULL) {
124	    CFRunLoopSourceSignal(source);
125	    if (runloop != NULL) {
126		CFRunLoopWakeUp(runloop);
127	    }
128	};
129    };
130    (void)_scprefs_observer_watch(scprefs_observer_type_global,
131				  kEAPOLControlPrefsIDStr,
132				  queue, handler);
133    return;
134}
135
136#else /* TARGET_OS_EMBEDDED */
137
138STATIC void
139enable_prefs_observer(CFRunLoopRef runloop)
140{
141    return;
142}
143
144#endif /* TARGET_OS_EMBEDDED */
145
146EXTERN void
147EAPOLControlPrefsSynchronize(void)
148{
149    if (S_prefs != NULL) {
150	SCPreferencesSynchronize(S_prefs);
151    }
152#if TARGET_OS_EMBEDDED
153    if (S_managed_prefs != NULL) {
154	SCPreferencesSynchronize(S_managed_prefs);
155    }
156#endif /* TARGET_OS_EMBEDDED */
157    return;
158}
159
160STATIC void
161EAPOLControlPrefsChanged(SCPreferencesRef prefs, SCPreferencesNotification type,
162			 void * info)
163{
164    prefs_changed(NULL);
165    return;
166}
167
168EXTERN SCPreferencesRef
169EAPOLControlPrefsInit(CFRunLoopRef runloop, EAPOLControlPrefsCallBack callback)
170{
171    S_prefs = SCPreferencesCreate(NULL, CFSTR("EAPOLControlPrefs"),
172				  kEAPOLClientPrefsID);
173    if (runloop != NULL && callback != NULL) {
174	S_callback = callback;
175	SCPreferencesSetCallback(S_prefs, EAPOLControlPrefsChanged, NULL);
176	SCPreferencesScheduleWithRunLoop(S_prefs, runloop,
177					 kCFRunLoopCommonModes);
178	enable_prefs_observer(runloop);
179    }
180    return (S_prefs);
181}
182
183STATIC Boolean
184EAPOLControlPrefsSave(void)
185{
186    Boolean		saved = FALSE;
187
188    if (S_prefs != NULL) {
189	saved = SCPreferencesCommitChanges(S_prefs);
190	SCPreferencesSynchronize(S_prefs);
191    }
192    return (saved);
193}
194
195STATIC CFNumberRef
196prefs_get_number(CFStringRef key)
197{
198    CFNumberRef		num = NULL;
199
200#if TARGET_OS_EMBEDDED
201    num = SCPreferencesGetValue(EAPOLControlManagedPrefsGet(), key);
202    num = isA_CFNumber(num);
203#endif /* TARGET_OS_EMBEDDED */
204    if (num == NULL) {
205	num = SCPreferencesGetValue(EAPOLControlPrefsGet(), key);
206	num = isA_CFNumber(num);
207    }
208    return (num);
209}
210
211STATIC void
212prefs_set_number(CFStringRef key, CFNumberRef num)
213{
214    SCPreferencesRef	prefs = EAPOLControlPrefsGet();
215
216    if (prefs != NULL) {
217	if (isA_CFNumber(num) == NULL) {
218	    SCPreferencesRemoveValue(prefs, key);
219	}
220	else {
221	    SCPreferencesSetValue(prefs, key, num);
222	}
223    }
224    return;
225}
226
227/**
228 ** Get
229 **/
230EXTERN uint32_t
231EAPOLControlPrefsGetLogFlags(void)
232{
233    CFNumberRef	num;
234    uint32_t	ret_value = 0;
235
236    num = prefs_get_number(kLogFlags);
237    if (num != NULL) {
238	CFNumberGetValue(num, kCFNumberSInt32Type, &ret_value);
239    }
240    return (ret_value);
241}
242
243/**
244 ** Set
245 **/
246EXTERN Boolean
247EAPOLControlPrefsSetLogFlags(uint32_t flags)
248{
249    if (flags == 0) {
250	prefs_set_number(kLogFlags, NULL);
251    }
252    else {
253	CFNumberRef	num;
254
255	num = CFNumberCreate(NULL, kCFNumberSInt32Type, &flags);
256	prefs_set_number(kLogFlags, num);
257	my_CFRelease(&num);
258    }
259    return (EAPOLControlPrefsSave());
260}
261