diff options
author | Max <post@wickenrode.com> | 2018-02-27 23:56:36 +0100 |
---|---|---|
committer | Max <post@wickenrode.com> | 2018-02-27 23:56:36 +0100 |
commit | d9f773eae0bf2d158012dfe55139ffdc6b1c57ff (patch) | |
tree | bab70669649543698a50fae1d83c30c84daf7a6e /Frameworks/SPMySQLFramework/Source | |
parent | 219d049c61d5588e5519171bd149fb2aa91351f3 (diff) | |
download | sequelpro-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')
6 files changed, 31 insertions, 195 deletions
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQL Private APIs.h b/Frameworks/SPMySQLFramework/Source/SPMySQL Private APIs.h index b2fa9f5d..8fdf4e7e 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQL Private APIs.h +++ b/Frameworks/SPMySQLFramework/Source/SPMySQL Private APIs.h @@ -41,7 +41,6 @@ - (BOOL)_connect; - (MYSQL *)_makeRawMySQLConnectionWithEncoding:(NSString *)encodingName isMasterConnection:(BOOL)isMaster; -- (void)_mysqlConnection:(MYSQL *)connection wantsPassword:(void (^)(const char *passwd))inBlock withPlugin:(const char *)pluginName; - (BOOL)_reconnectAllowingRetries:(BOOL)canRetry; - (BOOL)_reconnectAfterBackgroundConnectionLoss; - (BOOL)_waitForNetworkConnectionWithTimeout:(double)timeoutSeconds; diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h index 0faa3e02..343d0d36 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h @@ -61,7 +61,6 @@ pthread_t reconnectingThread; uint64_t initialConnectTime; unsigned long mysqlConnectionThreadId; - BOOL allowCleartextPlugin; // Connection proxy NSObject <SPMySQLConnectionProxy> *proxy; @@ -176,23 +175,6 @@ - (void)addClientFlags:(SPMySQLClientFlags)opts; - (void)removeClientFlags:(SPMySQLClientFlags)opts; -/** - * This tells the mysql client whether the cleartext auth plugin is permitted. - * - * If enabled, and requested by the server, the password will simply be transmitted - * in plaintext, instead of hashing it on the client first, thus this plugin is - * rather risky. It is mostly used when the server has to forward the password to another - * auth backend (which it can't do with the one-way hash). - * - * If it is not enabled, but requested by the server the connection will fail with - * error "plugin not enabled (2059)" - * - * WARNING: There are 2 ways to enable this plugin: Via this property or by setting - * the envvar LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN to 1. Sadly ANY ONE of those two is - * sufficient to enable the plugin. - */ -@property (readwrite, assign, nonatomic) BOOL allowCleartextPlugin; - #pragma mark - #pragma mark Connection and disconnection 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]; -} diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnectionDelegate.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnectionDelegate.h index f32be742..1e238c12 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnectionDelegate.h +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnectionDelegate.h @@ -62,18 +62,15 @@ - (void)showErrorWithTitle:(NSString *)title message:(NSString *)message; /** - * Requests the password for the connection. + * Requests the keychain password for the connection. * When a connection is being made to a server, it is best not to * set the password on the class; instead, it should be kept within - * the secure store (Keychain), and the other connection details (user, host) + * the secure store, and the other connection details (user, host) * can be used to look it up and supplied on demand. * - * NOTE: This will be called on the thread SPMySQL is running on (which *MAY* be a background thread)! - * * @param connection The connection instance to supply the password for - * @param pluginName The auth plugin libmysqlclients wants to use the password with */ -- (NSString *)passwordForConnection:(id)connection authPlugin:(NSString *)pluginName; +- (NSString *)keychainPasswordForConnection:(id)connection; /** * Notifies the delegate that no underlying connection is available, diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLUtilities.h b/Frameworks/SPMySQLFramework/Source/SPMySQLUtilities.h index 852ca685..50f9d504 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLUtilities.h +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLUtilities.h @@ -1,5 +1,5 @@ // -// SPMySQLUtilities.h +// Locking.h // SPMySQLFramework // // Created by Rowan Beentje (rowan.beent.je) on February 6, 2012 @@ -30,16 +30,6 @@ #include <mach/mach_time.h> -/** - * This function provides a memset() variant that cannot be optimized - * away by a compiler's dead store optimization. - * - * It will write cLength '\0' bytes to the buffer pointed to by cBuffer. - * - * @return See the documentation for memset_s in libc - */ -errno_t SPMySQLSafeEraseMemory(void *cBuffer, size_t cLength); - #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLUtilities.m b/Frameworks/SPMySQLFramework/Source/SPMySQLUtilities.m deleted file mode 100644 index 3d147143..00000000 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLUtilities.m +++ /dev/null @@ -1,66 +0,0 @@ -// -// SPMySQLUtilities.c -// SPMySQLFramework -// -// Created by Max Lohrmann on 25.02.2018 -// Copyright (c) 2018 Max Lohrmann. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// More info at <https://github.com/sequelpro/sequelpro> - -#include <errno.h> -#define __STDC_WANT_LIB_EXT1__ 1 -#include <string.h> -#include <dlfcn.h> -#include <dispatch/dispatch.h> - -#include "SPMySQLUtilities.h" - -static errno_t LegacyMemsetS(void *ptr, rsize_t ignored, int value, rsize_t count); - -errno_t SPMySQLSafeEraseMemory(void *cBuffer, size_t cLength) { - // memset_s is 10.9+ only - if we added a link time dependency, SP wouldn't launch on older targets - static errno_t (*memsetPtr)(void *, rsize_t, int, rsize_t); - static dispatch_once_t findMemsetToken; - dispatch_once(&findMemsetToken, ^{ - memsetPtr = dlsym(RTLD_DEFAULT, "memset_s"); - if(!memsetPtr) memsetPtr = &LegacyMemsetS; - }); - - return (*memsetPtr)(cBuffer, cLength, '\0', cLength); -} - -/** - * This function tries to emulate the important (to us) parts - * of memset_s on pre 10.9 systems. - * - * The implementation is taken from the original memset_s proposal: - * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1381.pdf - */ -errno_t LegacyMemsetS(void *s, rsize_t smax __attribute__((unused)), int c, rsize_t n) -{ - volatile unsigned char * addr = (volatile unsigned char *)s; - while(n--) *addr++ = (unsigned char)c; - - return 0; -} |