]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCProxies.c
configd-453.16.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCProxies.c
1 /*
2 * Copyright (c) 2000-2004, 2006-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 * May 18, 2001 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <TargetConditionals.h>
32 #include <SystemConfiguration/SystemConfiguration.h>
33 #include <SystemConfiguration/SCValidation.h>
34 #include <SystemConfiguration/SCPrivate.h>
35
36 #include <netdb.h>
37
38
39
40
41 CFStringRef
42 SCDynamicStoreKeyCreateProxies(CFAllocatorRef allocator)
43 {
44 return SCDynamicStoreKeyCreateNetworkGlobalEntity(allocator,
45 kSCDynamicStoreDomainState,
46 kSCEntNetProxies);
47 }
48
49
50 static void
51 validate_proxy_content(CFMutableDictionaryRef proxies,
52 CFStringRef proxy_enable,
53 CFStringRef proxy_host,
54 CFStringRef proxy_port,
55 const char * proxy_service,
56 int proxy_defaultport)
57 {
58 int enabled = 0;
59 CFNumberRef num;
60
61 num = CFDictionaryGetValue(proxies, proxy_enable);
62 if (num != NULL) {
63 if (!isA_CFNumber(num) ||
64 !CFNumberGetValue(num, kCFNumberIntType, &enabled)) {
65 // if we don't like the enabled key/value
66 goto disable;
67 }
68 }
69
70 if (proxy_host != NULL) {
71 CFStringRef host;
72
73 host = CFDictionaryGetValue(proxies, proxy_host);
74 if (((enabled == 0) && (host != NULL)) ||
75 ((enabled != 0) && !isA_CFString(host))) {
76 // pass only valid proxy hosts and only when enabled
77 goto disable;
78 }
79 }
80
81 if (proxy_port != NULL) {
82 CFNumberRef port;
83
84 port = CFDictionaryGetValue(proxies, proxy_port);
85 if (((enabled == 0) && (port != NULL)) ||
86 ((enabled != 0) && (port != NULL) && !isA_CFNumber(port))) {
87 // pass only provided/valid proxy ports and only when enabled
88 goto disable;
89 }
90
91 if ((enabled != 0) && (port == NULL)) {
92 struct servent *service;
93 int s_port;
94
95 service = getservbyname(proxy_service, "tcp");
96 if (service != NULL) {
97 s_port = ntohs(service->s_port);
98 } else {
99 s_port = proxy_defaultport;
100 }
101 num = CFNumberCreate(NULL, kCFNumberIntType, &s_port);
102 CFDictionarySetValue(proxies, proxy_port, num);
103 CFRelease(num);
104 }
105 }
106
107 return;
108
109 disable :
110
111 enabled = 0;
112 num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
113 CFDictionarySetValue(proxies, proxy_enable, num);
114 CFRelease(num);
115 if (proxy_host != NULL) {
116 CFDictionaryRemoveValue(proxies, proxy_host);
117 }
118 if (proxy_port != NULL) {
119 CFDictionaryRemoveValue(proxies, proxy_port);
120 }
121
122 return;
123 }
124
125
126 static void
127 normalize_scoped_proxy(const void *key, const void *value, void *context);
128
129
130 static void
131 normalize_supplemental_proxy(const void *value, void *context);
132
133
134 static CF_RETURNS_RETAINED CFDictionaryRef
135 __SCNetworkProxiesCopyNormalized(CFDictionaryRef proxy)
136 {
137 CFArrayRef array;
138 CFMutableDictionaryRef newProxy;
139 CFNumberRef num;
140 CFDictionaryRef scoped;
141 CFArrayRef supplemental;
142
143 if (!isA_CFDictionary(proxy)) {
144 proxy = CFDictionaryCreate(NULL,
145 NULL,
146 NULL,
147 0,
148 &kCFTypeDictionaryKeyCallBacks,
149 &kCFTypeDictionaryValueCallBacks);
150 return proxy;
151 }
152
153 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
154
155 validate_proxy_content(newProxy,
156 kSCPropNetProxiesFTPEnable,
157 kSCPropNetProxiesFTPProxy,
158 kSCPropNetProxiesFTPPort,
159 "ftp",
160 21);
161 validate_proxy_content(newProxy,
162 kSCPropNetProxiesGopherEnable,
163 kSCPropNetProxiesGopherProxy,
164 kSCPropNetProxiesGopherPort,
165 "gopher",
166 70);
167 validate_proxy_content(newProxy,
168 kSCPropNetProxiesHTTPEnable,
169 kSCPropNetProxiesHTTPProxy,
170 kSCPropNetProxiesHTTPPort,
171 "http",
172 80);
173 validate_proxy_content(newProxy,
174 kSCPropNetProxiesHTTPSEnable,
175 kSCPropNetProxiesHTTPSProxy,
176 kSCPropNetProxiesHTTPSPort,
177 "https",
178 443);
179 validate_proxy_content(newProxy,
180 kSCPropNetProxiesRTSPEnable,
181 kSCPropNetProxiesRTSPProxy,
182 kSCPropNetProxiesRTSPPort,
183 "rtsp",
184 554);
185 validate_proxy_content(newProxy,
186 kSCPropNetProxiesSOCKSEnable,
187 kSCPropNetProxiesSOCKSProxy,
188 kSCPropNetProxiesSOCKSPort,
189 "socks",
190 1080);
191 if (CFDictionaryContainsKey(newProxy, kSCPropNetProxiesProxyAutoConfigURLString)) {
192 validate_proxy_content(newProxy,
193 kSCPropNetProxiesProxyAutoConfigEnable,
194 kSCPropNetProxiesProxyAutoConfigURLString,
195 NULL,
196 NULL,
197 0);
198
199 // and we can't have both URLString and JavaScript keys
200 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesProxyAutoConfigJavaScript);
201 } else {
202 validate_proxy_content(newProxy,
203 kSCPropNetProxiesProxyAutoConfigEnable,
204 kSCPropNetProxiesProxyAutoConfigJavaScript,
205 NULL,
206 NULL,
207 0);
208 }
209 validate_proxy_content(newProxy,
210 kSCPropNetProxiesProxyAutoDiscoveryEnable,
211 NULL,
212 NULL,
213 NULL,
214 0);
215
216 // validate FTP passive setting
217 num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesFTPPassive);
218 if (num != NULL) {
219 int enabled = 0;
220
221 if (!isA_CFNumber(num) ||
222 !CFNumberGetValue(num, kCFNumberIntType, &enabled)) {
223 // if we don't like the enabled key/value
224 enabled = 1;
225 num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
226 CFDictionarySetValue(newProxy,
227 kSCPropNetProxiesFTPPassive,
228 num);
229 CFRelease(num);
230 }
231 }
232
233 // validate proxy exception list
234 array = CFDictionaryGetValue(newProxy, kSCPropNetProxiesExceptionsList);
235 if (array != NULL) {
236 CFIndex i;
237 CFIndex n;
238
239 n = isA_CFArray(array) ? CFArrayGetCount(array) : 0;
240 for (i = 0; i < n; i++) {
241 CFStringRef str;
242
243 str = CFArrayGetValueAtIndex(array, i);
244 if (!isA_CFString(str)) {
245 // if we don't like the array contents
246 n = 0;
247 break;
248 }
249 }
250
251 if (n == 0) {
252 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesExceptionsList);
253 }
254 }
255
256 // validate exclude simple hostnames setting
257 num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesExcludeSimpleHostnames);
258 if (num != NULL) {
259 int enabled;
260
261 if (!isA_CFNumber(num) ||
262 !CFNumberGetValue(num, kCFNumberIntType, &enabled)) {
263 // if we don't like the enabled key/value
264 enabled = 0;
265 num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
266 CFDictionarySetValue(newProxy,
267 kSCPropNetProxiesExcludeSimpleHostnames,
268 num);
269 CFRelease(num);
270 }
271 }
272
273 // cleanup scoped proxies
274 scoped = CFDictionaryGetValue(newProxy, kSCPropNetProxiesScoped);
275 if (isA_CFDictionary(scoped)) {
276 CFMutableDictionaryRef newScoped;
277
278 newScoped = CFDictionaryCreateMutable(NULL,
279 0,
280 &kCFTypeDictionaryKeyCallBacks,
281 &kCFTypeDictionaryValueCallBacks);
282 CFDictionaryApplyFunction(scoped,
283 normalize_scoped_proxy,
284 newScoped);
285 CFDictionarySetValue(newProxy, kSCPropNetProxiesScoped, newScoped);
286 CFRelease(newScoped);
287 }
288
289 // cleanup split/supplemental proxies
290 supplemental = CFDictionaryGetValue(newProxy, kSCPropNetProxiesSupplemental);
291 if (isA_CFArray(supplemental)) {
292 CFMutableArrayRef newSupplemental;
293
294 newSupplemental = CFArrayCreateMutable(NULL,
295 0,
296 &kCFTypeArrayCallBacks);
297 CFArrayApplyFunction(supplemental,
298 CFRangeMake(0, CFArrayGetCount(supplemental)),
299 normalize_supplemental_proxy,
300 newSupplemental);
301 CFDictionarySetValue(newProxy, kSCPropNetProxiesSupplemental, newSupplemental);
302 CFRelease(newSupplemental);
303 }
304
305 proxy = CFDictionaryCreateCopy(NULL,newProxy);
306 CFRelease(newProxy);
307
308 return proxy;
309 }
310
311
312 static void
313 normalize_scoped_proxy(const void *key, const void *value, void *context)
314 {
315 CFStringRef interface = (CFStringRef)key;
316 CFDictionaryRef proxy = (CFDictionaryRef)value;
317 CFMutableDictionaryRef newScoped = (CFMutableDictionaryRef)context;
318
319 proxy = __SCNetworkProxiesCopyNormalized(proxy);
320 CFDictionarySetValue(newScoped, interface, proxy);
321 CFRelease(proxy);
322
323 return;
324 }
325
326
327 static void
328 normalize_supplemental_proxy(const void *value, void *context)
329 {
330 CFDictionaryRef proxy = (CFDictionaryRef)value;
331 CFMutableArrayRef newSupplemental = (CFMutableArrayRef)context;
332
333 proxy = __SCNetworkProxiesCopyNormalized(proxy);
334 CFArrayAppendValue(newSupplemental, proxy);
335 CFRelease(proxy);
336
337 return;
338 }
339
340
341 CFDictionaryRef
342 SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
343 {
344 CFStringRef key;
345 CFDictionaryRef proxies;
346
347
348 /* copy proxy information from dynamic store */
349
350 key = SCDynamicStoreKeyCreateProxies(NULL);
351 proxies = SCDynamicStoreCopyValue(store, key);
352 CFRelease(key);
353
354
355 if (proxies != NULL) {
356 CFDictionaryRef base = proxies;
357
358 proxies = __SCNetworkProxiesCopyNormalized(base);
359 CFRelease(base);
360 } else {
361 proxies = CFDictionaryCreate(NULL,
362 NULL,
363 NULL,
364 0,
365 &kCFTypeDictionaryKeyCallBacks,
366 &kCFTypeDictionaryValueCallBacks);
367 }
368
369
370 return proxies;
371 }
372
373
374 CFArrayRef
375 SCNetworkProxiesCopyMatching(CFDictionaryRef globalConfiguration,
376 CFStringRef server,
377 CFStringRef interface)
378 {
379 CFMutableDictionaryRef newProxy;
380 CFArrayRef proxies = NULL;
381 CFDictionaryRef proxy;
382 int sc_status = kSCStatusOK;
383 CFStringRef trimmed = NULL;
384
385 if (!isA_CFDictionary(globalConfiguration)) {
386 // if no proxy configuration
387 _SCErrorSet(kSCStatusOK);
388 return NULL;
389 }
390
391 if (interface != NULL) {
392 CFDictionaryRef scoped;
393
394 if (!isA_CFString(interface) ||
395 (CFStringGetLength(interface) == 0)) {
396 _SCErrorSet(kSCStatusInvalidArgument);
397 return NULL;
398 }
399
400 scoped = CFDictionaryGetValue(globalConfiguration, kSCPropNetProxiesScoped);
401 if (scoped == NULL) {
402 // if no scoped proxy configurations
403 _SCErrorSet(kSCStatusOK);
404 return NULL;
405 }
406
407 if (!isA_CFDictionary(scoped)) {
408 // if corrupt proxy configuration
409 _SCErrorSet(kSCStatusFailed);
410 return NULL;
411 }
412
413 proxy = CFDictionaryGetValue(scoped, interface);
414 if (proxy == NULL) {
415 // if no scoped proxy configuration for this interface
416 _SCErrorSet(kSCStatusOK);
417 return NULL;
418 }
419
420 if (!isA_CFDictionary(proxy)) {
421 // if corrupt proxy configuration
422 _SCErrorSet(kSCStatusFailed);
423 return NULL;
424 }
425
426 // return per-interface proxy configuration
427 proxies = CFArrayCreate(NULL, (const void **)&proxy, 1, &kCFTypeArrayCallBacks);
428 return proxies;
429 }
430
431 if (server != NULL) {
432 CFIndex i;
433 CFMutableArrayRef matching = NULL;
434 CFIndex n = 0;
435 CFIndex server_len;
436 CFArrayRef supplemental;
437
438 trimmed = _SC_trimDomain(server);
439 if (trimmed == NULL) {
440 _SCErrorSet(kSCStatusInvalidArgument);
441 return NULL;
442 }
443
444 server = trimmed;
445 server_len = CFStringGetLength(server);
446
447 supplemental = CFDictionaryGetValue(globalConfiguration, kSCPropNetProxiesSupplemental);
448 if (supplemental != NULL) {
449 if (!isA_CFArray(supplemental)) {
450 // if corrupt proxy configuration
451 sc_status = kSCStatusFailed;
452 goto done;
453 }
454
455 n = CFArrayGetCount(supplemental);
456 }
457
458 for (i = 0; i < n; i++) {
459 CFStringRef domain;
460 CFIndex domain_len;
461 CFIndex n_matching;
462
463 proxy = CFArrayGetValueAtIndex(supplemental, i);
464 if (!isA_CFDictionary(proxy)) {
465 // if corrupt proxy configuration
466 continue;
467 }
468
469 domain = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchDomain);
470 if (!isA_CFString(domain)) {
471 // if corrupt proxy configuration
472 continue;
473 }
474
475 domain_len = CFStringGetLength(domain);
476 if (domain_len > 0) {
477 if (!CFStringFindWithOptions(server,
478 domain,
479 CFRangeMake(0, server_len),
480 kCFCompareCaseInsensitive|kCFCompareAnchored|kCFCompareBackwards,
481 NULL)) {
482 // if server does not match this proxy domain (or host)
483 continue;
484 }
485
486 if ((server_len > domain_len) &&
487 !CFStringFindWithOptions(server,
488 CFSTR("."),
489 CFRangeMake(0, server_len - domain_len),
490 kCFCompareCaseInsensitive|kCFCompareAnchored|kCFCompareBackwards,
491 NULL)) {
492 // if server does not match this proxy domain
493 continue;
494 }
495 // } else {
496 // // if this is a "default" (match all) proxy domain
497 }
498
499 if (matching == NULL) {
500 matching = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
501 }
502 n_matching = CFArrayGetCount(matching);
503
504 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
505 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomain);
506 if ((n_matching == 0) ||
507 !CFArrayContainsValue(matching, CFRangeMake(0, n_matching), newProxy)) {
508 // add this matching proxy
509 CFArrayAppendValue(matching, newProxy);
510 }
511 CFRelease(newProxy);
512 }
513
514 if (matching != NULL) {
515 // if we have any supplemental match domains
516 proxies = CFArrayCreateCopy(NULL, matching);
517 CFRelease(matching);
518 goto done;
519 }
520 }
521
522 // no matches, return "global" proxy configuration
523
524 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, globalConfiguration);
525 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesScoped);
526 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplemental);
527 proxies = CFArrayCreate(NULL, (const void **)&newProxy, 1, &kCFTypeArrayCallBacks);
528 CFRelease(newProxy);
529
530 done :
531
532 if (sc_status != kSCStatusOK) {
533 if (proxies != NULL) {
534 CFRelease(proxies);
535 proxies = NULL;
536 }
537 _SCErrorSet(sc_status);
538 }
539 if (trimmed != NULL) CFRelease(trimmed);
540
541 return proxies;
542 }