]> git.saurik.com Git - apple/cf.git/blob - CFSocketStream.c
CF-635.19.tar.gz
[apple/cf.git] / CFSocketStream.c
1 /*
2 * Copyright (c) 2012 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 /* CFSocketStream.c
25 Copyright (c) 2000-2011, Apple Inc. All rights reserved.
26 Responsibility: Jeremy Wyld
27 */
28 // Original Author: Becky Willrich
29 #include <CoreFoundation/CFStream.h>
30 #include <CoreFoundation/CFNumber.h>
31 #include "CFInternal.h"
32 #include "CFStreamInternal.h"
33 #include "CFStreamPriv.h"
34
35 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
36 // On Mach these live in CF for historical reasons, even though they are declared in CFNetwork
37
38 const int kCFStreamErrorDomainSSL = 3;
39 const int kCFStreamErrorDomainSOCKS = 5;
40
41 CONST_STRING_DECL(kCFStreamPropertyShouldCloseNativeSocket, "kCFStreamPropertyShouldCloseNativeSocket")
42 CONST_STRING_DECL(kCFStreamPropertyAutoErrorOnSystemChange, "kCFStreamPropertyAutoErrorOnSystemChange");
43
44 CONST_STRING_DECL(kCFStreamPropertySOCKSProxy, "kCFStreamPropertySOCKSProxy")
45 CONST_STRING_DECL(kCFStreamPropertySOCKSProxyHost, "SOCKSProxy")
46 CONST_STRING_DECL(kCFStreamPropertySOCKSProxyPort, "SOCKSPort")
47 CONST_STRING_DECL(kCFStreamPropertySOCKSVersion, "kCFStreamPropertySOCKSVersion")
48 CONST_STRING_DECL(kCFStreamSocketSOCKSVersion4, "kCFStreamSocketSOCKSVersion4")
49 CONST_STRING_DECL(kCFStreamSocketSOCKSVersion5, "kCFStreamSocketSOCKSVersion5")
50 CONST_STRING_DECL(kCFStreamPropertySOCKSUser, "kCFStreamPropertySOCKSUser")
51 CONST_STRING_DECL(kCFStreamPropertySOCKSPassword, "kCFStreamPropertySOCKSPassword")
52
53 CONST_STRING_DECL(kCFStreamPropertySocketSecurityLevel, "kCFStreamPropertySocketSecurityLevel");
54 CONST_STRING_DECL(kCFStreamSocketSecurityLevelNone, "kCFStreamSocketSecurityLevelNone");
55 CONST_STRING_DECL(kCFStreamSocketSecurityLevelSSLv2, "kCFStreamSocketSecurityLevelSSLv2");
56 CONST_STRING_DECL(kCFStreamSocketSecurityLevelSSLv3, "kCFStreamSocketSecurityLevelSSLv3");
57 CONST_STRING_DECL(kCFStreamSocketSecurityLevelTLSv1, "kCFStreamSocketSecurityLevelTLSv1");
58 CONST_STRING_DECL(kCFStreamSocketSecurityLevelNegotiatedSSL, "kCFStreamSocketSecurityLevelNegotiatedSSL");
59
60 #endif
61
62
63 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
64 #elif DEPLOYMENT_TARGET_WINDOWS
65 typedef void (*CF_SOCKET_STREAM_PAIR)(CFAllocatorRef, CFStringRef, UInt32, CFSocketNativeHandle, const CFSocketSignature*, CFReadStreamRef*, CFWriteStreamRef*);
66 #else
67 #error Unknown or unspecified DEPLOYMENT_TARGET
68 #endif
69
70 // These are duplicated in CFNetwork, who actually externs them in its headers
71 CONST_STRING_DECL(kCFStreamPropertySocketSSLContext, "kCFStreamPropertySocketSSLContext")
72 CONST_STRING_DECL(_kCFStreamPropertySocketSecurityAuthenticatesServerCertificate, "_kCFStreamPropertySocketSecurityAuthenticatesServerCertificate");
73
74
75 CF_EXPORT
76 void _CFSocketStreamSetAuthenticatesServerCertificateDefault(Boolean shouldAuthenticate) {
77 CFLog(__kCFLogAssertion, CFSTR("_CFSocketStreamSetAuthenticatesServerCertificateDefault(): This call has been deprecated. Use SetProperty(_kCFStreamPropertySocketSecurityAuthenticatesServerCertificate, kCFBooleanTrue/False)\n"));
78 }
79
80
81 /* CF_EXPORT */ Boolean
82 _CFSocketStreamGetAuthenticatesServerCertificateDefault(void) {
83 CFLog(__kCFLogAssertion, CFSTR("_CFSocketStreamGetAuthenticatesServerCertificateDefault(): This call has been removed as a security risk. Use security properties on individual streams instead.\n"));
84 return FALSE;
85 }
86
87
88 /* CF_EXPORT */ void
89 _CFSocketStreamPairSetAuthenticatesServerCertificate(CFReadStreamRef rStream, CFWriteStreamRef wStream, Boolean authenticates) {
90
91 CFBooleanRef value = (!authenticates ? kCFBooleanFalse : kCFBooleanTrue);
92
93 if (rStream)
94 CFReadStreamSetProperty(rStream, _kCFStreamPropertySocketSecurityAuthenticatesServerCertificate, value);
95 else
96 CFWriteStreamSetProperty(wStream, _kCFStreamPropertySocketSecurityAuthenticatesServerCertificate, value);
97 }
98
99
100 // Flags for dyld loading of libraries.
101 enum {
102 kTriedToLoad = 0,
103 kInitialized
104 };
105
106 static struct {
107 CFSpinLock_t lock;
108 UInt32 flags;
109 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
110 #elif DEPLOYMENT_TARGET_WINDOWS
111 HMODULE image;
112 #else
113 #error Unknown or unspecified DEPLOYMENT_TARGET
114 #endif
115 void (*_CFSocketStreamCreatePair)(CFAllocatorRef, CFStringRef, UInt32, CFSocketNativeHandle, const CFSocketSignature*, CFReadStreamRef*, CFWriteStreamRef*);
116 CFErrorRef (*_CFErrorCreateWithStreamError)(CFAllocatorRef, CFStreamError*);
117 CFStreamError (*_CFStreamErrorFromCFError)(CFErrorRef);
118 } CFNetworkSupport = {
119 CFSpinLockInit,
120 0x0,
121 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
122 #elif DEPLOYMENT_TARGET_WINDOWS
123 NULL,
124 #else
125 #error Unknown or unspecified DEPLOYMENT_TARGET
126 #endif
127 NULL,
128 NULL,
129 NULL
130 };
131
132 #define CFNETWORK_CALL(sym, args) ((CFNetworkSupport.sym)args)
133
134 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
135 #define CFNETWORK_LOAD_SYM(sym) __CFLookupCFNetworkFunction(#sym)
136 #elif DEPLOYMENT_TARGET_WINDOWS
137 #define CFNETWORK_LOAD_SYM(sym) (void *)GetProcAddress(CFNetworkSupport.image, #sym)
138 #else
139 #error Unknown or unspecified DEPLOYMENT_TARGET
140 #endif
141
142 static void initializeCFNetworkSupport(void) {
143 __CFBitSet(CFNetworkSupport.flags, kTriedToLoad);
144
145 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
146 CFNetworkSupport._CFSocketStreamCreatePair = CFNETWORK_LOAD_SYM(_CFSocketStreamCreatePair);
147 CFNetworkSupport._CFErrorCreateWithStreamError = CFNETWORK_LOAD_SYM(_CFErrorCreateWithStreamError);
148 CFNetworkSupport._CFStreamErrorFromCFError = CFNETWORK_LOAD_SYM(_CFStreamErrorFromCFError);
149 #elif DEPLOYMENT_TARGET_WINDOWS
150 if (!CFNetworkSupport.image) {
151 #if _DEBUG
152 CFNetworkSupport.image = GetModuleHandleW(L"CFNetwork_debug.dll");
153 #else
154 CFNetworkSupport.image = GetModuleHandleW(L"CFNetwork.dll");
155 #endif
156 }
157
158 if (!CFNetworkSupport.image) {
159 // not loaded yet, try to load from the filesystem
160 char path[MAX_PATH+1];
161 if (!CFNetworkSupport.image) {
162 strlcpy(path, (const char *)_CFDLLPath(), sizeof(path));
163 #if _DEBUG
164 strlcat(path, "\\CFNetwork_debug.dll", sizeof(path));
165 #else
166 strlcat(path, "\\CFNetwork.dll", sizeof(path));
167 #endif
168 CFNetworkSupport.image = LoadLibraryA(path);
169 }
170 }
171
172 if (!CFNetworkSupport.image) {
173 CFLog(__kCFLogAssertion, CFSTR("CoreFoundation: failed to dynamically load CFNetwork"));
174 } else {
175 CFNetworkSupport._CFSocketStreamCreatePair = (CF_SOCKET_STREAM_PAIR)CFNETWORK_LOAD_SYM(_CFSocketStreamCreatePair);
176 CFNetworkSupport._CFErrorCreateWithStreamError = (CFErrorRef(*)(CFAllocatorRef, CFStreamError *))CFNETWORK_LOAD_SYM(_CFErrorCreateWithStreamError);
177 CFNetworkSupport._CFStreamErrorFromCFError = (CFStreamError(*)(CFErrorRef))CFNETWORK_LOAD_SYM(_CFStreamErrorFromCFError);
178 }
179 #else
180 #error Unknown or unspecified DEPLOYMENT_TARGET
181 #endif
182
183 if (!CFNetworkSupport._CFSocketStreamCreatePair) CFLog(__kCFLogAssertion, CFSTR("CoreFoundation: failed to dynamically link symbol _CFSocketStreamCreatePair"));
184 if (!CFNetworkSupport._CFErrorCreateWithStreamError) CFLog(__kCFLogAssertion, CFSTR("CoreFoundation: failed to dynamically link symbol _CFErrorCreateWithStreamError"));
185 if (!CFNetworkSupport._CFStreamErrorFromCFError) CFLog(__kCFLogAssertion, CFSTR("CoreFoundation: failed to dynamically link symbol _CFStreamErrorFromCFError"));
186
187 __CFBitSet(CFNetworkSupport.flags, kInitialized);
188 }
189
190 static void
191 createPair(CFAllocatorRef alloc, CFStringRef host, UInt32 port, CFSocketNativeHandle sock, const CFSocketSignature* sig, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream)
192 {
193 if (readStream)
194 *readStream = NULL;
195
196 if (writeStream)
197 *writeStream = NULL;
198
199 __CFSpinLock(&(CFNetworkSupport.lock));
200 if (!__CFBitIsSet(CFNetworkSupport.flags, kTriedToLoad)) initializeCFNetworkSupport();
201 __CFSpinUnlock(&(CFNetworkSupport.lock));
202
203 CFNETWORK_CALL(_CFSocketStreamCreatePair, (alloc, host, port, sock, sig, readStream, writeStream));
204 }
205
206
207 CF_EXPORT void CFStreamCreatePairWithSocket(CFAllocatorRef alloc, CFSocketNativeHandle sock, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream) {
208 createPair(alloc, NULL, 0, sock, NULL, readStream, writeStream);
209 }
210
211 CF_EXPORT void CFStreamCreatePairWithSocketToHost(CFAllocatorRef alloc, CFStringRef host, UInt32 port, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream) {
212 createPair(alloc, host, port, 0, NULL, readStream, writeStream);
213 }
214
215 CF_EXPORT void CFStreamCreatePairWithPeerSocketSignature(CFAllocatorRef alloc, const CFSocketSignature* sig, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream) {
216 createPair(alloc, NULL, 0, 0, sig, readStream, writeStream);
217 }
218
219 __private_extern__ CFStreamError _CFStreamErrorFromError(CFErrorRef error) {
220 CFStreamError result;
221 Boolean canUpCall;
222
223 __CFSpinLock(&(CFNetworkSupport.lock));
224 if (!__CFBitIsSet(CFNetworkSupport.flags, kTriedToLoad)) initializeCFNetworkSupport();
225 canUpCall = (CFNetworkSupport._CFStreamErrorFromCFError != NULL);
226 __CFSpinUnlock(&(CFNetworkSupport.lock));
227
228 if (canUpCall) {
229 result = CFNETWORK_CALL(_CFStreamErrorFromCFError, (error));
230 } else {
231 CFStringRef domain = CFErrorGetDomain(error);
232 if (CFEqual(domain, kCFErrorDomainPOSIX)) {
233 result.domain = kCFStreamErrorDomainPOSIX;
234 } else if (CFEqual(domain, kCFErrorDomainOSStatus)) {
235 result.domain = kCFStreamErrorDomainMacOSStatus;
236 } else if (CFEqual(domain, kCFErrorDomainMach)) {
237 result.domain = 11; // kCFStreamErrorDomainMach, but that symbol is in CFNetwork
238 } else {
239 result.domain = kCFStreamErrorDomainCustom;
240 }
241 result.error = CFErrorGetCode(error);
242 }
243 return result;
244 }
245
246 __private_extern__ CFErrorRef _CFErrorFromStreamError(CFAllocatorRef alloc, CFStreamError *streamError) {
247 CFErrorRef result;
248 Boolean canUpCall;
249
250 __CFSpinLock(&(CFNetworkSupport.lock));
251 if (!__CFBitIsSet(CFNetworkSupport.flags, kTriedToLoad)) initializeCFNetworkSupport();
252 canUpCall = (CFNetworkSupport._CFErrorCreateWithStreamError != NULL);
253 __CFSpinUnlock(&(CFNetworkSupport.lock));
254
255 if (canUpCall) {
256 result = CFNETWORK_CALL(_CFErrorCreateWithStreamError, (alloc, streamError));
257 } else {
258 if (streamError->domain == kCFStreamErrorDomainPOSIX) {
259 return CFErrorCreate(alloc, kCFErrorDomainPOSIX, streamError->error, NULL);
260 } else if (streamError->domain == kCFStreamErrorDomainMacOSStatus) {
261 return CFErrorCreate(alloc, kCFErrorDomainOSStatus, streamError->error, NULL);
262 } else {
263 CFStringRef key = CFSTR("CFStreamErrorDomainKey");
264 CFNumberRef value = CFNumberCreate(alloc, kCFNumberCFIndexType, &streamError->domain);
265 CFDictionaryRef dict = CFDictionaryCreate(alloc, (const void **)(&key), (const void **)(&value), 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
266 result = CFErrorCreate(alloc, CFSTR("BogusCFStreamErrorCompatibilityDomain"), streamError->error, dict);
267 CFRelease(value);
268 CFRelease(dict);
269 }
270 }
271 return result;
272 }