Example #1
0
CURLcode SSLImpl::connect(int sockfd, int nonblocking, int *done, int ssl_verify_peer, void *storage, char* host_name)
{
    ssl_data_t *data = (ssl_data_t*)storage;
    
    CFStreamCreatePairWithSocket(kCFAllocatorDefault, sockfd, &data->readStream, &data->writeStream);
    // Indicate that the connection needs to be done in secure manner
    CFReadStreamSetProperty(data->readStream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelSSLv3);
    CFWriteStreamSetProperty(data->writeStream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelSSLv3);
    
    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
                &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    if (!dict) {
        RAWLOG_ERROR("Can not allocate CFMutableDictionaryRef");
        return CURLE_SSL_CONNECT_ERROR;
    }
    
    CFDictionarySetValue(dict, kCFStreamSSLValidatesCertificateChain, ssl_verify_peer ? kCFBooleanTrue : kCFBooleanFalse);
    CFReadStreamSetProperty(data->readStream, kCFStreamPropertySSLSettings, dict);
    CFWriteStreamSetProperty(data->writeStream, kCFStreamPropertySSLSettings, dict);
    CFRelease(dict);
    
    if (!CFReadStreamOpen(data->readStream) || !CFWriteStreamOpen(data->writeStream)) {
        RAWLOG_ERROR("SSL connection error");
        return CURLE_SSL_CONNECT_ERROR;
    }
    CFReadStreamScheduleWithRunLoop(    data->readStream,
                                        CFRunLoopGetCurrent(),
                                        kCFRunLoopCommonModes);
    CFWriteStreamScheduleWithRunLoop(    data->writeStream,
                                    CFRunLoopGetCurrent(),
                                    kCFRunLoopCommonModes);
    *done = 1;
    return CURLE_OK;
}
Example #2
0
/* MyCFStreamSetUsernamePassword applies the specified user name and password to the stream. */
static void
MyCFStreamSetUsernamePassword(CFTypeRef stream, CFStringRef username, CFStringRef password)
{
    Boolean success;
    assert(stream != NULL);
    assert( (username != NULL) || (password == NULL) );
    
    if (username && CFStringGetLength(username) > 0) {

        if (CFGetTypeID(stream) == CFReadStreamGetTypeID()) {
            success = CFReadStreamSetProperty((CFReadStreamRef)stream, kCFStreamPropertyFTPUserName, username);
            assert(success);
            if (password) {
                success = CFReadStreamSetProperty((CFReadStreamRef)stream, kCFStreamPropertyFTPPassword, password);
                assert(success);
            }
        } else if (CFGetTypeID(stream) == CFWriteStreamGetTypeID()) {
            success = CFWriteStreamSetProperty((CFWriteStreamRef)stream, kCFStreamPropertyFTPUserName, username);
            assert(success);
            if (password) {
                success = CFWriteStreamSetProperty((CFWriteStreamRef)stream, kCFStreamPropertyFTPPassword, password);
                assert(success);
            }
        } else {
            assert(false);
        }
    }
}
void SocketStreamHandle::createStreams()
{
    if (m_connectionType == Unknown)
        chooseProxy();

    // If it's still unknown, then we're resolving a PAC file asynchronously.
    if (m_connectionType == Unknown)
        return;

    RetainPtr<CFStringRef> host = m_url.host().createCFString();

    // Creating streams to final destination, not to proxy.
    CFReadStreamRef readStream = 0;
    CFWriteStreamRef writeStream = 0;
    CFStreamCreatePairWithSocketToHost(0, host.get(), port(), &readStream, &writeStream);
#if PLATFORM(IOS) || (PLATFORM(MAC) && MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
    // <rdar://problem/12855587> _kCFStreamSocketSetNoDelay is not exported on Windows
    CFWriteStreamSetProperty(writeStream, _kCFStreamSocketSetNoDelay, kCFBooleanTrue);
#endif

    m_readStream.adoptCF(readStream);
    m_writeStream.adoptCF(writeStream);

    switch (m_connectionType) {
    case Unknown:
        ASSERT_NOT_REACHED();
        break;
    case Direct:
        break;
    case SOCKSProxy: {
        // FIXME: SOCKS5 doesn't do challenge-response, should we try to apply credentials from Keychain right away?
        // But SOCKS5 credentials don't work at the time of this writing anyway, see <rdar://6776698>.
        const void* proxyKeys[] = { kCFStreamPropertySOCKSProxyHost, kCFStreamPropertySOCKSProxyPort };
        const void* proxyValues[] = { m_proxyHost.get(), m_proxyPort.get() };
        RetainPtr<CFDictionaryRef> connectDictionary(AdoptCF, CFDictionaryCreate(0, proxyKeys, proxyValues, WTF_ARRAY_LENGTH(proxyKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
        CFReadStreamSetProperty(m_readStream.get(), kCFStreamPropertySOCKSProxy, connectDictionary.get());
        break;
        }
    case CONNECTProxy:
        wkSetCONNECTProxyForStream(m_readStream.get(), m_proxyHost.get(), m_proxyPort.get());
        break;
    }

    if (shouldUseSSL()) {
        const void* keys[] = { kCFStreamSSLPeerName, kCFStreamSSLLevel };
        const void* values[] = { host.get(), kCFStreamSocketSecurityLevelNegotiatedSSL };
        RetainPtr<CFDictionaryRef> settings(AdoptCF, CFDictionaryCreate(0, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
        CFReadStreamSetProperty(m_readStream.get(), kCFStreamPropertySSLSettings, settings.get());
        CFWriteStreamSetProperty(m_writeStream.get(), kCFStreamPropertySSLSettings, settings.get());
    }
}
Example #4
0
CFReadStreamRef HTTP_Stream::createReadStream(CFURLRef url)
{
    CFReadStreamRef readStream = 0;
    CFHTTPMessageRef request = 0;
    CFDictionaryRef proxySettings = 0;
    
    Stream_Configuration *config = Stream_Configuration::configuration();
    
    if (!(request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, httpRequestMethod, url, kCFHTTPVersion1_1))) {
        goto out;
    }
    
    if (config->userAgent) {
        CFHTTPMessageSetHeaderFieldValue(request, httpUserAgentHeader, config->userAgent);
    }
    
    CFHTTPMessageSetHeaderFieldValue(request, icyMetaDataHeader, icyMetaDataValue);
    
    if (m_position.start > 0 && m_position.end > m_position.start) {
        CFStringRef rangeHeaderValue = CFStringCreateWithFormat(NULL,
                                                                NULL,
                                                                CFSTR("bytes=%llu-%llu"),
                                                                m_position.start,
                                                                m_position.end);
        
        CFHTTPMessageSetHeaderFieldValue(request, httpRangeHeader, rangeHeaderValue);
        CFRelease(rangeHeaderValue);
    }
    
    if (!(readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request))) {
        goto out;
    }
    
    CFReadStreamSetProperty(readStream,
                            kCFStreamPropertyHTTPShouldAutoredirect,
                            kCFBooleanTrue);
    
    proxySettings = CFNetworkCopySystemProxySettings();
    if (proxySettings) {
        CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, proxySettings);
        CFRelease(proxySettings);
    }
    
out:
    if (request) {
        CFRelease(request);
    }
    
    return readStream;
}
Example #5
0
static void
nc_trigger(int argc, char **argv)
{
	Boolean		background	= FALSE;
	int		i;
	CFStringRef	hostName	= NULL;
	int		port		= 80;

	for (i = 0; i < 3 && i < argc; i++) {
		/* Parse host name. Must be first arg. */
		if (i == 0) {
			hostName = CFStringCreateWithCString(NULL, argv[i], kCFStringEncodingUTF8);
			continue;
		}

		/* Check for optional background flag */
		if (strcmp(argv[i], "background") == 0) {
			background = TRUE;
			continue;
		}

		/* Parse optional port number */
		CFStringRef str = CFStringCreateWithCString(NULL, argv[i], kCFStringEncodingUTF8);
		if (str) {
			int num = CFStringGetIntValue(str);
			if (num) {
				port = num;
			}
			my_CFRelease(&str);
		}
	}

	if (hostName) {
		CFReadStreamRef		readStream	= NULL;
		CFWriteStreamRef	writeStream	= NULL;

		CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, hostName, port, &readStream, &writeStream);

		if (background) {
			CFReadStreamSetProperty(readStream, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground"));
			CFWriteStreamSetProperty(writeStream, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground"));
		}

		if (readStream && writeStream) {
			CFReadStreamOpen(readStream);
			CFWriteStreamOpen(writeStream);
			SCPrint(TRUE, stdout, CFSTR("Opened stream to %@, port %d%s\n"), hostName, port, background ? ", background traffic class" : "");
			sleep(1);
		}

		my_CFRelease(&readStream);
		my_CFRelease(&writeStream);
	} else {
		SCPrint(TRUE, stderr, CFSTR("Invalid or missing host name\n"));
	}

	my_CFRelease(&hostName);

	exit(0);
}
/* CF_EXPORT */ void
_CFSocketStreamPairSetAuthenticatesServerCertificate(CFReadStreamRef rStream, CFWriteStreamRef wStream, Boolean authenticates) {
    
    CFBooleanRef value = (!authenticates ? kCFBooleanFalse : kCFBooleanTrue);
    
    if (rStream)
        CFReadStreamSetProperty(rStream, _kCFStreamPropertySocketSecurityAuthenticatesServerCertificate, value);
    else
        CFWriteStreamSetProperty(wStream, _kCFStreamPropertySocketSecurityAuthenticatesServerCertificate, value);
}
Example #7
0
// Return false if we cannot advance the stream. Currently the only possible failure is that the underlying file has been removed or changed since File.slice.
static bool advanceCurrentStream(FormStreamFields* form)
{
    closeCurrentStream(form);

    if (form->remainingElements.isEmpty())
        return true;

    // Create the new stream.
    FormDataElement& nextInput = form->remainingElements.last();

    if (nextInput.m_type == FormDataElement::data) {
        size_t size = nextInput.m_data.size();
        MallocPtr<char> data = nextInput.m_data.releaseBuffer();
        form->currentStream = CFReadStreamCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data.get()), size, kCFAllocatorNull);
        form->currentData = std::move(data);
    } else {
#if ENABLE(BLOB)
        // Check if the file has been changed or not if required.
        if (isValidFileTime(nextInput.m_expectedFileModificationTime)) {
            time_t fileModificationTime;
            if (!getFileModificationTime(nextInput.m_filename, fileModificationTime) || fileModificationTime != static_cast<time_t>(nextInput.m_expectedFileModificationTime))
                return false;
        }
#endif
        const String& path = nextInput.m_shouldGenerateFile ? nextInput.m_generatedFilename : nextInput.m_filename;
        form->currentStream = CFReadStreamCreateWithFile(0, pathAsURL(path).get());
        if (!form->currentStream) {
            // The file must have been removed or become unreadable.
            return false;
        }
#if ENABLE(BLOB)
        if (nextInput.m_fileStart > 0) {
            RetainPtr<CFNumberRef> position = adoptCF(CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart));
            CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position.get());
        }
        form->currentStreamRangeLength = nextInput.m_fileLength;
#endif
    }
    form->remainingElements.removeLast();

    // Set up the callback.
    CFStreamClientContext context = { 0, form, 0, 0, 0 };
    CFReadStreamSetClient(form->currentStream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
        formEventCallback, &context);

    // Schedule with the current set of run loops.
    SchedulePairHashSet::iterator end = form->scheduledRunLoopPairs.end();
    for (SchedulePairHashSet::iterator it = form->scheduledRunLoopPairs.begin(); it != end; ++it)
        CFReadStreamScheduleWithRunLoop(form->currentStream, (*it)->runLoop(), (*it)->mode());

    return true;
}
Example #8
0
static void activesock_create_iphone_os_stream(pj_activesock_t *asock)
{
    if (ios_bg_support && asock->bg_setting && asock->stream_oriented) {
	activesock_destroy_iphone_os_stream(asock);

	CFStreamCreatePairWithSocket(kCFAllocatorDefault, asock->sock,
				     &asock->readStream, NULL);

	if (!asock->readStream ||
	    CFReadStreamSetProperty(asock->readStream,
				    kCFStreamNetworkServiceType,
				    kCFStreamNetworkServiceTypeVoIP)
	    != TRUE ||
	    CFReadStreamOpen(asock->readStream) != TRUE)
	{
	    PJ_LOG(2,("", "Failed to configure TCP transport for VoIP "
		      "usage. Background mode will not be supported."));
	    
	    activesock_destroy_iphone_os_stream(asock);
	}
    }
}
int mailstream_cfstream_set_ssl_enabled(mailstream * s, int ssl_enabled)
{
#if HAVE_CFNETWORK
  struct mailstream_cfstream_data * cfstream_data;
  int r;
  
  cfstream_data = (struct mailstream_cfstream_data *) s->low->data;
  cfstream_data->ssl_enabled = ssl_enabled;
  if (ssl_enabled) {
    CFMutableDictionaryRef settings;
    
    settings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    switch (cfstream_data->ssl_level) {
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_NONE:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNone);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_SSLv2:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelSSLv2);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_SSLv3:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelSSLv3);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_TLSv1:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelTLSv1);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_NEGOCIATED_SSL:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
        break;
    }
    
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_ALLOWS_EXPIRED_CERTIFICATES) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue);
    }
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_ALLOWS_EXPIRED_ROOTS) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLAllowsExpiredRoots, kCFBooleanTrue);
    }
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_ALLOWS_ANY_ROOT) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLAllowsAnyRoot, kCFBooleanTrue);
    }
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_DISABLE_VALIDATES_CERTIFICATE_CHAIN) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
    }
    
    CFReadStreamSetProperty(cfstream_data->readStream, kCFStreamPropertySSLSettings, settings);
    CFWriteStreamSetProperty(cfstream_data->writeStream, kCFStreamPropertySSLSettings, settings);
    CFRelease(settings);
  }
  else {
    CFMutableDictionaryRef settings;
    
    settings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNone);
		CFReadStreamSetProperty(cfstream_data->readStream, kCFStreamPropertySSLSettings, settings);
		CFWriteStreamSetProperty(cfstream_data->writeStream, kCFStreamPropertySSLSettings, settings);
    CFRelease(settings);
    
    //fprintf(stderr, "is not ssl\n");
  }
  
  // We need to investigate more about how to establish a STARTTLS connection.
  // For now, wait until we get the certificate chain.
  while (1) {
    r = wait_runloop(s->low, STATE_WAIT_SSL);
    if (r != WAIT_RUNLOOP_EXIT_NO_ERROR) {
      return -1;
    }
    if (cfstream_data->writeSSLResult < 0)
      return -1;
    if (cfstream_data->readSSLResult < 0)
      return -1;
    
    SecTrustRef secTrust = (SecTrustRef)CFReadStreamCopyProperty(cfstream_data->readStream, kCFStreamPropertySSLPeerTrust);
    if (secTrust == NULL) {
      // No trust, wait more.
      continue;
    }
    
    CFIndex count = SecTrustGetCertificateCount(secTrust);
    CFRelease(secTrust);
    
    if (count == 0) {
      // No certificates, wait more.
      continue;
    }
    break;
  }
  
  return 0;
#else
  return -1;
#endif
}
mailstream_low * mailstream_low_cfstream_open_voip_timeout(const char * hostname, int16_t port,
  int voip_enabled, time_t timeout)
{
#if HAVE_CFNETWORK
  mailstream_low * s;
  struct mailstream_cfstream_data * cfstream_data;
  CFReadStreamRef readStream;
  CFWriteStreamRef writeStream;
  CFStringRef hostString;
  CFOptionFlags readFlags;
  CFOptionFlags writeFlags;
  int r;
  
  hostString = CFStringCreateWithCString(NULL, hostname, kCFStringEncodingUTF8);
  CFStreamCreatePairWithSocketToHost(NULL, hostString, port, &readStream, &writeStream);
  CFRelease(hostString);

#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR  
  if (voip_enabled) {
    CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
    CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
  }
#endif
  
  cfstream_data = cfstream_data_new(readStream, writeStream);
  s = mailstream_low_new(cfstream_data, mailstream_cfstream_driver);
	mailstream_low_set_timeout(s, timeout);  

  //fprintf(stderr, "open %s %i -> %p\n", hostname, port, s);
  
  /* setup streams */
  cfstream_data->streamContext.info = s;
  
  readFlags = kCFStreamEventOpenCompleted |
  kCFStreamEventHasBytesAvailable |
  kCFStreamEventErrorOccurred |
  kCFStreamEventEndEncountered;
  
  writeFlags = kCFStreamEventOpenCompleted |
  kCFStreamEventCanAcceptBytes |
  kCFStreamEventErrorOccurred |
  kCFStreamEventEndEncountered;
  
  CFReadStreamSetClient(cfstream_data->readStream, readFlags, readStreamCallback, &cfstream_data->streamContext);
  CFWriteStreamSetClient(cfstream_data->writeStream, writeFlags, writeStreamCallback, &cfstream_data->streamContext);
  
  CFRelease(readStream);
  CFRelease(writeStream);
  readStream = NULL;
  writeStream = NULL;
  
  /* setup cancel */
  cfstream_data->cancelContext.info = s;
  cfstream_data->cancelContext.perform = cancelPerform;
  cfstream_data->cancelSource = CFRunLoopSourceCreate(NULL, 0, &cfstream_data->cancelContext);
  
  r = low_open(s);
  if (r < 0) {
    mailstream_low_cfstream_close(s);
    return NULL;
  }
  
  return s;
#else
  return NULL;
#endif
}
int tnet_transport_wrap(tnet_transport_t *transport, int index) {
    transport_context_t *context = transport->context;
    transport_socket_t *sock = context->sockets[index];
    
    // If the socket is already wrapped in a CFSocket then return.
    if (sock->cf_socket || sock->cf_read_stream) {
        return 1;
    }
    
    // Put a reference to the transport context 
    const CFSocketContext socket_context = { 0, transport, NULL, NULL, NULL };
    
    if (TNET_SOCKET_TYPE_IS_DGRAM(sock->type)) {
        
        // Create a CFSocket from the native socket and register for Read events
        sock->cf_socket = CFSocketCreateWithNative(kCFAllocatorDefault, 
                                                   sock->fd,
                                                   kCFSocketReadCallBack, 
                                                   &__CFSocketCallBack, 
                                                   &socket_context);
        
        // Don't close the socket if the CFSocket is invalidated
        CFOptionFlags flags = CFSocketGetSocketFlags(sock->cf_socket);
        flags = flags & ~kCFSocketCloseOnInvalidate;
        CFSocketSetSocketFlags(sock->cf_socket, flags);
		
        
        // Create a new RunLoopSource and register it with the main thread RunLoop
        sock->cf_run_loop_source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sock->cf_socket, 0);
        CFRunLoopAddSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopDefaultMode);
        CFRelease(sock->cf_run_loop_source);
        
    } else if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) {
        
        // Create a pair of streams (read/write) from the socket
        CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock->fd, &sock->cf_read_stream, &sock->cf_write_stream);
        
        // Don't close underlying socket
        CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
        CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
        
        if (TNET_SOCKET_TYPE_IS_SECURE(sock->type)) {
            CFMutableDictionaryRef settings = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
            CFDictionaryAddValue(settings, kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue);
            CFDictionaryAddValue(settings, kCFStreamSSLAllowsAnyRoot, kCFBooleanTrue);
            CFDictionaryAddValue(settings, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
            CFDictionaryAddValue(settings, kCFStreamSSLPeerName, kCFNull);
            
            // Set the SSL settings
            CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
            CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertySSLSettings, settings);
            CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
            CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertySSLSettings, settings);
            
            CFRelease(settings);
        }
        
#if __IPHONE_4_0
        // Mark the stream for VoIP usage
        CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
        CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
#endif
        
        // Setup a context for the streams
        CFStreamClientContext streamContext = { 0, transport, NULL, NULL, NULL };
        
        // Set the client callback for the stream
        CFReadStreamSetClient(sock->cf_read_stream, 
                              kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
                              &__CFReadStreamClientCallBack, 
                              &streamContext);
        CFWriteStreamSetClient(sock->cf_write_stream, 
                               kCFStreamEventOpenCompleted | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, 
                               &__CFWriteStreamClientCallBack, 
                               &streamContext);
        
        // Enroll streams in the run-loop
        CFReadStreamScheduleWithRunLoop(sock->cf_read_stream, context->cf_run_loop, kCFRunLoopDefaultMode);
        CFWriteStreamScheduleWithRunLoop(sock->cf_write_stream, context->cf_run_loop, kCFRunLoopDefaultMode);
        
        // Release references
        CFRelease(sock->cf_read_stream);
        CFRelease(sock->cf_write_stream);
        
        CFReadStreamOpen(sock->cf_read_stream);
        CFWriteStreamOpen(sock->cf_write_stream);
    }
    
    return 0;
}
int mailstream_cfstream_set_ssl_enabled(mailstream * s, int ssl_enabled)
{
#if HAVE_CFNETWORK
  struct mailstream_cfstream_data * cfstream_data;
  int r;
  
  cfstream_data = (struct mailstream_cfstream_data *) s->low->data;
  cfstream_data->ssl_enabled = ssl_enabled;
  if (ssl_enabled) {
    CFMutableDictionaryRef settings;
    
    settings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    switch (cfstream_data->ssl_level) {
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_NONE:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNone);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_SSLv2:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelSSLv2);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_SSLv3:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelSSLv3);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_TLSv1:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelTLSv1);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_NEGOCIATED_SSL:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
        break;
    }
    
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_ALLOWS_EXPIRED_CERTIFICATES) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue);
    }
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_ALLOWS_EXPIRED_ROOTS) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLAllowsExpiredRoots, kCFBooleanTrue);
    }
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_ALLOWS_ANY_ROOT) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLAllowsAnyRoot, kCFBooleanTrue);
    }
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_DISABLE_VALIDATES_CERTIFICATE_CHAIN) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
    }
    
    CFReadStreamSetProperty(cfstream_data->readStream, kCFStreamPropertySSLSettings, settings);
    CFWriteStreamSetProperty(cfstream_data->writeStream, kCFStreamPropertySSLSettings, settings);
    CFRelease(settings);
  }
  else {
    CFMutableDictionaryRef settings;
    
    settings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNone);
		CFReadStreamSetProperty(cfstream_data->readStream, kCFStreamPropertySSLSettings, settings);
		CFWriteStreamSetProperty(cfstream_data->writeStream, kCFStreamPropertySSLSettings, settings);
    CFRelease(settings);
    
    //fprintf(stderr, "is not ssl\n");
  }
  
  r = wait_runloop(s->low, STATE_WAIT_SSL);
  if (r != WAIT_RUNLOOP_EXIT_NO_ERROR) {
    return -1;
  }
  
  if (cfstream_data->writeSSLResult < 0)
    return -1;
  if (cfstream_data->readSSLResult < 0)
    return -1;
  
  return 0;
#else
  return -1;
#endif
}
char* DotMacQuery::ReadStream (CFURLRef url, size_t &responseLength)
{
	SInt32 ito;
	CFNumberRef cfnTo = NULL;
	CFDictionaryRef proxyDict = NULL;
	
	// make a connection to the provided URL
	CFHTTPMessageRef httpRequestRef = CFHTTPMessageCreateRequest (kCFAllocatorDefault, CFSTR("GET"), url, kCFHTTPVersion1_1);
	if (httpRequestRef == NULL)
	{
		CSSMError::ThrowCSSMError (CSSMERR_DL_RECORD_NOT_FOUND);
	}
	
	// open the stream
	CFReadStreamRef httpStreamRef = CFReadStreamCreateForHTTPRequest (kCFAllocatorDefault, httpRequestRef);
	if (httpStreamRef == NULL)
	{
		CSSMError::ThrowCSSMError (CSSMERR_DL_RECORD_NOT_FOUND);
	}

	// set a reasonable timeout
	ito = READ_STREAM_TIMEOUT;
	cfnTo = CFNumberCreate(NULL, kCFNumberSInt32Type, &ito);
    if(!CFReadStreamSetProperty(httpStreamRef, _kCFStreamPropertyReadTimeout, cfnTo)) {
		// oh well - keep going 
	}
	
	/* set up possible proxy info */
	proxyDict = SCDynamicStoreCopyProxies(NULL);
	if(proxyDict) {
		CFReadStreamSetProperty(httpStreamRef, kCFStreamPropertyHTTPProxy, proxyDict);
	}

	if (CFReadStreamOpen (httpStreamRef) == false)
	{
		CFRelease(httpRequestRef);
		CFRelease(httpStreamRef);
		CFRelease(cfnTo);
		if(proxyDict) {
			CFRelease(proxyDict);
		}
		CSSMError::ThrowCSSMError (CSSMERR_DL_RECORD_NOT_FOUND);
	}
	
	char* response = (char*) malloc (kResponseIncrement);
	size_t responseBufferLength = kResponseIncrement;
	responseLength = 0;

	// read data from the stream
	CFIndex bytesRead = CFReadStreamRead (httpStreamRef, (UInt8*) response + responseLength, kResponseIncrement);
	while (bytesRead > 0)
	{
		responseLength += bytesRead;
		responseBufferLength = responseLength + kResponseIncrement;
		response = (char*) realloc (response, responseBufferLength);
		
		bytesRead = CFReadStreamRead (httpStreamRef, (UInt8*) response + responseLength, kResponseIncrement);
	}
	
	CFRelease (httpRequestRef);
	CFRelease (httpStreamRef);
	CFRelease(cfnTo);
	if(proxyDict) {
		CFRelease(proxyDict);
	}

	// check for error
	if (bytesRead < 0)
	{
		CSSMError::ThrowCSSMError (CSSMERR_DL_RECORD_NOT_FOUND);
	}
	
	return response;
}
Example #14
0
/* extern */ HttpContextRef
HttpContextCreate(CFAllocatorRef alloc, CFSocketNativeHandle nativeSocket) {

	HttpContextRef context = NULL;

	do {
		// Allocate the buffer for the context.
		context = CFAllocatorAllocate(alloc, sizeof(context[0]), 0);
		
		// Fail if unable to create the context
		if (context == NULL)
			break;
		
		memset(context, 0, sizeof(context[0]));
		
		// Save the allocator for deallocating later.
		if (alloc)
			context->_alloc = CFRetain(alloc);
		
		// Bump the retain count.
		HttpContextRetain(context);
		
		// Create the streams for the incoming socket connection.
		CFStreamCreatePairWithSocket(alloc, nativeSocket, &(context->_inStream), &(context->_outStream));

		// Require both streams in order to create.
		if ((context->_inStream == NULL) || (context->_outStream == NULL))
			break;
				
		// Give up ownership of the native socket.
		CFReadStreamSetProperty(context->_inStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
			
		// Create the receive buffer of no fixed size.
		context->_rcvdBytes = CFDataCreateMutable(alloc, 0);
		
		// Fail if unable to create receive buffer.
		if (context->_rcvdBytes == NULL)
			break;

        // Create the outbound buffer of no fixed size.
		context->_sendBytes = CFDataCreateMutable(alloc, 0);
		
		// Fail if unable to create send buffer.
		if (context->_sendBytes == NULL)
			break;
        
        context->_request = CFAllocatorAllocate(alloc, sizeof(context->_request[0]), 0);

        // Fail if unable to create request.
		if (context->_request == NULL)
			break;
        
        memset(context->_request, 0, sizeof(context->_request[0]));
                
		return context;
		
	} while (0);
	
	// Something failed, so clean up.
	HttpContextRelease(context);
	
	return NULL;
}
Example #15
0
/* MySimpleDownload implements the download command.  It sets up a MyStreamInfo 'object' 
with the read stream being an FTP stream of the file to download and the write stream being 
a file stream of the destination file.  It then returns, and the real work happens 
asynchronously in the runloop.  The function returns true if the stream setup succeeded, 
and false if it failed. */
static Boolean
MySimpleDownload(CFStringRef urlString, CFURLRef destinationFolder, CFStringRef username, CFStringRef password)
{
    CFReadStreamRef        readStream;
    CFWriteStreamRef       writeStream;
    CFStreamClientContext  context = { 0, NULL, NULL, NULL, NULL };
    CFURLRef               downloadPath, downloadURL;
    CFStringRef            fileName;
    Boolean                dirPath, success = true;
    MyStreamInfo           *streamInfo;

    assert(urlString != NULL);
    assert(destinationFolder != NULL);
    assert( (username != NULL) || (password == NULL) );

    /* Returns true if the CFURL path represents a directory. */
    dirPath = CFURLHasDirectoryPath(destinationFolder);
    if (!dirPath) {
        fprintf(stderr, "Download destination must be a directory.\n");
        return false;
    }
    
    /* Create a CFURL from the urlString. */
    downloadURL = CFURLCreateWithString(kCFAllocatorDefault, urlString, NULL);
    assert(downloadURL != NULL);

    /* Copy the end of the file path and use it as the file name. */
    fileName = CFURLCopyLastPathComponent(downloadURL);
    assert(fileName != NULL);

    /* Create the downloadPath by taking the destination folder and appending the file name. */
    downloadPath = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, destinationFolder, fileName, false);
    assert(downloadPath != NULL);
    CFRelease(fileName);

    /* Create a CFWriteStream for the file being downloaded. */
    writeStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, downloadPath);
    assert(writeStream != NULL);
    CFRelease(downloadPath);
    
    /* CFReadStreamCreateWithFTPURL creates an FTP read stream for downloading from an FTP URL. */
    readStream = CFReadStreamCreateWithFTPURL(kCFAllocatorDefault, downloadURL);
    assert(readStream != NULL);
    CFRelease(downloadURL);
    
    /* Initialize our MyStreamInfo structure, which we use to store some information about the stream. */
    MyStreamInfoCreate(&streamInfo, readStream, writeStream);
    context.info = (void *)streamInfo;

    /* CFWriteStreamOpen will return success/failure.  Opening a stream causes it to reserve all the
    system resources it requires.  If the stream can open non-blocking, this will always return TRUE;
    listen to the run loop source to find out when the open completes and whether it was successful. */
    success = CFWriteStreamOpen(writeStream);
    if (success) {
    
        /* CFReadStreamSetClient registers a callback to hear about interesting events that occur on a stream. */
        success = CFReadStreamSetClient(readStream, kNetworkEvents, MyDownloadCallBack, &context);
        if (success) {

            /* Schedule a run loop on which the client can be notified about stream events.  The client
            callback will be triggered via the run loop.  It's the caller's responsibility to ensure that
            the run loop is running. */
            CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
            
            MyCFStreamSetUsernamePassword(readStream, username, password);
            MyCFStreamSetFTPProxy(readStream, &streamInfo->proxyDict);
            
            /* Setting the kCFStreamPropertyFTPFetchResourceInfo property will instruct the FTP stream
            to fetch the file size before downloading the file.  Note that fetching the file size adds
            some time to the length of the download.  Fetching the file size allows you to potentially
            provide a progress dialog during the download operation. You will retrieve the actual file
            size after your CFReadStream Callback gets called with a kCFStreamEventOpenCompleted event. */
            CFReadStreamSetProperty(readStream, kCFStreamPropertyFTPFetchResourceInfo, kCFBooleanTrue);
            
            /* CFReadStreamOpen will return success/failure.  Opening a stream causes it to reserve all the
            system resources it requires.  If the stream can open non-blocking, this will always return TRUE;
            listen to the run loop source to find out when the open completes and whether it was successful. */
            success = CFReadStreamOpen(readStream);
            if (success == false) {
                fprintf(stderr, "CFReadStreamOpen failed\n");
                MyStreamInfoDestroy(streamInfo);
            }
        } else {
            fprintf(stderr, "CFReadStreamSetClient failed\n");
            MyStreamInfoDestroy(streamInfo);
        }
    } else {
        fprintf(stderr, "CFWriteStreamOpen failed\n");
        MyStreamInfoDestroy(streamInfo);
    }

    return success;
}
Example #16
0
/* MyCFStreamSetFTPProxy applies the current proxy settings to the specified stream.  This returns a 
reference to the proxy dictionary that we used because of <rdar://problem/3745574>, discussed below. */
static void
MyCFStreamSetFTPProxy(CFTypeRef stream, CFDictionaryRef * proxyDictPtr)
{
    CFDictionaryRef  proxyDict;
    CFNumberRef      passiveMode;
    CFBooleanRef     isPassive;
    Boolean          success;
    
    assert(stream != NULL);
    assert(proxyDictPtr != NULL);
    
    /* SCDynamicStoreCopyProxies gets the current Internet proxy settings.  Then we call
    CFReadStreamSetProperty, with property name kCFStreamPropertyFTPProxy, to apply the
    settings to the FTP read stream. */
    proxyDict = CFNetworkCopySystemProxySettings();
    assert(proxyDict != NULL);    
    
    /* Get the FTP passive mode setting from the proxy dictionary.  Because of a bug <rdar://problem/3625438>
    setting the kCFStreamPropertyFTPProxy property using the SCDynamicStore proxy dictionary does not
    currently set the FTP passive mode setting on the stream, so we need to do it ourselves. 
    Also, <rdar://problem/4526438> indicates that out in the real world some people are setting 
    kSCPropNetProxiesFTPPassive to a Boolean, as opposed to a number.  That's just incorrect, 
    but I've hardened the code against it. */
//    passiveMode = CFDictionaryGetValue(proxyDict, kSCPropNetProxiesFTPPassive);
    passiveMode = true;
    if ( (passiveMode != NULL) && (CFGetTypeID(passiveMode) == CFNumberGetTypeID()) ) {
        int         value;
        
        success = CFNumberGetValue(passiveMode, kCFNumberIntType, &value);
        assert(success);
        
        if (value) isPassive = kCFBooleanTrue;
        else isPassive = kCFBooleanFalse;
    } else {
        assert(false);
        isPassive = kCFBooleanTrue;         // if prefs malformed, we just assume true
    }
        
    if (CFGetTypeID(stream) == CFReadStreamGetTypeID()) {
        success = CFReadStreamSetProperty((CFReadStreamRef)stream, kCFStreamPropertyFTPProxy, proxyDict);
        assert(success);
        success = CFReadStreamSetProperty((CFReadStreamRef)stream, kCFStreamPropertyFTPUsePassiveMode, isPassive);
        assert(success);
    } else if (CFGetTypeID(stream) == CFWriteStreamGetTypeID()) {
        success = CFWriteStreamSetProperty((CFWriteStreamRef)stream, kCFStreamPropertyFTPProxy, proxyDict);
        assert(success);
        success = CFWriteStreamSetProperty((CFWriteStreamRef)stream, kCFStreamPropertyFTPUsePassiveMode, isPassive);
        assert(success);
    } else {
        fprintf(stderr, "This is not a CFStream\n");
    }

    /* Prior to Mac OS X 10.4, CFFTPStream has a bug <rdar://problem/3745574> that causes it to reference the 
    proxy dictionary that you applied /after/ it has released its last reference to that dictionary.  This causes 
    a crash.  We work around this bug by holding on to our own reference to the proxy dictionary until we're 
    done with the stream.  Thus, our reference prevents the dictionary from being disposed, and thus CFFTPStream 
    can access it safely.  So, rather than release our reference to the proxy dictionary, we pass it back to 
    our caller and require it to release it. */
    
    // CFRelease(proxyDict);  After bug #3745574 is fixed, we'll be able to release the proxyDict here.
    
    *proxyDictPtr = proxyDict;
}