aboutsummaryrefslogtreecommitdiffstats
path: root/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
diff options
context:
space:
mode:
authorMax <post@wickenrode.com>2018-02-27 23:56:36 +0100
committerMax <post@wickenrode.com>2018-02-27 23:56:36 +0100
commitd9f773eae0bf2d158012dfe55139ffdc6b1c57ff (patch)
treebab70669649543698a50fae1d83c30c84daf7a6e /Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
parent219d049c61d5588e5519171bd149fb2aa91351f3 (diff)
downloadsequelpro-d9f773eae0bf2d158012dfe55139ffdc6b1c57ff.tar.gz
sequelpro-d9f773eae0bf2d158012dfe55139ffdc6b1c57ff.tar.bz2
sequelpro-d9f773eae0bf2d158012dfe55139ffdc6b1c57ff.zip
Manually roll back all changes for #2979
Those will be moved to a different branch for the time being since other stuff needs to be changed first
Diffstat (limited to 'Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m')
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m120
1 files changed, 27 insertions, 93 deletions
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
index d4146f58..d50375e2 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
@@ -33,9 +33,6 @@
#include <mach/mach_time.h>
#include <pthread.h>
#include <SystemConfiguration/SCNetworkReachability.h>
-#include <errno.h>
-#include <string.h>
-#import "SPMySQLUtilities.h"
// Thread flag constant
static pthread_key_t mySQLThreadInitFlagKey;
@@ -52,7 +49,6 @@ const SPMySQLClientFlags SPMySQLConnectionOptions =
// List of permissible ciphers to use for SSL connections
const char *SPMySQLSSLPermissibleCiphers = "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";
-static void PasswordCallback(MYSQL *mysql, const char *plugin, void (^with_password)(const char *passwd));
@implementation SPMySQLConnection
@@ -78,7 +74,6 @@ static void PasswordCallback(MYSQL *mysql, const char *plugin, void (^with_passw
@synthesize delegateQueryLogging;
@synthesize lastQueryWasCancelled;
@synthesize clientFlags = clientFlags;
-@synthesize allowCleartextPlugin = allowCleartextPlugin;
#pragma mark -
#pragma mark Getters and Setters
@@ -475,6 +470,14 @@ static void PasswordCallback(MYSQL *mysql, const char *plugin, void (^with_passw
const char *__crashreporter_info__ = NULL;
asm(".desc ___crashreporter_info__, 0x10");
+static uint64_t _elapsedMicroSecondsSinceAbsoluteTime(uint64_t comparisonTime)
+{
+ uint64_t elapsedTime_t = mach_absolute_time() - comparisonTime;
+ Nanoseconds elapsedTime = AbsoluteToNanoseconds(*(AbsoluteTime *)&(elapsedTime_t));
+
+ return (UnsignedWideToUInt64(elapsedTime) / 1000ULL);
+}
+
@implementation SPMySQLConnection (PrivateAPI)
/**
@@ -486,8 +489,8 @@ asm(".desc ___crashreporter_info__, 0x10");
// If a connection is already active in some form, throw an exception
if (state != SPMySQLDisconnected && state != SPMySQLConnectionLostInBackground) {
@synchronized (self) {
- double diff = _elapsedSecondsSinceAbsoluteTime(initialConnectTime);
- asprintf(&__crashreporter_info__, "Attempted to connect a connection that is not disconnected (SPMySQLConnectionState=%d).\nIf state==2: Previous connection made %lfs ago from: %s", state, diff, [_debugLastConnectedEvent cStringUsingEncoding:NSUTF8StringEncoding]);
+ uint64_t diff = _elapsedMicroSecondsSinceAbsoluteTime(initialConnectTime);
+ asprintf(&__crashreporter_info__, "Attempted to connect a connection that is not disconnected (SPMySQLConnectionState=%d).\nIf state==2: Previous connection made %lluµs ago from: %s", state, diff, [_debugLastConnectedEvent cStringUsingEncoding:NSUTF8StringEncoding]);
__builtin_trap();
}
[NSException raise:NSInternalInconsistencyException format:@"Attempted to connect a connection that is not disconnected (SPMySQLConnectionState=%d).", state];
@@ -606,17 +609,30 @@ asm(".desc ___crashreporter_info__, 0x10");
NSStringEncoding connectEncodingNS = [SPMySQLConnection stringEncodingForMySQLCharset:[encodingName UTF8String]];
mysql_options(theConnection, MYSQL_SET_CHARSET_NAME, [encodingName UTF8String]);
- my_bool cleartextAllowed = [self allowCleartextPlugin] ? TRUE : FALSE;
- mysql_options(theConnection, MYSQL_ENABLE_CLEARTEXT_PLUGIN, &cleartextAllowed);
-
// Set up the connection variables in the format MySQL needs, from the class-wide variables
const char *theHost = NULL;
const char *theUsername = "";
+ const char *thePassword = NULL;
const char *theSocket = NULL;
if (host) theHost = [host UTF8String]; //mysql calls getaddrinfo on the hostname. Apples code uses -UTF8String in that situation.
if (username) theUsername = _cStringForStringWithEncoding(username, connectEncodingNS, NULL); //during connect this is in MYSQL_SET_CHARSET_NAME encoding
+ // If a password was supplied, use it; otherwise ask the delegate if appropriate.
+ //
+ // Note that password has no charset in mysql: If a user password is set to 'ü' on a latin1 connection
+ // and you later try to connect on an UTF-8 terminal (or vice versa) it will fail. The MySQL (5.5) manual wrongly states that
+ // MYSQL_SET_CHARSET_NAME has influence over that, but it does not and could not, since the password is hashed by the client
+ // before transmitting it to the server and the (5.5) client has no charset support, effectively treating password as
+ // a NUL-terminated byte array.
+ // There is one exception, though: The "mysql_clear_password" auth plugin sends the password in plaintext and the server side
+ // MAY choose to do a charset conversion as appropriate before handing it to whatever backend is used.
+ // Since we don't know which auth plugin server and client will agree upon, we'll do as the manual says...
+ if (password) {
+ thePassword = _cStringForStringWithEncoding(password, connectEncodingNS, NULL);
+ } else if ([delegate respondsToSelector:@selector(keychainPasswordForConnection:)]) {
+ thePassword = _cStringForStringWithEncoding([delegate keychainPasswordForConnection:self], connectEncodingNS, NULL);
+ }
// If set to use a socket and a socket was supplied, use it; otherwise, search for a socket to use
if (useSocket) {
@@ -674,11 +690,7 @@ asm(".desc ___crashreporter_info__, 0x10");
}
}
- // we will provide the password via this callback. the mysql_real_connect parameter is a dummy and won't work
- theConnection->passwd_callback = &PasswordCallback;
- theConnection->sp_context = self;
-
- MYSQL *connectionStatus = mysql_real_connect(theConnection, theHost, theUsername, "", NULL, (unsigned int)port, theSocket, [self clientFlags]);
+ MYSQL *connectionStatus = mysql_real_connect(theConnection, theHost, theUsername, thePassword, NULL, (unsigned int)port, theSocket, [self clientFlags]);
// If the connection failed, return NULL
if (theConnection != connectionStatus) {
@@ -721,78 +733,6 @@ asm(".desc ___crashreporter_info__, 0x10");
return theConnection;
}
-- (void)_mysqlConnection:(MYSQL *)connection wantsPassword:(void (^)(const char *passwd))inBlock withPlugin:(const char *)pluginName
-{
- NSString *passwd = nil;
-
- // If a password was supplied, use it; otherwise ask the delegate if appropriate.
- if (password) {
- passwd = password;
- }
- else if ([delegate respondsToSelector:@selector(passwordForConnection:authPlugin:)]) {
- // It's not clear what charset the plugin name is in:
- // In the 5.5 libmysqlclient:
- // * For the compiled-in plugins this will simply be the byte sequence as it was in the source code
- // * The server requests a plugin in the first packet it sends and gives its own charset (mysql->server_language)
- // * However client for the most part ignores the plugin name
- // * and it completely ignores the server_language
- // * When the client sends its reply (in send_client_reply_packet()) it will send the plugin name together with
- // the desired charset+collation (but doesn't apply any charset conversion logic to the values)
- // In the JDBC client it works like this:
- // * The plugin name in the first packet from the server will always be interpreted as "ASCII"
- // * The plugin name in the client response will be encoded in the client's initial charset
- // TODO We will just use latin1 for now, as it is the safest fallback
- NSString *plugin = [NSString stringWithCString:pluginName encoding:NSISOLatin1StringEncoding];
- passwd = [delegate passwordForConnection:self authPlugin:plugin];
- }
-
- // shortcut for nil/empty passwords
- if(![passwd length]) {
- // nil means abort, "" is a valid password:
- // only invoke the block when the password is @"", otherwise we'll skip it which will make mysql abort the connection
- if(passwd) inBlock("");
- return;
- }
-
- // Note (libmysqlclient 5.5):
- // mysql_character_set_name() is only initialized after mysql has read the first packet from the server.
- // Before that it will always be latin1, regardless of what was set with mysql_options().
- // That does not mean, that client and server have agreed on a charset already, though!
- NSStringEncoding connectEncodingNS = [SPMySQLConnection stringEncodingForMySQLCharset:mysql_character_set_name(connection)];
-
- // Note that password has no charset in mysql: If a user password is set to 'ü' on a latin1 connection
- // and you later try to connect on an UTF-8 terminal (or vice versa) it will fail. The MySQL (5.5) manual wrongly states that
- // MYSQL_SET_CHARSET_NAME has influence over that, but it does not and could not, since the password is hashed by the client
- // before transmitting it to the server and the (5.5) client has very limited charset support,
- // effectively treating password as a NUL-terminated byte array.
- // There is one exception, though: The "mysql_clear_password" auth plugin sends the password in plaintext and the server side
- // MAY choose to do a charset conversion as appropriate before handing it to whatever backend is used.
- // Since we don't know which auth plugin server and client will agree upon, we'll do as the manual says...
- NSInteger cLength = [passwd lengthOfBytesUsingEncoding:connectEncodingNS];
-
- if(!cLength || cLength == NSIntegerMax) {
- NSLog(@"%s: -lengthOfBytesUsingEncoding: returned 0 or NSIntegerMax for encoding %lu (mysql: %s)", __PRETTY_FUNCTION__, connectEncodingNS, connection->options.charset_name);
- return;
- }
-
- char *cBuffer = malloc(++cLength);
-
- if(!cBuffer) {
- NSLog(@"%s: malloc(%ld) failed: %s", __PRETTY_FUNCTION__, (long)cLength, strerror(errno));
- return;
- }
-
- if([passwd getCString:cBuffer maxLength:cLength encoding:connectEncodingNS]) {
- inBlock(cBuffer);
- }
- else {
- NSLog(@"%s: -getCString:maxLength:encoding: failed for password!", __PRETTY_FUNCTION__);
- }
-
- SPMySQLSafeEraseMemory(cBuffer, cLength); //clear password from memory
- free(cBuffer);
-}
-
/**
* Perform a reconnection task, either once-only or looping as requested. If looping is
* permitted and this method fails, it will ask how to proceed and loop depending on
@@ -1222,9 +1162,3 @@ asm(".desc ___crashreporter_info__, 0x10");
}
@end
-
-void PasswordCallback(MYSQL *mysql, const char *plugin, void (^with_password)(const char *))
-{
- assert(mysql && mysql->sp_context);
- [(SPMySQLConnection *)mysql->sp_context _mysqlConnection:mysql wantsPassword:with_password withPlugin:plugin];
-}