1
-
2
1
/*
3
2
Copyright (c) 2021, 2023, Oracle and/or its affiliates.
4
3
@@ -37,20 +36,23 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
37
36
38
37
#define QUERY_LENGTH 2048
39
38
#define MAX_QUERY_LENGTH 4096
39
+ #define ENCODING_LENGTH 4
40
+ #define CAPABILITY_BIT_LENGTH 1
40
41
41
42
/* *
42
- This helper method parses --fido-register-factor option values, and
43
- inserts the parsed values in list.
43
+ This helper method parses --register-factor/-- fido-register-factor
44
+ option values, and inserts the parsed values in list.
44
45
45
- @param[in] what_factor comma separated string containing what all factors
46
- are to be registered
47
- @param[out] list container holding individual factors
46
+ @param [in] what_factor Comma separated list of values, which specifies
47
+ which factor requires registration.
48
+ Valid values are "2", "3", "2,3" or "3,2"
49
+ @param [out] factors container holding individual factors
48
50
49
51
@return true failed
50
52
@return false success
51
53
*/
52
- static bool parse_register_option (char *what_factor,
53
- std::vector<unsigned int > &list ) {
54
+ bool parse_register_option (const char *what_factor,
55
+ std::vector<unsigned int > &factors ) {
54
56
std::string token;
55
57
std::stringstream str (what_factor);
56
58
while (getline (str, token, ' ,' )) {
@@ -64,7 +66,7 @@ static bool parse_register_option(char *what_factor,
64
66
}
65
67
/* nth_factor can be either 2 or 3 */
66
68
if (nth_factor < 2 || nth_factor > 3 ) return true ;
67
- list .push_back (nth_factor);
69
+ factors .push_back (nth_factor);
68
70
}
69
71
return false ;
70
72
}
@@ -75,15 +77,16 @@ static bool parse_register_option(char *what_factor,
75
77
76
78
Please refer @ref sect_fido_info for more information.
77
79
78
- @param mysql mysql connection handle
79
- @param register_option Comma separated list of values, which specifies
80
- which factor requires registration. Valid values are "2", "3", "2,3" or "3,2"
81
- @param errmsg Buffer tol hold error message in case of error.
80
+ @param [in] mysql_handle mysql connection handle
81
+ @param [in] register_option Comma separated list of values, which
82
+ specifies which factor requires registration. Valid values are "2", "3", "2,3"
83
+ or "3,2"
84
+ @param [out] errmsg Buffer to hold error message in case of error.
82
85
83
86
@return true failed
84
87
@return false success
85
88
*/
86
- bool user_device_registration (MYSQL *mysql , char *register_option,
89
+ bool user_device_registration (MYSQL *mysql_handle , char *register_option,
87
90
char *errmsg) {
88
91
char query[QUERY_LENGTH] = {0 };
89
92
char *query_ptr = nullptr ;
@@ -92,55 +95,68 @@ bool user_device_registration(MYSQL *mysql, char *register_option,
92
95
ulong *lengths;
93
96
uchar *server_challenge = nullptr ;
94
97
uchar *server_challenge_response = nullptr ;
95
-
96
- if (!mysql) {
97
- sprintf (errmsg, " MySQL internal error. " );
98
- return true ;
99
- }
100
-
101
- std::vector<unsigned int > list;
102
- if (parse_register_option (register_option, list)) {
103
- sprintf (errmsg,
104
- " Incorrect value specified for --fido-register-factor option. "
105
- " Correct values can be '2', '3', '2,3' or '3,2'." );
98
+ std::string client_plugin_name{" authentication_fido_client" };
99
+ struct st_mysql_client_plugin *plugin_handler = nullptr ;
100
+ std::stringstream err{};
101
+
102
+ auto print_error = [&errmsg, &mysql_handle, &err](bool print_mysql_error) {
103
+ if (print_mysql_error) {
104
+ sprintf (errmsg, " %s: %d (%s): %s\n " , err.str ().c_str (),
105
+ mysql_errno (mysql_handle), mysql_sqlstate (mysql_handle),
106
+ mysql_error (mysql_handle));
107
+ } else {
108
+ sprintf (errmsg, " %s\n " , err.str ().c_str ());
109
+ }
110
+ };
111
+
112
+ std::vector<unsigned int > factors;
113
+ if (parse_register_option (register_option, factors)) {
114
+ err << " Incorrect value specified for "
115
+ " --register-factor/--fido-register-factor option. "
116
+ " Correct values can be '2', '3', '2,3' or '3,2'." ;
117
+ print_error (false );
106
118
return true ;
107
119
}
108
-
109
- for (auto f : list) {
120
+ for (auto f : factors) {
110
121
sprintf (query, " ALTER USER USER() %d FACTOR INITIATE REGISTRATION" , f);
111
- if (mysql_real_query (mysql , query, (ulong)strlen (query))) {
112
- sprintf (errmsg, " Initiate registration failed with error: %s. " ,
113
- mysql_error (mysql) );
122
+ if (mysql_real_query (mysql_handle , query, (ulong)strlen (query))) {
123
+ err << " Initiate registration for " << f << " factor: ALTER USER failed " ;
124
+ print_error ( true );
114
125
return true ;
115
126
}
116
- if (!(result = mysql_store_result (mysql))) {
117
- sprintf (errmsg, " Initiate registration failed with error: %s. " ,
118
- mysql_error (mysql));
127
+ if (!(result = mysql_store_result (mysql_handle))) {
128
+ err << " Initiate registration for " << f
129
+ << " factor: Cannot process result" ;
130
+ print_error (true );
119
131
return true ;
120
132
}
121
133
if (mysql_num_rows (result) > 1 ) {
122
- sprintf (errmsg, " Initiate registration failed with error: %s. " ,
123
- mysql_error (mysql) );
134
+ err << " Initiate registration for " << f << " factor: Unexpected result " ;
135
+ print_error ( true );
124
136
mysql_free_result (result);
125
137
return true ;
126
138
}
139
+
127
140
row = mysql_fetch_row (result);
128
141
lengths = mysql_fetch_lengths (result);
129
142
/*
130
143
max length of challenge can be 32 (random challenge) +
131
144
255 (relying party ID) + 255 (host name) + 32 (user name) + 4 byte for
132
- length encodings
145
+ length encodings + 1 byte capability
133
146
*/
134
- if (lengths[0 ] > (CHALLENGE_LENGTH + RELYING_PARTY_ID_LENGTH +
135
- HOSTNAME_LENGTH + USERNAME_LENGTH + 4 )) {
136
- sprintf (errmsg, " Received server challenge is corrupt. Please retry.\n " );
147
+ if (lengths[0 ] >
148
+ (CHALLENGE_LENGTH + RELYING_PARTY_ID_LENGTH + HOSTNAME_LENGTH +
149
+ USERNAME_LENGTH + ENCODING_LENGTH + CAPABILITY_BIT_LENGTH)) {
150
+ err << " Initiate registration for " << f
151
+ << " factor: Received server challenge is corrupt. "
152
+ " Please retry." ;
153
+ print_error (false );
137
154
mysql_free_result (result);
138
155
return true ;
139
156
}
140
157
server_challenge = static_cast <uchar *>(my_malloc (
141
158
PSI_NOT_INSTRUMENTED, lengths[0 ] + 1 , MYF (MY_WME | MY_ZEROFILL)));
142
159
memcpy (server_challenge, row[0 ], lengths[0 ]);
143
- mysql_free_result (result);
144
160
145
161
auto cleanup_guard = create_scope_guard ([&] {
146
162
if (server_challenge_response) {
@@ -157,28 +173,47 @@ bool user_device_registration(MYSQL *mysql, char *register_option,
157
173
}
158
174
});
159
175
160
- /* load fido client authentication plugin if required */
161
- struct st_mysql_client_plugin *p =
162
- mysql_client_find_plugin (mysql, " authentication_fido_client" ,
176
+ if (mysql_num_fields (result) >= 2 ) {
177
+ if (!lengths[1 ] || !row[1 ]) {
178
+ err << " Initiate registration for " << f
179
+ << " factor: No client plugin name received. Please retry." ;
180
+ print_error (false );
181
+ mysql_free_result (result);
182
+ return true ;
183
+ }
184
+ client_plugin_name.assign (row[1 ], lengths[1 ]);
185
+ }
186
+ mysql_free_result (result);
187
+
188
+ plugin_handler =
189
+ mysql_client_find_plugin (mysql_handle, client_plugin_name.c_str (),
163
190
MYSQL_CLIENT_AUTHENTICATION_PLUGIN);
164
- if (!p) {
165
- sprintf (
166
- errmsg,
167
- " Loading authentication_fido_client plugin failed with error: %s. " ,
168
- mysql_error (mysql));
191
+ /* check if client plugin is loaded */
192
+ if (!plugin_handler) {
193
+ err << " Initiate registration for " << f
194
+ << " factor: Loading client plugin '" << client_plugin_name
195
+ << " 'failed with error" ;
196
+ print_error (true );
169
197
return true ;
170
198
}
171
199
/* set server challenge in plugin */
172
- if (mysql_plugin_options (p, " registration_challenge" , server_challenge)) {
173
- sprintf (errmsg,
174
- " Failed to set plugin options \" registration_challenge\" .\n " );
200
+ if (mysql_plugin_options (plugin_handler, " registration_challenge" ,
201
+ server_challenge)) {
202
+ err << " Finish registration for " << f
203
+ << " factor: Failed to set plugin options \" registration_challenge\" "
204
+ " for plugin '"
205
+ << client_plugin_name << " '." ;
206
+ print_error (false );
175
207
return true ;
176
208
}
177
209
/* get challenge response from plugin, and release the memory */
178
- if (mysql_plugin_get_option (p , " registration_response" ,
210
+ if (mysql_plugin_get_option (plugin_handler , " registration_response" ,
179
211
&server_challenge_response)) {
180
- sprintf (errmsg,
181
- " Failed to get plugin options \" registration_response\" .\n " );
212
+ err << " Finish registration for " << f
213
+ << " factor: Failed to get plugin options \" registration_response\" . "
214
+ " for pugin '"
215
+ << client_plugin_name << " '." ;
216
+ print_error (false );
182
217
return true ;
183
218
}
184
219
@@ -190,10 +225,11 @@ bool user_device_registration(MYSQL *mysql, char *register_option,
190
225
size_t tot_query_len =
191
226
n + strlen (reinterpret_cast <char *>(server_challenge_response));
192
227
if (tot_query_len >= MAX_QUERY_LENGTH) {
193
- sprintf (
194
- errmsg,
195
- " registration_response length exceeds max supported length of %d.\n " ,
196
- MAX_QUERY_LENGTH);
228
+ err << " Finish registration for " << f
229
+ << " factor: registration_response length exceeds max "
230
+ " supported length of "
231
+ << MAX_QUERY_LENGTH << " \n " ;
232
+ print_error (false );
197
233
return true ;
198
234
}
199
235
if (tot_query_len >= QUERY_LENGTH) {
@@ -206,9 +242,9 @@ bool user_device_registration(MYSQL *mysql, char *register_option,
206
242
" ALTER USER USER() %d FACTOR FINISH REGISTRATION SET "
207
243
" CHALLENGE_RESPONSE AS '%s'" ,
208
244
f, server_challenge_response);
209
- if (mysql_real_query (mysql , query, (ulong)strlen (query))) {
210
- sprintf (errmsg, " Finish registration failed with error: %s. \n " ,
211
- mysql_error (mysql) );
245
+ if (mysql_real_query (mysql_handle , query, (ulong)strlen (query))) {
246
+ err << " Finish registration for " << f << " factor failed " ;
247
+ print_error ( true );
212
248
return true ;
213
249
}
214
250
}
0 commit comments