2 * Copyright (c) 2000-2004, 2006-2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * May 18, 2001 Allan Nathanson <ajn@apple.com>
31 #include <TargetConditionals.h>
32 #include <SystemConfiguration/SystemConfiguration.h>
33 #include <SystemConfiguration/SCValidation.h>
34 #include <SystemConfiguration/SCPrivate.h>
42 SCDynamicStoreKeyCreateProxies(CFAllocatorRef allocator
)
44 return SCDynamicStoreKeyCreateNetworkGlobalEntity(allocator
,
45 kSCDynamicStoreDomainState
,
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
)
61 num
= CFDictionaryGetValue(proxies
, proxy_enable
);
63 if (!isA_CFNumber(num
) ||
64 !CFNumberGetValue(num
, kCFNumberIntType
, &enabled
)) {
65 // if we don't like the enabled key/value
70 if (proxy_host
!= NULL
) {
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
81 if (proxy_port
!= NULL
) {
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
91 if ((enabled
!= 0) && (port
== NULL
)) {
92 struct servent
*service
;
95 service
= getservbyname(proxy_service
, "tcp");
96 if (service
!= NULL
) {
97 s_port
= ntohs(service
->s_port
);
99 s_port
= proxy_defaultport
;
101 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &s_port
);
102 CFDictionarySetValue(proxies
, proxy_port
, num
);
112 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &enabled
);
113 CFDictionarySetValue(proxies
, proxy_enable
, num
);
115 if (proxy_host
!= NULL
) {
116 CFDictionaryRemoveValue(proxies
, proxy_host
);
118 if (proxy_port
!= NULL
) {
119 CFDictionaryRemoveValue(proxies
, proxy_port
);
127 SCDynamicStoreCopyProxies(SCDynamicStoreRef store
)
131 CFMutableDictionaryRef newProxies
= NULL
;
133 CFDictionaryRef proxies
;
134 Boolean tempSession
= FALSE
;
137 /* copy proxy information from dynamic store */
140 store
= SCDynamicStoreCreate(NULL
,
141 CFSTR("SCDynamicStoreCopyProxies"),
150 key
= SCDynamicStoreKeyCreateProxies(NULL
);
151 proxies
= SCDynamicStoreCopyValue(store
, key
);
156 if (proxies
!= NULL
) {
157 if (isA_CFDictionary(proxies
)) {
158 newProxies
= CFDictionaryCreateMutableCopy(NULL
, 0, proxies
);
163 if (newProxies
== NULL
) {
164 newProxies
= CFDictionaryCreateMutable(NULL
,
166 &kCFTypeDictionaryKeyCallBacks
,
167 &kCFTypeDictionaryValueCallBacks
);
170 /* validate [and augment] proxy content */
172 validate_proxy_content(newProxies
,
173 kSCPropNetProxiesFTPEnable
,
174 kSCPropNetProxiesFTPProxy
,
175 kSCPropNetProxiesFTPPort
,
178 validate_proxy_content(newProxies
,
179 kSCPropNetProxiesGopherEnable
,
180 kSCPropNetProxiesGopherProxy
,
181 kSCPropNetProxiesGopherPort
,
184 validate_proxy_content(newProxies
,
185 kSCPropNetProxiesHTTPEnable
,
186 kSCPropNetProxiesHTTPProxy
,
187 kSCPropNetProxiesHTTPPort
,
190 validate_proxy_content(newProxies
,
191 kSCPropNetProxiesHTTPSEnable
,
192 kSCPropNetProxiesHTTPSProxy
,
193 kSCPropNetProxiesHTTPSPort
,
196 validate_proxy_content(newProxies
,
197 kSCPropNetProxiesRTSPEnable
,
198 kSCPropNetProxiesRTSPProxy
,
199 kSCPropNetProxiesRTSPPort
,
202 validate_proxy_content(newProxies
,
203 kSCPropNetProxiesSOCKSEnable
,
204 kSCPropNetProxiesSOCKSProxy
,
205 kSCPropNetProxiesSOCKSPort
,
208 if (CFDictionaryContainsKey(newProxies
, kSCPropNetProxiesProxyAutoConfigURLString
)) {
209 validate_proxy_content(newProxies
,
210 kSCPropNetProxiesProxyAutoConfigEnable
,
211 kSCPropNetProxiesProxyAutoConfigURLString
,
216 // and we can't have both URLString and JavaScript keys
217 CFDictionaryRemoveValue(newProxies
, kSCPropNetProxiesProxyAutoConfigJavaScript
);
219 validate_proxy_content(newProxies
,
220 kSCPropNetProxiesProxyAutoConfigEnable
,
221 kSCPropNetProxiesProxyAutoConfigJavaScript
,
226 validate_proxy_content(newProxies
,
227 kSCPropNetProxiesProxyAutoDiscoveryEnable
,
233 // validate FTP passive setting
234 num
= CFDictionaryGetValue(newProxies
, kSCPropNetProxiesFTPPassive
);
238 if (!isA_CFNumber(num
) ||
239 !CFNumberGetValue(num
, kCFNumberIntType
, &enabled
)) {
240 // if we don't like the enabled key/value
242 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &enabled
);
243 CFDictionarySetValue(newProxies
,
244 kSCPropNetProxiesFTPPassive
,
250 // validate proxy exception list
251 array
= CFDictionaryGetValue(newProxies
, kSCPropNetProxiesExceptionsList
);
256 n
= isA_CFArray(array
) ? CFArrayGetCount(array
) : 0;
257 for (i
= 0; i
< n
; i
++) {
260 str
= CFArrayGetValueAtIndex(array
, i
);
261 if (!isA_CFString(str
)) {
262 // if we don't like the array contents
269 CFDictionaryRemoveValue(newProxies
, kSCPropNetProxiesExceptionsList
);
273 // validate exclude simple hostnames setting
274 num
= CFDictionaryGetValue(newProxies
, kSCPropNetProxiesExcludeSimpleHostnames
);
278 if (!isA_CFNumber(num
) ||
279 !CFNumberGetValue(num
, kCFNumberIntType
, &enabled
)) {
280 // if we don't like the enabled key/value
282 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &enabled
);
283 CFDictionarySetValue(newProxies
,
284 kSCPropNetProxiesExcludeSimpleHostnames
,
291 proxies
= CFDictionaryCreateCopy(NULL
, newProxies
);
292 CFRelease(newProxies
);
294 if (tempSession
) CFRelease(store
);
300 SCNetworkProxiesCopyMatching(CFDictionaryRef globalConfiguration
,
302 CFStringRef interface
)
304 CFMutableDictionaryRef newProxy
;
305 CFArrayRef proxies
= NULL
;
306 CFDictionaryRef proxy
;
307 int sc_status
= kSCStatusOK
;
308 CFStringRef trimmed
= NULL
;
310 if (!isA_CFDictionary(globalConfiguration
)) {
311 // if no proxy configuration
312 _SCErrorSet(kSCStatusOK
);
316 if (interface
!= NULL
) {
317 CFDictionaryRef scoped
;
319 if (!isA_CFString(interface
) ||
320 (CFStringGetLength(interface
) == 0)) {
321 _SCErrorSet(kSCStatusInvalidArgument
);
325 scoped
= CFDictionaryGetValue(globalConfiguration
, kSCPropNetProxiesScoped
);
326 if (scoped
== NULL
) {
327 // if no scoped proxy configurations
328 _SCErrorSet(kSCStatusOK
);
332 if (!isA_CFDictionary(scoped
)) {
333 // if corrupt proxy configuration
334 _SCErrorSet(kSCStatusFailed
);
338 proxy
= CFDictionaryGetValue(scoped
, interface
);
340 // if no scoped proxy configuration for this interface
341 _SCErrorSet(kSCStatusOK
);
345 if (!isA_CFDictionary(proxy
)) {
346 // if corrupt proxy configuration
347 _SCErrorSet(kSCStatusFailed
);
351 // return per-interface proxy configuration
352 proxies
= CFArrayCreate(NULL
, (const void **)&proxy
, 1, &kCFTypeArrayCallBacks
);
356 if (server
!= NULL
) {
358 CFMutableArrayRef matching
= NULL
;
361 CFArrayRef supplemental
;
363 trimmed
= _SC_trimDomain(server
);
364 if (trimmed
== NULL
) {
365 _SCErrorSet(kSCStatusInvalidArgument
);
370 server_len
= CFStringGetLength(server
);
372 supplemental
= CFDictionaryGetValue(globalConfiguration
, kSCPropNetProxiesSupplemental
);
373 if (supplemental
== NULL
) {
374 // if no supplemental configurations
378 if (!isA_CFArray(supplemental
)) {
379 // if corrupt proxy configuration
380 sc_status
= kSCStatusFailed
;
384 n
= CFArrayGetCount(supplemental
);
385 for (i
= 0; i
< n
; i
++) {
390 proxy
= CFArrayGetValueAtIndex(supplemental
, i
);
391 if (!isA_CFDictionary(proxy
)) {
392 // if corrupt proxy configuration
396 domain
= CFDictionaryGetValue(proxy
, kSCPropNetProxiesSupplementalMatchDomain
);
397 if (!isA_CFString(domain
)) {
398 // if corrupt proxy configuration
402 domain_len
= CFStringGetLength(domain
);
403 if (domain_len
> 0) {
404 if (!CFStringFindWithOptions(server
,
406 CFRangeMake(0, server_len
),
407 kCFCompareCaseInsensitive
|kCFCompareAnchored
|kCFCompareBackwards
,
409 // if server does not match this proxy domain (or host)
413 if ((server_len
> domain_len
) &&
414 !CFStringFindWithOptions(server
,
416 CFRangeMake(0, server_len
- domain_len
),
417 kCFCompareCaseInsensitive
|kCFCompareAnchored
|kCFCompareBackwards
,
419 // if server does not match this proxy domain
423 // // if this is a "default" (match all) proxy domain
426 if (matching
== NULL
) {
427 matching
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
429 n_matching
= CFArrayGetCount(matching
);
431 newProxy
= CFDictionaryCreateMutableCopy(NULL
, 0, proxy
);
432 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesSupplementalMatchDomain
);
433 if ((n_matching
== 0) ||
434 !CFArrayContainsValue(matching
, CFRangeMake(0, n_matching
), newProxy
)) {
435 // add this matching proxy
436 CFArrayAppendValue(matching
, newProxy
);
441 if (matching
!= NULL
) {
442 // if we have any supplemental match domains
443 proxies
= CFArrayCreateCopy(NULL
, matching
);
449 // no matches, return "global" proxy configuration
451 newProxy
= CFDictionaryCreateMutableCopy(NULL
, 0, globalConfiguration
);
452 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesScoped
);
453 CFDictionaryRemoveValue(newProxy
, kSCPropNetProxiesSupplemental
);
454 proxies
= CFArrayCreate(NULL
, (const void **)&newProxy
, 1, &kCFTypeArrayCallBacks
);
459 if (sc_status
!= kSCStatusOK
) {
460 if (proxies
!= NULL
) {
464 _SCErrorSet(sc_status
);
466 if (trimmed
!= NULL
) CFRelease(trimmed
);