]> git.saurik.com Git - apple/configd.git/blob - dnsinfo/dnsinfo_copy.c
configd-888.1.2.tar.gz
[apple/configd.git] / dnsinfo / dnsinfo_copy.c
1 /*
2 * Copyright (c) 2004, 2006, 2008-2013, 2015, 2016 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 * March 9, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <pthread.h>
34 #include <dispatch/dispatch.h>
35 #include <mach/mach.h>
36 #include <os/activity.h>
37 #include <xpc/xpc.h>
38
39 #include "libSystemConfiguration_client.h"
40 #include "dnsinfo.h"
41 #include "dnsinfo_private.h"
42 #include "dnsinfo_internal.h"
43
44
45 const char *
46 dns_configuration_notify_key()
47 {
48 const char *key;
49
50 key = "com.apple.system.SystemConfiguration.dns_configuration";
51 return key;
52 }
53
54
55 #pragma mark -
56 #pragma mark DNS configuration [dnsinfo] client support
57
58
59 // Note: protected by __dns_configuration_queue()
60 static int dnsinfo_active = 0;
61 static libSC_info_client_t *dnsinfo_client = NULL;
62
63
64 static os_activity_t
65 __dns_configuration_activity()
66 {
67 static os_activity_t activity;
68 static dispatch_once_t once;
69
70 dispatch_once(&once, ^{
71 activity = os_activity_create("accessing DNS configuration",
72 OS_ACTIVITY_CURRENT,
73 OS_ACTIVITY_FLAG_DEFAULT);
74 });
75
76 return activity;
77 }
78
79
80 static dispatch_queue_t
81 __dns_configuration_queue()
82 {
83 static dispatch_once_t once;
84 static dispatch_queue_t q;
85
86 dispatch_once(&once, ^{
87 q = dispatch_queue_create(DNSINFO_SERVICE_NAME, NULL);
88 });
89
90 return q;
91 }
92
93
94 dns_config_t *
95 dns_configuration_copy()
96 {
97 uint8_t *buf = NULL;
98 size_t bufLen;
99 dns_config_t *config = NULL;
100 static const char *proc_name = NULL;
101 xpc_object_t reqdict;
102 xpc_object_t reply;
103
104 if (!libSC_info_available()) {
105 os_log(OS_LOG_DEFAULT, "*** DNS configuration requested between fork() and exec()");
106 return NULL;
107 }
108
109 dispatch_sync(__dns_configuration_queue(), ^{
110 if ((dnsinfo_active++ == 0) || (dnsinfo_client == NULL)) {
111 static dispatch_once_t once;
112 static const char *service_name = DNSINFO_SERVICE_NAME;
113
114 dispatch_once(&once, ^{
115 #if DEBUG
116 const char *name;
117
118 // get [XPC] service name
119 name = getenv(service_name);
120 if (name != NULL) {
121 service_name = strdup(name);
122 }
123 #endif // DEBUG
124
125 // get process name
126 proc_name = getprogname();
127 });
128
129 dnsinfo_client =
130 libSC_info_client_create(__dns_configuration_queue(), // dispatch queue
131 service_name, // XPC service name
132 "DNS configuration"); // service description
133 if (dnsinfo_client == NULL) {
134 --dnsinfo_active;
135 }
136 }
137 });
138
139 if ((dnsinfo_client == NULL) || !dnsinfo_client->active) {
140 // if DNS configuration server not available
141 return NULL;
142 }
143
144 // scope DNS configuration activity
145 os_activity_scope(__dns_configuration_activity());
146
147 // create message
148 reqdict = xpc_dictionary_create(NULL, NULL, 0);
149
150 // set process name
151 if (proc_name != NULL) {
152 xpc_dictionary_set_string(reqdict, DNSINFO_PROC_NAME, proc_name);
153 }
154
155 // set request
156 xpc_dictionary_set_int64(reqdict, DNSINFO_REQUEST, DNSINFO_REQUEST_COPY);
157
158 // send request to the DNS configuration server
159 reply = libSC_send_message_with_reply_sync(dnsinfo_client, reqdict);
160 xpc_release(reqdict);
161
162 if (reply != NULL) {
163 const void *dataRef;
164 size_t dataLen = 0;
165
166 dataRef = xpc_dictionary_get_data(reply, DNSINFO_CONFIGURATION, &dataLen);
167 if ((dataRef != NULL) &&
168 ((dataLen >= sizeof(_dns_config_buf_t)) && (dataLen <= DNS_CONFIG_BUF_MAX))) {
169 _dns_config_buf_t *config = (_dns_config_buf_t *)(void *)dataRef;
170 size_t configLen;
171 uint32_t n_attribute = ntohl(config->n_attribute);
172 uint32_t n_padding = ntohl(config->n_padding);
173
174 /*
175 * Check that the size of the configuration header plus the size of the
176 * attribute data matches the size of the configuration buffer.
177 *
178 * If the sizes are different, something that should NEVER happen, CRASH!
179 */
180 configLen = sizeof(_dns_config_buf_t) + n_attribute;
181 assert(configLen == dataLen);
182
183 /*
184 * Check that the size of the requested padding would not result in our
185 * allocating a configuration + padding buffer larger than our maximum size.
186 *
187 * If the requested padding size is too large, something that should NEVER
188 * happen, CRASH!
189 */
190 assert(n_padding <= (DNS_CONFIG_BUF_MAX - dataLen));
191
192 /*
193 * Check that the actual size of the configuration data and any requested
194 * padding will be less than the maximum possible size of the in-memory
195 * configuration buffer.
196 *
197 * If the length needed is too large, something that should NEVER happen, CRASH!
198 */
199 bufLen = dataLen + n_padding;
200 assert(bufLen <= DNS_CONFIG_BUF_MAX);
201
202 // allocate a buffer large enough to hold both the configuration
203 // data and the padding.
204 buf = malloc(bufLen);
205 bcopy((void *)dataRef, buf, dataLen);
206 bzero(&buf[dataLen], n_padding);
207 }
208
209 xpc_release(reply);
210 }
211
212 if (buf != NULL) {
213 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
214 config = _dns_configuration_expand_config((_dns_config_buf_t *)(void *)buf);
215 if (config == NULL) {
216 free(buf);
217 }
218 }
219
220 return config;
221 }
222
223
224 void
225 dns_configuration_free(dns_config_t *config)
226 {
227 if (config == NULL) {
228 return; // ASSERT
229 }
230
231 dispatch_sync(__dns_configuration_queue(), ^{
232 if (--dnsinfo_active == 0) {
233 // if last reference, drop connection
234 libSC_info_client_release(dnsinfo_client);
235 dnsinfo_client = NULL;
236 }
237 });
238
239 free((void *)config);
240 return;
241 }
242
243
244 void
245 _dns_configuration_ack(dns_config_t *config, const char *bundle_id)
246 {
247 xpc_object_t reqdict;
248
249 if (config == NULL) {
250 return; // ASSERT
251 }
252
253 if ((dnsinfo_client == NULL) || !dnsinfo_client->active) {
254 // if DNS configuration server not available
255 return;
256 }
257
258 dispatch_sync(__dns_configuration_queue(), ^{
259 dnsinfo_active++; // keep connection active (for the life of the process)
260 });
261
262 // create message
263 reqdict = xpc_dictionary_create(NULL, NULL, 0);
264
265 // set request
266 xpc_dictionary_set_int64(reqdict, DNSINFO_REQUEST, DNSINFO_REQUEST_ACKNOWLEDGE);
267
268 // set generation
269 xpc_dictionary_set_uint64(reqdict, DNSINFO_GENERATION, config->generation);
270
271 // send acknowledgement to the DNS configuration server
272 xpc_connection_send_message(dnsinfo_client->connection, reqdict);
273
274 xpc_release(reqdict);
275 return;
276 }
277
278 #ifdef MAIN
279
280 int
281 main(int argc, char **argv)
282 {
283 dns_config_t *config;
284
285 config = dns_configuration_copy();
286 if (config != NULL) {
287 dns_configuration_free(config);
288 }
289
290 exit(0);
291 }
292
293 #endif