]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCProxies.c
configd-1109.101.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCProxies.c
1 /*
2 * Copyright (c) 2000-2004, 2006-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 * 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 #if !TARGET_OS_SIMULATOR
39 #include <ne_session.h>
40 #endif // !TARGET_OS_SIMULATOR
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_key,
54 CFStringRef proxy_host_key,
55 CFStringRef proxy_port_key,
56 const char * proxy_service_name,
57 int proxy_defaultport,
58 Boolean multiple_proxies)
59 {
60 int enabled = 0;
61 CFNumberRef num;
62
63 num = CFDictionaryGetValue(proxies, proxy_enable_key);
64 if (num != NULL) {
65 if (!isA_CFNumber(num) ||
66 !CFNumberGetValue(num, kCFNumberIntType, &enabled)) {
67 goto disable; // if we don't like the enabled key/value
68 }
69 }
70
71 if (proxy_host_key != NULL) {
72 CFTypeRef host_val;
73
74 host_val = CFDictionaryGetValue(proxies, proxy_host_key);
75 if ((enabled == 0) && (host_val != NULL)) {
76 goto disable; // if not enabled, remove provided key/value
77 }
78
79 if (enabled != 0) {
80 if (isA_CFString(host_val)) {
81 CFStringRef host = (CFStringRef)host_val;
82
83 if (multiple_proxies) {
84 goto disable; // if multiple proxies expected
85 }
86
87 if (CFStringGetLength(host) == 0) {
88 goto disable; // if proxy host string not valid
89 }
90 } else if (isA_CFArray(host_val)) {
91 CFArrayRef hosts = (CFArrayRef)host_val;
92 CFIndex n;
93
94 if (!multiple_proxies) {
95 goto disable; // if single proxy expected
96 }
97
98 n = CFArrayGetCount(hosts);
99 if (n == 0) {
100 goto disable; // if no hosts provided
101 }
102
103 for (CFIndex i = 0; i < n; i++) {
104 CFStringRef host = CFArrayGetValueAtIndex(hosts, i);
105
106 if (!isA_CFString(host) || (CFStringGetLength(host) == 0)) {
107 goto disable; // if proxy host string not valid
108 }
109 }
110 } else {
111 goto disable; // not valid
112 }
113 }
114 }
115
116 if (proxy_port_key != NULL) {
117 CFNumberRef port;
118 int s_port = 0;
119
120 port = CFDictionaryGetValue(proxies, proxy_port_key);
121 if ((enabled == 0) && (port != NULL)) {
122 goto disable; // if not enabled, remove provided key/value
123 }
124
125 if ((enabled != 0) && (port != NULL)) {
126 if (!isA_CFNumber(port) ||
127 !CFNumberGetValue(port, kCFNumberIntType, &s_port) ||
128 (s_port > UINT16_MAX)) {
129 goto disable; // if enabled, not provided (or not valid)
130 }
131
132 if (s_port == 0) {
133 port = NULL; // if no port # provided, use default
134 }
135 }
136
137 if ((enabled != 0) && (port == NULL)) {
138 struct servent *service;
139
140 if (proxy_service_name == NULL) {
141 goto disable; // no "default" port available
142 }
143
144 service = getservbyname(proxy_service_name, "tcp");
145 if (service != NULL) {
146 s_port = ntohs(service->s_port);
147 } else {
148 s_port = proxy_defaultport;
149 }
150 num = CFNumberCreate(NULL, kCFNumberIntType, &s_port);
151 CFDictionarySetValue(proxies, proxy_port_key, num);
152 CFRelease(num);
153 }
154 }
155
156 return;
157
158 disable :
159
160 enabled = 0;
161 num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
162 CFDictionarySetValue(proxies, proxy_enable_key, num);
163 CFRelease(num);
164 if (proxy_host_key != NULL) {
165 CFDictionaryRemoveValue(proxies, proxy_host_key);
166 }
167 if (proxy_port_key != NULL) {
168 CFDictionaryRemoveValue(proxies, proxy_port_key);
169 }
170
171 return;
172 }
173
174
175 static void
176 normalize_scoped_proxy(const void *key, const void *value, void *context);
177
178
179 static void
180 normalize_services_proxy(const void *key, const void *value, void *context);
181
182
183 static void
184 normalize_supplemental_proxy(const void *value, void *context);
185
186
187 static CF_RETURNS_RETAINED CFDictionaryRef
188 __SCNetworkProxiesCopyNormalized(CFDictionaryRef proxy)
189 {
190 CFArrayRef array;
191 CFMutableDictionaryRef newProxy;
192 CFNumberRef num;
193 CFDictionaryRef scoped;
194 CFDictionaryRef services;
195 CFArrayRef supplemental;
196
197 if (!isA_CFDictionary(proxy)) {
198 proxy = CFDictionaryCreate(NULL,
199 NULL,
200 NULL,
201 0,
202 &kCFTypeDictionaryKeyCallBacks,
203 &kCFTypeDictionaryValueCallBacks);
204 return proxy;
205 }
206
207 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
208
209 validate_proxy_content(newProxy,
210 kSCPropNetProxiesFTPEnable,
211 kSCPropNetProxiesFTPProxy,
212 kSCPropNetProxiesFTPPort,
213 "ftp",
214 21,
215 FALSE);
216 validate_proxy_content(newProxy,
217 kSCPropNetProxiesGopherEnable,
218 kSCPropNetProxiesGopherProxy,
219 kSCPropNetProxiesGopherPort,
220 "gopher",
221 70,
222 FALSE);
223 validate_proxy_content(newProxy,
224 kSCPropNetProxiesHTTPEnable,
225 kSCPropNetProxiesHTTPProxy,
226 kSCPropNetProxiesHTTPPort,
227 "http",
228 80,
229 FALSE);
230 validate_proxy_content(newProxy,
231 kSCPropNetProxiesHTTPSEnable,
232 kSCPropNetProxiesHTTPSProxy,
233 kSCPropNetProxiesHTTPSPort,
234 "https",
235 443,
236 FALSE);
237 validate_proxy_content(newProxy,
238 kSCPropNetProxiesRTSPEnable,
239 kSCPropNetProxiesRTSPProxy,
240 kSCPropNetProxiesRTSPPort,
241 "rtsp",
242 554,
243 FALSE);
244 validate_proxy_content(newProxy,
245 kSCPropNetProxiesSOCKSEnable,
246 kSCPropNetProxiesSOCKSProxy,
247 kSCPropNetProxiesSOCKSPort,
248 "socks",
249 1080,
250 FALSE);
251 validate_proxy_content(newProxy,
252 kSCPropNetProxiesTransportConverterEnable,
253 kSCPropNetProxiesTransportConverterProxy,
254 kSCPropNetProxiesTransportConverterPort,
255 NULL,
256 0,
257 TRUE);
258 if (CFDictionaryContainsKey(newProxy, kSCPropNetProxiesProxyAutoConfigURLString)) {
259 validate_proxy_content(newProxy,
260 kSCPropNetProxiesProxyAutoConfigEnable,
261 kSCPropNetProxiesProxyAutoConfigURLString,
262 NULL,
263 NULL,
264 0,
265 FALSE);
266
267 // and we can't have both URLString and JavaScript keys
268 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesProxyAutoConfigJavaScript);
269 } else {
270 validate_proxy_content(newProxy,
271 kSCPropNetProxiesProxyAutoConfigEnable,
272 kSCPropNetProxiesProxyAutoConfigJavaScript,
273 NULL,
274 NULL,
275 0,
276 FALSE);
277 }
278 validate_proxy_content(newProxy,
279 kSCPropNetProxiesProxyAutoDiscoveryEnable,
280 NULL,
281 NULL,
282 NULL,
283 0,
284 FALSE);
285
286 validate_proxy_content(newProxy,
287 kSCPropNetProxiesFallBackAllowed,
288 NULL,
289 NULL,
290 NULL,
291 0,
292 FALSE);
293
294 // validate FTP passive setting
295 num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesFTPPassive);
296 if (num != NULL) {
297 int enabled = 0;
298
299 if (!isA_CFNumber(num) ||
300 !CFNumberGetValue(num, kCFNumberIntType, &enabled)) {
301 // if we don't like the enabled key/value
302 enabled = 1;
303 num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
304 CFDictionarySetValue(newProxy,
305 kSCPropNetProxiesFTPPassive,
306 num);
307 CFRelease(num);
308 }
309 }
310
311 // validate proxy exception list
312 array = CFDictionaryGetValue(newProxy, kSCPropNetProxiesExceptionsList);
313 if (array != NULL) {
314 CFIndex i;
315 CFIndex n;
316
317 n = isA_CFArray(array) ? CFArrayGetCount(array) : 0;
318 for (i = 0; i < n; i++) {
319 CFStringRef str;
320
321 str = CFArrayGetValueAtIndex(array, i);
322 if (!isA_CFString(str) || (CFStringGetLength(str) == 0)) {
323 // if we don't like the array contents
324 n = 0;
325 break;
326 }
327 }
328
329 if (n == 0) {
330 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesExceptionsList);
331 }
332 }
333
334 // validate exclude simple hostnames setting
335 num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesExcludeSimpleHostnames);
336 if (num != NULL) {
337 int enabled;
338
339 if (!isA_CFNumber(num) ||
340 !CFNumberGetValue(num, kCFNumberIntType, &enabled)) {
341 // if we don't like the enabled key/value
342 enabled = 0;
343 num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
344 CFDictionarySetValue(newProxy,
345 kSCPropNetProxiesExcludeSimpleHostnames,
346 num);
347 CFRelease(num);
348 }
349 }
350
351 // cleanup scoped proxies
352 scoped = CFDictionaryGetValue(newProxy, kSCPropNetProxiesScoped);
353 if (isA_CFDictionary(scoped)) {
354 CFMutableDictionaryRef newScoped;
355
356 newScoped = CFDictionaryCreateMutable(NULL,
357 0,
358 &kCFTypeDictionaryKeyCallBacks,
359 &kCFTypeDictionaryValueCallBacks);
360 CFDictionaryApplyFunction(scoped,
361 normalize_scoped_proxy,
362 newScoped);
363 CFDictionarySetValue(newProxy, kSCPropNetProxiesScoped, newScoped);
364 CFRelease(newScoped);
365 }
366
367 // cleanup services proxies
368 services = CFDictionaryGetValue(newProxy, kSCPropNetProxiesServices);
369 if (isA_CFDictionary(services)) {
370 CFMutableDictionaryRef newServices;
371
372 newServices = CFDictionaryCreateMutable(NULL,
373 0,
374 &kCFTypeDictionaryKeyCallBacks,
375 &kCFTypeDictionaryValueCallBacks);
376 CFDictionaryApplyFunction(services,
377 normalize_services_proxy,
378 newServices);
379 CFDictionarySetValue(newProxy, kSCPropNetProxiesServices, newServices);
380 CFRelease(newServices);
381 }
382
383 // cleanup split/supplemental proxies
384 supplemental = CFDictionaryGetValue(newProxy, kSCPropNetProxiesSupplemental);
385 if (isA_CFArray(supplemental)) {
386 CFMutableArrayRef newSupplemental;
387
388 newSupplemental = CFArrayCreateMutable(NULL,
389 0,
390 &kCFTypeArrayCallBacks);
391 CFArrayApplyFunction(supplemental,
392 CFRangeMake(0, CFArrayGetCount(supplemental)),
393 normalize_supplemental_proxy,
394 newSupplemental);
395 CFDictionarySetValue(newProxy, kSCPropNetProxiesSupplemental, newSupplemental);
396 CFRelease(newSupplemental);
397 }
398
399 proxy = CFDictionaryCreateCopy(NULL,newProxy);
400 CFRelease(newProxy);
401
402 return proxy;
403 }
404
405
406 static void
407 normalize_scoped_proxy(const void *key, const void *value, void *context)
408 {
409 CFStringRef interface = (CFStringRef)key;
410 CFDictionaryRef proxy = (CFDictionaryRef)value;
411 CFMutableDictionaryRef newScoped = (CFMutableDictionaryRef)context;
412
413 proxy = __SCNetworkProxiesCopyNormalized(proxy);
414 CFDictionarySetValue(newScoped, interface, proxy);
415 CFRelease(proxy);
416
417 return;
418 }
419
420 static void
421 normalize_services_proxy(const void *key, const void *value, void *context)
422 {
423 CFNumberRef serviceIndex = (CFNumberRef)key;
424 CFDictionaryRef proxy = (CFDictionaryRef)value;
425 CFMutableDictionaryRef newServices = (CFMutableDictionaryRef)context;
426
427 proxy = __SCNetworkProxiesCopyNormalized(proxy);
428 CFDictionarySetValue(newServices, serviceIndex, proxy);
429 CFRelease(proxy);
430
431 return;
432 }
433
434 static void
435 normalize_supplemental_proxy(const void *value, void *context)
436 {
437 CFDictionaryRef proxy = (CFDictionaryRef)value;
438 CFMutableArrayRef newSupplemental = (CFMutableArrayRef)context;
439
440 proxy = __SCNetworkProxiesCopyNormalized(proxy);
441 CFArrayAppendValue(newSupplemental, proxy);
442 CFRelease(proxy);
443
444 return;
445 }
446
447 CFDictionaryRef
448 SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
449 {
450 return SCDynamicStoreCopyProxiesWithOptions(store, NULL);
451 }
452
453 const CFStringRef kSCProxiesNoGlobal = CFSTR("NO_GLOBAL");
454
455 CFDictionaryRef
456 SCDynamicStoreCopyProxiesWithOptions(SCDynamicStoreRef store, CFDictionaryRef options)
457 {
458 Boolean bypass = FALSE;
459 CFStringRef key;
460 CFDictionaryRef proxies = NULL;
461
462 if (options != NULL) {
463 CFBooleanRef bypassGlobalOption;
464
465 if (!isA_CFDictionary(options)) {
466 _SCErrorSet(kSCStatusInvalidArgument);
467 return NULL;
468 }
469
470 bypassGlobalOption = CFDictionaryGetValue(options, kSCProxiesNoGlobal);
471 if (isA_CFBoolean(bypassGlobalOption) && CFBooleanGetValue(bypassGlobalOption)) {
472 bypass = TRUE;
473 }
474 }
475
476
477 /* copy proxy information from dynamic store */
478
479 key = SCDynamicStoreKeyCreateProxies(NULL);
480 proxies = SCDynamicStoreCopyValue(store, key);
481 CFRelease(key);
482
483 if (isA_CFDictionary(proxies) &&
484 CFDictionaryContainsKey(proxies, kSCPropNetProxiesBypassAllowed)) {
485 CFMutableDictionaryRef newProxies;
486
487 newProxies = CFDictionaryCreateMutableCopy(NULL, 0, proxies);
488 CFRelease(proxies);
489
490 /*
491 * Remove kSCPropNetProxiesBypassAllowed property from network
492 * service based configurations.
493 */
494 CFDictionaryRemoveValue(newProxies, kSCPropNetProxiesBypassAllowed);
495 proxies = newProxies;
496 }
497
498
499 if (proxies != NULL) {
500 CFDictionaryRef base = proxies;
501
502 proxies = __SCNetworkProxiesCopyNormalized(base);
503 CFRelease(base);
504 } else {
505 proxies = CFDictionaryCreate(NULL,
506 NULL,
507 NULL,
508 0,
509 &kCFTypeDictionaryKeyCallBacks,
510 &kCFTypeDictionaryValueCallBacks);
511 }
512
513 return proxies;
514 }
515
516
517 static CFArrayRef
518 _SCNetworkProxiesCopyMatchingInternal(CFDictionaryRef globalConfiguration,
519 CFStringRef server,
520 CFStringRef interface,
521 CFDictionaryRef options)
522 {
523 CFMutableDictionaryRef newProxy;
524 uuid_t match_uuid;
525 CFArrayRef proxies = NULL;
526 CFDictionaryRef proxy;
527 int sc_status = kSCStatusOK;
528 CFStringRef trimmed = NULL;
529
530
531 if (!isA_CFDictionary(globalConfiguration)) {
532 // if no proxy configuration
533 _SCErrorSet(kSCStatusOK);
534 return NULL;
535 }
536
537 uuid_clear(match_uuid);
538
539 if (isA_CFDictionary(options)) {
540 CFUUIDRef euuid;
541
542 interface = CFDictionaryGetValue(options, kSCProxiesMatchInterface);
543 interface = isA_CFString(interface);
544
545 server = CFDictionaryGetValue(options, kSCProxiesMatchServer);
546 server = isA_CFString(server);
547
548 euuid = CFDictionaryGetValue(options, kSCProxiesMatchExecutableUUID);
549 euuid = isA_CFType(euuid, CFUUIDGetTypeID());
550 if (euuid != NULL) {
551 CFUUIDBytes uuid_bytes = CFUUIDGetUUIDBytes(euuid);
552 uuid_copy(match_uuid, (const uint8_t *)&uuid_bytes);
553 }
554 }
555
556 if (interface != NULL) {
557 CFDictionaryRef scoped;
558
559 if (!isA_CFString(interface) ||
560 (CFStringGetLength(interface) == 0)) {
561 _SCErrorSet(kSCStatusInvalidArgument);
562 return NULL;
563 }
564
565 scoped = CFDictionaryGetValue(globalConfiguration, kSCPropNetProxiesScoped);
566 if (scoped == NULL) {
567 #if !TARGET_OS_SIMULATOR
568 if (CFDictionaryContainsKey(globalConfiguration, kSCPropNetProxiesBypassAllowed) &&
569 ne_session_always_on_vpn_configs_present()) {
570 /*
571 * The kSCPropNetProxiesBypassAllowed key will be present
572 * for managed proxy configurations where bypassing is *not*
573 * allowed.
574 *
575 * Also (for now), forcing the use of the managed proxy
576 * configurations will only be done with AOVPN present.
577 */
578 goto useDefault;
579 }
580 #endif // !TARGET_OS_SIMULATOR
581
582 // if no scoped proxy configurations
583 _SCErrorSet(kSCStatusOK);
584 return NULL;
585 }
586
587 if (!isA_CFDictionary(scoped)) {
588 // if corrupt proxy configuration
589 _SCErrorSet(kSCStatusFailed);
590 return NULL;
591 }
592
593 proxy = CFDictionaryGetValue(scoped, interface);
594 if (proxy == NULL) {
595 // if no scoped proxy configuration for this interface
596 _SCErrorSet(kSCStatusOK);
597 return NULL;
598 }
599
600 if (!isA_CFDictionary(proxy)) {
601 // if corrupt proxy configuration
602 _SCErrorSet(kSCStatusFailed);
603 return NULL;
604 }
605
606 // return per-interface proxy configuration
607 proxies = CFArrayCreate(NULL, (const void **)&proxy, 1, &kCFTypeArrayCallBacks);
608 return proxies;
609 }
610
611
612 if (server != NULL) {
613 CFIndex i;
614 CFMutableArrayRef matching = NULL;
615 CFIndex n = 0;
616 CFIndex server_len;
617 CFArrayRef supplemental;
618
619 trimmed = _SC_trimDomain(server);
620 if (trimmed == NULL) {
621 _SCErrorSet(kSCStatusInvalidArgument);
622 return NULL;
623 }
624
625 server = trimmed;
626 server_len = CFStringGetLength(server);
627
628 supplemental = CFDictionaryGetValue(globalConfiguration, kSCPropNetProxiesSupplemental);
629 if (supplemental != NULL) {
630 if (!isA_CFArray(supplemental)) {
631 // if corrupt proxy configuration
632 sc_status = kSCStatusFailed;
633 goto done;
634 }
635
636 n = CFArrayGetCount(supplemental);
637 }
638
639 for (i = 0; i < n; i++) {
640 CFStringRef domain;
641 CFIndex domain_len;
642 CFIndex n_matching;
643
644 proxy = CFArrayGetValueAtIndex(supplemental, i);
645 if (!isA_CFDictionary(proxy)) {
646 // if corrupt proxy configuration
647 continue;
648 }
649
650 domain = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchDomain);
651 if (!isA_CFString(domain)) {
652 // if corrupt proxy configuration
653 continue;
654 }
655
656 domain_len = CFStringGetLength(domain);
657 if (domain_len > 0) {
658 if (!CFStringFindWithOptions(server,
659 domain,
660 CFRangeMake(0, server_len),
661 kCFCompareCaseInsensitive|kCFCompareAnchored|kCFCompareBackwards,
662 NULL)) {
663 // if server does not match this proxy domain (or host)
664 continue;
665 }
666
667 if ((server_len > domain_len) &&
668 !CFStringFindWithOptions(server,
669 CFSTR("."),
670 CFRangeMake(0, server_len - domain_len),
671 kCFCompareCaseInsensitive|kCFCompareAnchored|kCFCompareBackwards,
672 NULL)) {
673 // if server does not match this proxy domain
674 continue;
675 }
676 // } else {
677 // // if this is a "default" (match all) proxy domain
678 }
679
680 if (matching == NULL) {
681 matching = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
682 }
683 n_matching = CFArrayGetCount(matching);
684
685 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
686 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomain);
687 if ((n_matching == 0) ||
688 !CFArrayContainsValue(matching, CFRangeMake(0, n_matching), newProxy)) {
689 // add this matching proxy
690 CFArrayAppendValue(matching, newProxy);
691 }
692 CFRelease(newProxy);
693 }
694
695 if (matching != NULL) {
696 // if we have any supplemental match domains
697 proxies = CFArrayCreateCopy(NULL, matching);
698 CFRelease(matching);
699 goto done;
700 }
701 }
702
703 // no matches, return "global" proxy configuration
704
705 #if !TARGET_OS_SIMULATOR
706 useDefault :
707 #endif // !TARGET_OS_SIMULATOR
708
709 newProxy = CFDictionaryCreateMutableCopy(NULL, 0, globalConfiguration);
710 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesScoped);
711 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesServices);
712 CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplemental);
713 proxies = CFArrayCreate(NULL, (const void **)&newProxy, 1, &kCFTypeArrayCallBacks);
714 CFRelease(newProxy);
715
716 done :
717
718 if (sc_status != kSCStatusOK) {
719 _SCErrorSet(sc_status);
720
721 // Note: if we are returning an error then we must
722 // return w/proxies==NULL. At present, there
723 // is no code (above) that would get here with
724 // proxies!=NULL so we don't need to take any
725 // action but future coder's should beware :-)
726 // if (proxies != NULL) {
727 // CFRelease(proxies);
728 // proxies = NULL;
729 // }
730 }
731 if (trimmed != NULL) CFRelease(trimmed);
732
733 return proxies;
734 }
735
736 CFDataRef
737 SCNetworkProxiesCreateProxyAgentData(CFDictionaryRef proxyConfig)
738 {
739 CFDataRef result = NULL;
740 CFArrayRef newProxy = NULL;
741
742 if (!isA_CFDictionary(proxyConfig)) {
743 SC_log(LOG_ERR, "Invalid proxy configuration");
744 _SCErrorSet(kSCStatusInvalidArgument);
745 return NULL;
746 }
747
748 newProxy = CFArrayCreate(NULL, (const void **)&proxyConfig, 1, &kCFTypeArrayCallBacks);
749 (void)_SCSerialize(newProxy, &result, NULL, NULL);
750 CFRelease(newProxy);
751
752 return result;
753 }
754
755 CFArrayRef
756 SCNetworkProxiesCopyMatching(CFDictionaryRef globalConfiguration,
757 CFStringRef server,
758 CFStringRef interface)
759 {
760 return _SCNetworkProxiesCopyMatchingInternal(globalConfiguration, server, interface, NULL);
761 }
762
763 CFArrayRef
764 SCNetworkProxiesCopyMatchingWithOptions(CFDictionaryRef globalConfiguration,
765 CFDictionaryRef options)
766 {
767 return _SCNetworkProxiesCopyMatchingInternal(globalConfiguration, NULL, NULL, options);
768 }