-
Notifications
You must be signed in to change notification settings - Fork 842
/
003-callback-password-auth.diff
111 lines (99 loc) · 4.89 KB
/
003-callback-password-auth.diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
This patch changes the way libmysqlclient receives the connection password.
Usually it will get the password by trying in order:
1) The passwd that is passed as a parameter to mysql_real_connect()
2) The password that was set on MYSQL->options.password
3) The contents of the environment variable MYSQL_PWD (compile time setting)
4) An empty string
If a connection could be made (not yet authenticathed) the password will be stored
in MYSQL->passwd for the whole lifetime of the struct.
We don't want that for two reasons:
1) That way the password stays in plaintext memory for possibly a long time (and
may even get swapped to disk)
2) MySQL uses plugins for auth (negotiated with the server) and some of them may
transmit the password in plaintext over an unsecure connection.
Since we have no control over that we would have to decide beforehand if that
COULD happen and flat out always deny or allow Keychain access (since e.g.
the AVAILABILITY of the cleartext plugin can be controlled by an envvar).
So with this patch we change the flow of information:
Now mysql doesn't receive the password up front, but instead it has to ask the user (ie. SPMySQL)
to get the password precisely then when it needs it and mysql will also tell us
which auth plugin it negotiated with the server, so we can decide on a per situation
basis whether to request manual input or fetch it from Keychain.
To apply:
cd mysql-source-root
patch -p1 < this-file
(patch created with `diff -Naur`)
diff -Naur mysql-5.5.59-p002/include/mysql.h mysql-5.5.59-p003/include/mysql.h
--- mysql-5.5.59-p002/include/mysql.h 2017-11-27 13:03:17.000000000 +0100
+++ mysql-5.5.59-p003/include/mysql.h 2018-02-16 00:23:19.000000000 +0100
@@ -288,6 +288,18 @@
/* needed for embedded server - no net buffer to store the 'info' */
char *info_buffer;
void *extension;
+
+ /* SPMySQL patch:
+ * Set this to a callback function that will be invoked when mysql wants to do authentication.
+ * @param mysql The MYSQL struct
+ * @param plugin The name of the auth plugin that will be used (usually either
+ * "mysql_native_password", "mysql_old_password" or "mysql_clear_password")
+ * @param with_password A block function you must invoke, during which mysql can use the password you provide via the passwd parameter.
+ * After the block you should immediately clear the password from memory again.
+ */
+ void (*passwd_callback)(struct st_mysql *mysql, const char *plugin, void (^with_password)(const char *passwd));
+ /* SPMySQL patch: This is used with passwd_callback to bridge back to OOP land */
+ void *sp_context;
} MYSQL;
diff -Naur mysql-5.5.59-p002/sql-common/client.c mysql-5.5.59-p003/sql-common/client.c
--- mysql-5.5.59-p002/sql-common/client.c 2017-11-27 13:03:17.000000000 +0100
+++ mysql-5.5.59-p003/sql-common/client.c 2018-02-16 00:27:37.000000000 +0100
@@ -2952,7 +2952,7 @@
auth_plugin_t *auth_plugin;
MCPVIO_EXT mpvio;
ulong pkt_length;
- int res;
+ __block int res;
DBUG_ENTER ("run_plugin_auth");
/* determine the default/initial plugin to use */
@@ -2996,7 +2996,29 @@
mpvio.db= db;
mpvio.plugin= auth_plugin;
- res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
+ /*
+ * SPMySQL Patch to inverse the password flow
+ */
+ if(mysql->passwd_callback)
+ {
+ res = CR_ERROR; //fallback, if block is never invoked
+ mysql->passwd_callback(mysql, auth_plugin_name, ^(const char *passwd) {
+ char *saved_passwd = mysql->passwd;
+ mysql->passwd = (char *)(passwd ? passwd : ""); // see mysql_change_user
+ res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
+ mysql->passwd = saved_passwd;
+ });
+ }
+ else
+ {
+ set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
+ unknown_sqlstate,
+ ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
+ auth_plugin_name,
+ "passwd_callback not set!");
+ DBUG_RETURN (1);
+ }
+
DBUG_PRINT ("info", ("authenticate_user returned %s",
res == CR_OK ? "CR_OK" :
res == CR_ERROR ? "CR_ERROR" :
@@ -3069,7 +3091,13 @@
DBUG_RETURN(1);
mpvio.plugin= auth_plugin;
- res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
+ res = CR_ERROR; //fallback, if block is never invoked
+ mysql->passwd_callback(mysql, auth_plugin_name, ^(const char *passwd) {
+ char *saved_passwd = mysql->passwd;
+ mysql->passwd = (char *)(passwd ? passwd : ""); // see mysql_change_user
+ res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
+ mysql->passwd = saved_passwd;
+ });
DBUG_PRINT ("info", ("second authenticate_user returned %s",
res == CR_OK ? "CR_OK" :