From 92e7b9a652b0d1806d732079574aea7270b8a2c0 Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Mon, 13 Sep 2010 22:26:54 +0000 Subject: - Implement support for MySQL over SSL for both TCP/IP and Socket connection modes. - Upgrade the MySQL binaries to version 5.1.50 (was 5.1.46) - Enable SSL support in the MySQL libraries (this leads to a large increase in library size, unfortunately) - Enable more optimisations in the MySQL libraries (especially --enable-assembler for faster in-library string processing and --with-mysqld-ldflags=-all-static) This completes support for Issue #27. --- Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h | 7 ++ Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m | 92 +++++++++++++++++++-- Frameworks/MCPKit/MySQL/include/mysql.h | 2 + Frameworks/MCPKit/MySQL/include/mysql_com.h | 10 +++ Frameworks/MCPKit/MySQL/include/mysql_version.h | 4 +- Frameworks/MCPKit/MySQL/lib/libmysqlclient.a | Bin 1900748 -> 4561036 bytes Frameworks/MCPKit/MySQL/lib/libmysqlclient_r.a | Bin 1935244 -> 4595172 bytes 7 files changed, 108 insertions(+), 7 deletions(-) (limited to 'Frameworks') diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h index 7e60ccb2..864eb413 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.h @@ -139,6 +139,11 @@ NSInteger maxAllowedPacketSize; unsigned long connectionThreadId; + BOOL useSSL; + NSString *sslKeyFilePath; + NSString *sslCertificatePath; + NSString *sslCACertificatePath; + NSString *encoding, *previousEncoding; NSStringEncoding *stringEncoding; BOOL encodingUsesLatin1Transport, previousEncodingUsesLatin1Transport; @@ -207,6 +212,7 @@ // Connection details - (BOOL)setPort:(NSInteger)thePort; - (BOOL)setPassword:(NSString *)thePassword; +- (BOOL) setSSL:(BOOL)shouldUseSSL usingKeyFilePath:(NSString *)keyFilePath certificatePath:(NSString *)certificatePath certificateAuthorityCertificatePath:(NSString *)caCertificatePath; // Proxy - (BOOL)setConnectionProxy:(id )proxy; @@ -217,6 +223,7 @@ - (void)disconnect; - (BOOL)reconnect; - (BOOL)isConnected; +- (BOOL)isConnectedViaSSL; - (BOOL)userTriggeredDisconnect; - (BOOL)checkConnection; - (BOOL)pingConnection; diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m index d8905d8d..362c3dc6 100644 --- a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m +++ b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m @@ -48,6 +48,7 @@ BOOL keepAliveActive; const NSUInteger kMCPConnectionDefaultOption = CLIENT_COMPRESS | CLIENT_REMEMBER_OPTIONS | CLIENT_MULTI_RESULTS; const char *kMCPConnectionDefaultSocket = MYSQL_UNIX_ADDR; +const char *kMCPSSLCipherList = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RSA-AES128-SHA:AES128-SHA:AES256-RMD:AES128-RMD:DES-CBC3-RMD:DHE-RSA-AES256-RMD:DHE-RSA-AES128-RMD:DHE-RSA-DES-CBC3-RMD:RC4-SHA:RC4-MD5:DES-CBC3-SHA:DES-CBC-SHA:EDH-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC-SHA"; const NSUInteger kMCPConnection_Not_Inited = 1000; const NSUInteger kLengthOfTruncationForLog = 100; @@ -111,6 +112,10 @@ static BOOL sTruncateLongFieldInLogs = YES; connectionLogin = nil; connectionSocket = nil; connectionPassword = nil; + useSSL = NO; + sslKeyFilePath = nil; + sslCertificatePath = nil; + sslCACertificatePath = nil; keepAliveThread = NULL; lastKeepAliveTime = 0; pingThread = NULL; @@ -298,6 +303,29 @@ static BOOL sTruncateLongFieldInLogs = YES; return YES; } +/** + * Set the connection to establish secure connections using SSL; must be + * called before connect:. + * This will always attempt to activate SSL if set, but depending on server + * setup connection may sometimes proceed without SSL enabled even if requested; + * it is suggested that after connection, -[MCPConnection isConnectedViaSSL] + * is checked to determine whether SSL is actually active. + */ +- (void) setSSL:(BOOL)shouldUseSSL usingKeyFilePath:(NSString *)keyFilePath certificatePath:(NSString *)certificatePath certificateAuthorityCertificatePath:(NSString *)caCertificatePath +{ + useSSL = shouldUseSSL; + + // Reset the old SSL details + if (sslKeyFilePath) [sslKeyFilePath release], sslKeyFilePath = nil; + if (sslCertificatePath) [sslCertificatePath release], sslCertificatePath = nil; + if (sslCACertificatePath) [sslCACertificatePath release], sslCACertificatePath = nil; + + // Set new details if provided + if (keyFilePath) sslKeyFilePath = [[NSString alloc] initWithString:[keyFilePath stringByExpandingTildeInPath]]; + if (certificatePath) sslCertificatePath = [[NSString alloc] initWithString:[certificatePath stringByExpandingTildeInPath]]; + if (caCertificatePath) sslCACertificatePath = [[NSString alloc] initWithString:[caCertificatePath stringByExpandingTildeInPath]]; +} + #pragma mark - #pragma mark Connection proxy @@ -385,7 +413,18 @@ static BOOL sTruncateLongFieldInLogs = YES; } else { theSocket = [self cStringFromString:connectionSocket]; } - + + // Apply SSL if appropriate + if (useSSL) { + NSLog(@"sdfsdfsfds SET"); + mysql_ssl_set(mConnection, + sslKeyFilePath ? [sslKeyFilePath UTF8String] : NULL, + sslCertificatePath ? [sslCertificatePath UTF8String] : NULL, + sslCACertificatePath ? [sslCACertificatePath UTF8String] : NULL, + NULL, + kMCPSSLCipherList); + } + // Select the password from the provided method if (!connectionPassword) { if (delegate && [delegate respondsToSelector:@selector(keychainPasswordForConnection:)]) { @@ -406,7 +445,7 @@ static BOOL sTruncateLongFieldInLogs = YES; return mConnected = NO; } - + mConnected = YES; userTriggeredDisconnect = NO; connectionStartTime = mach_absolute_time(); @@ -626,6 +665,15 @@ static BOOL sTruncateLongFieldInLogs = YES; return mConnected; } +/** + * Returns YES if the MCPConnection is connected to a server via SSL, NO otherwise. + */ +- (BOOL)isConnectedViaSSL +{ + if (![self isConnected]) return NO; + return (mysql_get_ssl_cipher(mConnection))?YES:NO; +} + /** * Returns YES if the user chose to disconnect at the last "connection failure" * prompt, NO otherwise. @@ -1255,6 +1303,16 @@ void performThreadedKeepAlive(void *ptr) if (theSocket == NULL) { theSocket = kMCPConnectionDefaultSocket; } + + // Apply SSL if appropriate + if (useSSL) { + mysql_ssl_set(mConnection, + sslKeyFilePath ? [sslKeyFilePath UTF8String] : NULL, + sslCertificatePath ? [sslCertificatePath UTF8String] : NULL, + sslCACertificatePath ? [sslCACertificatePath UTF8String] : NULL, + NULL, + kMCPSSLCipherList); + } theRet = mysql_real_connect(mConnection, theHost, theLogin, thePass, NULL, port, theSocket, mConnectionFlags); if (theRet != mConnection) { @@ -1833,6 +1891,14 @@ void performThreadedKeepAlive(void *ptr) } else { thePass = [self cStringFromString:connectionPassword]; } + if (useSSL) { + mysql_ssl_set(mConnection, + sslKeyFilePath ? [sslKeyFilePath UTF8String] : NULL, + sslCertificatePath ? [sslCertificatePath UTF8String] : NULL, + sslCACertificatePath ? [sslCACertificatePath UTF8String] : NULL, + NULL, + kMCPSSLCipherList); + } // Connect connectionSetupStatus = mysql_real_connect(killerConnection, theHost, theLogin, thePass, NULL, connectionPort, theSocket, mConnectionFlags); @@ -1850,13 +1916,18 @@ void performThreadedKeepAlive(void *ptr) NSData *encodedKillQueryData = NSStringDataUsingLossyEncoding(killQueryString, killerConnectionEncoding, 1); const char *killQueryCString = [encodedKillQueryData bytes]; unsigned long killQueryCStringLength = [encodedKillQueryData length]; - if (mysql_real_query(killerConnection, killQueryCString, killQueryCStringLength) == 0) { - mysql_close(killerConnection); + int killerReturnError = mysql_real_query(killerConnection, killQueryCString, killQueryCStringLength); + mysql_close(killerConnection); + if (killerReturnError == 0) { queryCancelUsedReconnect = NO; return; } - mysql_close(killerConnection); + NSLog(@"Task cancellation: kill query failed (Returned status %d)", killerReturnError); + } else { + NSLog(@"Task cancellation connection failed (error %u)", mysql_errno(killerConnection)); } + } else { + NSLog(@"Task cancelletion MySQL init failed."); } // Reset the connection @@ -2333,6 +2404,14 @@ void performThreadedKeepAlive(void *ptr) } else { theSocket = [self cStringFromString:connectionSocket]; } + if (useSSL) { + mysql_ssl_set(mConnection, + sslKeyFilePath ? [sslKeyFilePath UTF8String] : NULL, + sslCertificatePath ? [sslCertificatePath UTF8String] : NULL, + sslCACertificatePath ? [sslCACertificatePath UTF8String] : NULL, + NULL, + kMCPSSLCipherList); + } if (!connectionPassword) { if (delegate && [delegate respondsToSelector:@selector(keychainPasswordForConnection:)]) { thePass = [self cStringFromString:[delegate keychainPasswordForConnection:self]]; @@ -3135,6 +3214,9 @@ void performThreadedKeepAlive(void *ptr) if (connectionLogin) [connectionLogin release]; if (connectionSocket) [connectionSocket release]; if (connectionPassword) [connectionPassword release]; + if (sslKeyFilePath) [sslKeyFilePath release]; + if (sslCertificatePath) [sslCertificatePath release]; + if (sslCACertificatePath) [sslCACertificatePath release]; if (serverVersionString) [serverVersionString release], serverVersionString = nil; if (structure) [structure release], structure = nil; if (allKeysofDbStructure) [allKeysofDbStructure release], allKeysofDbStructure = nil; diff --git a/Frameworks/MCPKit/MySQL/include/mysql.h b/Frameworks/MCPKit/MySQL/include/mysql.h index d114afb6..dcf3e167 100644 --- a/Frameworks/MCPKit/MySQL/include/mysql.h +++ b/Frameworks/MCPKit/MySQL/include/mysql.h @@ -44,7 +44,9 @@ extern "C" { #endif #ifndef _global_h /* If not standard header */ +#ifndef MYSQL_ABI_CHECK #include +#endif #ifdef __LCC__ #include /* For windows */ #endif diff --git a/Frameworks/MCPKit/MySQL/include/mysql_com.h b/Frameworks/MCPKit/MySQL/include/mysql_com.h index db5a5eb8..7d3dd3d4 100644 --- a/Frameworks/MCPKit/MySQL/include/mysql_com.h +++ b/Frameworks/MCPKit/MySQL/include/mysql_com.h @@ -277,6 +277,16 @@ typedef struct st_net { /** Client library sqlstate buffer. Set along with the error message. */ char sqlstate[SQLSTATE_LENGTH+1]; void *extension; +#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) + /* + Controls whether a big packet should be skipped. + + Initially set to FALSE by default. Unauthenticated sessions must have + this set to FALSE so that the server can't be tricked to read packets + indefinitely. + */ + my_bool skip_big_packet; +#endif } NET; diff --git a/Frameworks/MCPKit/MySQL/include/mysql_version.h b/Frameworks/MCPKit/MySQL/include/mysql_version.h index 7017707c..736c2021 100644 --- a/Frameworks/MCPKit/MySQL/include/mysql_version.h +++ b/Frameworks/MCPKit/MySQL/include/mysql_version.h @@ -9,11 +9,11 @@ #include #else #define PROTOCOL_VERSION 10 -#define MYSQL_SERVER_VERSION "5.1.46" +#define MYSQL_SERVER_VERSION "5.1.50" #define MYSQL_BASE_VERSION "mysqld-5.1" #define MYSQL_SERVER_SUFFIX_DEF "" #define FRM_VER 6 -#define MYSQL_VERSION_ID 50146 +#define MYSQL_VERSION_ID 50150 #define MYSQL_PORT 3306 #define MYSQL_PORT_DEFAULT 0 #define MYSQL_UNIX_ADDR "/tmp/mysql.sock" diff --git a/Frameworks/MCPKit/MySQL/lib/libmysqlclient.a b/Frameworks/MCPKit/MySQL/lib/libmysqlclient.a index 512d3b52..ab6939c1 100644 Binary files a/Frameworks/MCPKit/MySQL/lib/libmysqlclient.a and b/Frameworks/MCPKit/MySQL/lib/libmysqlclient.a differ diff --git a/Frameworks/MCPKit/MySQL/lib/libmysqlclient_r.a b/Frameworks/MCPKit/MySQL/lib/libmysqlclient_r.a index a9ae37fe..b04f6c35 100644 Binary files a/Frameworks/MCPKit/MySQL/lib/libmysqlclient_r.a and b/Frameworks/MCPKit/MySQL/lib/libmysqlclient_r.a differ -- cgit v1.2.3