1/*
2 * Copyright (c) 2000-2009, 2011 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 * Modification History
26 *
27 * June 1, 2001			Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * March 24, 2000		Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34#include "configd.h"
35#include "configd_server.h"
36#include "session.h"
37
38#include <bsm/libbsm.h>
39#include <sys/types.h>
40#include <unistd.h>
41
42__private_extern__
43int
44__SCDynamicStoreOpen(SCDynamicStoreRef *store, CFStringRef name)
45{
46	/*
47	 * allocate and initialize a new session
48	 */
49	*store = (SCDynamicStoreRef)__SCDynamicStoreCreatePrivate(NULL, name, NULL, NULL);
50
51	/*
52	 * If necessary, initialize the store and session data dictionaries
53	 */
54	if (storeData == NULL) {
55		sessionData        = CFDictionaryCreateMutable(NULL,
56							       0,
57							       &kCFTypeDictionaryKeyCallBacks,
58							       &kCFTypeDictionaryValueCallBacks);
59		storeData          = CFDictionaryCreateMutable(NULL,
60							       0,
61							       &kCFTypeDictionaryKeyCallBacks,
62							       &kCFTypeDictionaryValueCallBacks);
63		patternData        = CFDictionaryCreateMutable(NULL,
64							       0,
65							       &kCFTypeDictionaryKeyCallBacks,
66							       &kCFTypeDictionaryValueCallBacks);
67		changedKeys        = CFSetCreateMutable(NULL,
68							0,
69							&kCFTypeSetCallBacks);
70		deferredRemovals   = CFSetCreateMutable(NULL,
71							0,
72							&kCFTypeSetCallBacks);
73		removedSessionKeys = CFSetCreateMutable(NULL,
74							0,
75							&kCFTypeSetCallBacks);
76	}
77
78	return kSCStatusOK;
79}
80
81
82static CFStringRef
83openMPCopyDescription(const void *info)
84{
85	return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SCDynamicStore MP>"));
86}
87
88
89__private_extern__
90kern_return_t
91_configopen(mach_port_t			server,
92	    xmlData_t			nameRef,		/* raw XML bytes */
93	    mach_msg_type_number_t	nameLen,
94	    xmlData_t			optionsRef,		/* raw XML bytes */
95	    mach_msg_type_number_t	optionsLen,
96	    mach_port_t			*newServer,
97	    int				*sc_status,
98	    audit_token_t		audit_token)
99{
100	CFDictionaryRef			info;
101	serverSessionRef		mySession;
102	CFStringRef			name		= NULL;	/* name (un-serialized) */
103	CFMutableDictionaryRef		newInfo;
104	mach_port_t			oldNotify;
105	CFDictionaryRef			options		= NULL;	/* options (un-serialized) */
106	CFStringRef			sessionKey;
107	kern_return_t 			status;
108	SCDynamicStorePrivateRef	storePrivate;
109	CFBooleanRef			useSessionKeys	= NULL;
110
111	*sc_status = kSCStatusOK;
112
113	/* un-serialize the name */
114	if (!_SCUnserializeString(&name, NULL, (void *)nameRef, nameLen)) {
115		*sc_status = kSCStatusFailed;
116	}
117
118	if ((optionsRef != NULL) && (optionsLen > 0)) {
119		/* un-serialize the [session] options */
120		if (!_SCUnserialize((CFPropertyListRef *)&options, NULL, (void *)optionsRef, optionsLen)) {
121			*sc_status = kSCStatusFailed;
122		}
123	}
124
125	if (*sc_status != kSCStatusOK) {
126		goto done;
127	}
128
129	if (!isA_CFString(name)) {
130		*sc_status = kSCStatusInvalidArgument;
131		goto done;
132	}
133
134	if (options != NULL) {
135		if (!isA_CFDictionary(options)) {
136			*sc_status = kSCStatusInvalidArgument;
137			goto done;
138		}
139
140		/*
141		 * [pre-]process any provided options
142		 */
143		useSessionKeys = CFDictionaryGetValue(options, kSCDynamicStoreUseSessionKeys);
144		if (useSessionKeys != NULL) {
145			if (!isA_CFBoolean(useSessionKeys)) {
146				*sc_status = kSCStatusInvalidArgument;
147				goto done;
148			}
149		}
150	}
151
152	/*
153	 * establish the new session
154	 */
155	mySession = addSession(server, openMPCopyDescription);
156	if (mySession == NULL) {
157#ifdef	DEBUG
158		SCLog(TRUE, LOG_DEBUG, CFSTR("_configopen(): session is already open."));
159#endif	/* DEBUG */
160		*sc_status = kSCStatusFailed;	/* you can't re-open an "open" session */
161		goto done;
162	}
163
164	*newServer = mySession->key;
165	__MACH_PORT_DEBUG(TRUE, "*** _configopen (after addSession)", *newServer);
166
167	/* save the audit_token in case we need to check the callers credentials */
168	mySession->auditToken = audit_token;
169
170	/* Create and add a run loop source for the port */
171	mySession->serverRunLoopSource = CFMachPortCreateRunLoopSource(NULL, mySession->serverPort, 0);
172	CFRunLoopAddSource(CFRunLoopGetCurrent(),
173			   mySession->serverRunLoopSource,
174			   kCFRunLoopDefaultMode);
175
176	if (_configd_trace) {
177		SCTrace(TRUE, _configd_trace,
178			CFSTR("open    : %5d : %@\n"),
179			*newServer,
180			name);
181	}
182
183	*sc_status = __SCDynamicStoreOpen(&mySession->store, name);
184	storePrivate = (SCDynamicStorePrivateRef)mySession->store;
185
186	/*
187	 * Make the server port accessible to the framework routines.
188	 * ... and be sure to clear before calling CFRelease(store)
189	 */
190	storePrivate->server = *newServer;
191
192	/*
193	 * Process any provided [session] options
194	 */
195	if (useSessionKeys != NULL) {
196		storePrivate->useSessionKeys = CFBooleanGetValue(useSessionKeys);
197	}
198
199	/* Request a notification when/if the client dies */
200	status = mach_port_request_notification(mach_task_self(),
201						*newServer,
202						MACH_NOTIFY_NO_SENDERS,
203						1,
204						*newServer,
205						MACH_MSG_TYPE_MAKE_SEND_ONCE,
206						&oldNotify);
207	if (status != KERN_SUCCESS) {
208		SCLog(TRUE, LOG_ERR, CFSTR("_configopen() mach_port_request_notification() failed: %s"), mach_error_string(status));
209		cleanupSession(*newServer);
210		*newServer = MACH_PORT_NULL;
211		*sc_status = kSCStatusFailed;
212		goto done;
213	}
214	__MACH_PORT_DEBUG(TRUE, "*** _configopen (after mach_port_request_notification)", *newServer);
215
216	if (oldNotify != MACH_PORT_NULL) {
217		SCLog(TRUE, LOG_ERR, CFSTR("_configopen(): oldNotify != MACH_PORT_NULL"));
218	}
219
220	/*
221	 * Save the name of the calling application / plug-in with the session data.
222	 */
223	sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), *newServer);
224	info = CFDictionaryGetValue(sessionData, sessionKey);
225	if (info != NULL) {
226		newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info);
227	} else {
228		newInfo = CFDictionaryCreateMutable(NULL,
229						    0,
230						    &kCFTypeDictionaryKeyCallBacks,
231						    &kCFTypeDictionaryValueCallBacks);
232	}
233	CFDictionarySetValue(newInfo, kSCDName, name);
234	CFDictionarySetValue(sessionData, sessionKey, newInfo);
235	CFRelease(newInfo);
236	CFRelease(sessionKey);
237
238	/*
239	 * Note: at this time we should be holding ONE send right and
240	 *       ONE receive right to the server.  The send right is
241	 *       moved to the caller.
242	 */
243
244    done :
245
246	if (name != NULL)	CFRelease(name);
247	if (options != NULL)	CFRelease(options);
248	return KERN_SUCCESS;
249}
250