1/*
2 * Copyright (c) 2000-2006, 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 * April 14, 2000		Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34#include <fcntl.h>
35#include <paths.h>
36#include <unistd.h>
37
38#include "configd.h"
39#include "configd_server.h"
40#include "session.h"
41#include "plugin_support.h"
42
43
44#define	SNAPSHOT_PATH_STATE	_PATH_VARTMP "configd-state"
45#define	SNAPSHOT_PATH_STORE	_PATH_VARTMP "configd-store.plist"
46#define	SNAPSHOT_PATH_PATTERN	_PATH_VARTMP "configd-pattern.plist"
47#define	SNAPSHOT_PATH_SESSION	_PATH_VARTMP "configd-session.plist"
48
49
50#define N_QUICK	100
51
52static CF_RETURNS_RETAINED CFDictionaryRef
53_expandStore(CFDictionaryRef storeData)
54{
55	const void *		keys_q[N_QUICK];
56	const void **		keys		= keys_q;
57	CFIndex			nElements;
58	CFDictionaryRef		newStoreData	= NULL;
59	const void *		nValues_q[N_QUICK];
60	const void **		nValues		= nValues_q;
61	const void *		oValues_q[N_QUICK];
62	const void **		oValues		= oValues_q;
63
64	nElements = CFDictionaryGetCount(storeData);
65	if (nElements > 0) {
66		CFIndex	i;
67
68		if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
69			keys    = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
70			oValues = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
71			nValues = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
72		}
73		bzero(nValues, nElements * sizeof(CFTypeRef));
74
75		CFDictionaryGetKeysAndValues(storeData, keys, oValues);
76		for (i = 0; i < nElements; i++) {
77			CFDataRef		data;
78
79			data = CFDictionaryGetValue(oValues[i], kSCDData);
80			if (data) {
81				CFPropertyListRef	plist;
82
83				nValues[i] = CFDictionaryCreateMutableCopy(NULL, 0, oValues[i]);
84
85				_SCUnserialize(&plist, data, NULL, 0);
86				CFDictionarySetValue((CFMutableDictionaryRef)nValues[i],
87						     kSCDData,
88						     plist);
89				CFRelease(plist);
90			} else {
91				nValues[i] = CFRetain(oValues[i]);
92			}
93		}
94	}
95
96	newStoreData = CFDictionaryCreate(NULL,
97				     keys,
98				     nValues,
99				     nElements,
100				     &kCFTypeDictionaryKeyCallBacks,
101				     &kCFTypeDictionaryValueCallBacks);
102
103	if (nElements > 0) {
104		CFIndex	i;
105
106		for (i = 0; i < nElements; i++) {
107			CFRelease(nValues[i]);
108		}
109
110		if (keys != keys_q) {
111			CFAllocatorDeallocate(NULL, keys);
112			CFAllocatorDeallocate(NULL, oValues);
113			CFAllocatorDeallocate(NULL, nValues);
114		}
115	}
116
117	return newStoreData;
118}
119
120
121__private_extern__
122int
123__SCDynamicStoreSnapshot(SCDynamicStoreRef store)
124{
125	CFDictionaryRef			expandedStoreData;
126	FILE				*f;
127	int				fd;
128	CFDataRef			xmlData;
129
130	/* Save a snapshot of configd's "state" */
131
132	(void) unlink(SNAPSHOT_PATH_STATE);
133	fd = open(SNAPSHOT_PATH_STATE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
134	if (fd == -1) {
135		return kSCStatusFailed;
136	}
137	f = fdopen(fd, "w");
138	if (f == NULL) {
139		return kSCStatusFailed;
140	}
141	SCPrint(TRUE, f, CFSTR("Main thread :\n\n"));
142	SCPrint(TRUE, f, CFSTR("%@\n"), CFRunLoopGetCurrent());
143	if (plugin_runLoop != NULL) {
144		SCPrint(TRUE, f, CFSTR("Plug-in thread :\n\n"));
145		SCPrint(TRUE, f, CFSTR("%@\n"), plugin_runLoop);
146	}
147	listSessions(f);
148	(void) fclose(f);
149
150	/* Save a snapshot of the "store" data */
151
152	(void) unlink(SNAPSHOT_PATH_STORE);
153	fd = open(SNAPSHOT_PATH_STORE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
154	if (fd == -1) {
155		return kSCStatusFailed;
156	}
157
158	expandedStoreData = _expandStore(storeData);
159	xmlData = CFPropertyListCreateData(NULL, expandedStoreData, kCFPropertyListXMLFormat_v1_0, 0, NULL);
160	CFRelease(expandedStoreData);
161	if (xmlData == NULL) {
162		SCLog(TRUE, LOG_ERR, CFSTR("__SCDynamicStoreSnapshot CFPropertyListCreateData() failed"));
163		close(fd);
164		return kSCStatusFailed;
165	}
166	(void) write(fd, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData));
167	(void) close(fd);
168	CFRelease(xmlData);
169
170	/* Save a snapshot of the "pattern" data */
171
172	(void) unlink(SNAPSHOT_PATH_PATTERN);
173	fd = open(SNAPSHOT_PATH_PATTERN, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
174	if (fd == -1) {
175		return kSCStatusFailed;
176	}
177
178	xmlData = CFPropertyListCreateData(NULL, patternData, kCFPropertyListXMLFormat_v1_0, 0, NULL);
179	if (xmlData == NULL) {
180		SCLog(TRUE, LOG_ERR, CFSTR("__SCDynamicStoreSnapshot CFPropertyListCreateData() failed"));
181		close(fd);
182		return kSCStatusFailed;
183	}
184	(void) write(fd, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData));
185	(void) close(fd);
186	CFRelease(xmlData);
187
188	/* Save a snapshot of the "session" data */
189
190	(void) unlink(SNAPSHOT_PATH_SESSION);
191	fd = open(SNAPSHOT_PATH_SESSION, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
192	if (fd == -1) {
193		return kSCStatusFailed;
194	}
195
196	xmlData = CFPropertyListCreateData(NULL, sessionData, kCFPropertyListXMLFormat_v1_0, 0, NULL);
197	if (xmlData == NULL) {
198		SCLog(TRUE, LOG_ERR, CFSTR("__SCDynamicStoreSnapshot CFPropertyListCreateData() failed"));
199		close(fd);
200		return kSCStatusFailed;
201	}
202	(void) write(fd, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData));
203	(void) close(fd);
204	CFRelease(xmlData);
205
206	return kSCStatusOK;
207}
208
209
210__private_extern__
211kern_return_t
212_snapshot(mach_port_t server, int *sc_status, audit_token_t audit_token)
213{
214	serverSessionRef	mySession;
215
216	mySession = getSession(server);
217	if (mySession == NULL) {
218		mySession = tempSession(server, CFSTR("SCDynamicStoreSnapshot"), audit_token);
219		if (mySession == NULL) {
220			/* you must have an open session to play */
221			return kSCStatusNoStoreSession;
222		}
223	}
224
225	if (!hasRootAccess(mySession)) {
226		return kSCStatusAccessError;
227	}
228
229	*sc_status = __SCDynamicStoreSnapshot(mySession->store);
230	return KERN_SUCCESS;
231}
232