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