1 /* Copyright (c) 2011, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 02110-1301 USA */
23
24
25 /*
26 In here, we rewrite queries (to obfuscate passwords etc.) that need it
27 before we log them.
28
29 Stored procedures may also rewrite their statements (to show the actual
30 values of their variables etc.). There is currently no scenario where
31 a statement can be eligible for both rewrites. (see sp_instr.cc)
32 Special consideration will need to be taken if this assertion is changed.
33
34 We also do not intersect with query cache at this time, as QC only
35 caches SELECTs (which we don't rewrite). If and when QC becomes more
36 general, it should probably cache the rewritten query along with the
37 user-submitted one. (see sql_parse.cc)
38 */
39
40
41 #include "auth_common.h" // append_user
42 #include "sql_parse.h" // get_current_user
43 #include "sql_show.h" // append_identifier
44 #include "sp_head.h" // struct set_var_base
45 #include "rpl_slave.h" // SLAVE_SQL, SLAVE_IO
46 #include "mysqld.h" // opt_log_builtin_as_identified_by_password
47 #include "log.h"
48
49 /**
50 Append a key/value pair to a string, with an optional preceding comma.
51 For numeric values.
52
53 @param str The string to append to
54 @param comma Prepend a comma?
55 @param txt C-string, must end in a space
56 @param len strlen(txt)
57 @param val numeric value
58 @param cond only append if this evaluates to true
59
60 @retval false if any subsequent key/value pair would be the first
61 */
62
append_int(String * str,bool comma,const char * txt,size_t len,long val,int cond)63 bool append_int(String *str, bool comma, const char *txt, size_t len,
64 long val, int cond)
65 {
66 if (cond)
67 {
68 String numbuf(42);
69 if (comma)
70 str->append(STRING_WITH_LEN(", "));
71 str->append(txt,len);
72 numbuf.set((longlong)val,&my_charset_bin);
73 str->append(numbuf);
74 return true;
75 }
76 return comma;
77 }
78
79
80 /**
81 Append a key/value pair to a string if the value is non-NULL,
82 with an optional preceding comma.
83
84 @param str The string to append to
85 @param comma Prepend a comma?
86 @param key C-string: the key, must be non-NULL
87 @param val C-string: the value
88
89 @retval false if any subsequent key/value pair would be the first
90 */
91
append_str(String * str,bool comma,const char * key,const char * val)92 bool append_str(String *str, bool comma, const char *key, const char *val)
93 {
94 if (val)
95 {
96 if (comma)
97 str->append(STRING_WITH_LEN(", "));
98 str->append(key);
99 str->append(STRING_WITH_LEN(" '"));
100 str->append(val);
101 str->append(STRING_WITH_LEN("'"));
102 return true;
103 }
104 return comma;
105 }
106
rewrite_ssl_properties(LEX * lex,String * rlb)107 void rewrite_ssl_properties(LEX *lex, String *rlb)
108 {
109 if (lex->ssl_type != SSL_TYPE_NOT_SPECIFIED)
110 {
111 rlb->append(STRING_WITH_LEN(" REQUIRE"));
112 switch (lex->ssl_type)
113 {
114 case SSL_TYPE_SPECIFIED:
115 if (lex->x509_subject)
116 {
117 rlb->append(STRING_WITH_LEN(" SUBJECT '"));
118 rlb->append(lex->x509_subject);
119 rlb->append(STRING_WITH_LEN("'"));
120 }
121 if (lex->x509_issuer)
122 {
123 rlb->append(STRING_WITH_LEN(" ISSUER '"));
124 rlb->append(lex->x509_issuer);
125 rlb->append(STRING_WITH_LEN("'"));
126 }
127 if (lex->ssl_cipher)
128 {
129 rlb->append(STRING_WITH_LEN(" CIPHER '"));
130 rlb->append(lex->ssl_cipher);
131 rlb->append(STRING_WITH_LEN("'"));
132 }
133 break;
134 case SSL_TYPE_X509:
135 rlb->append(STRING_WITH_LEN(" X509"));
136 break;
137 case SSL_TYPE_ANY:
138 rlb->append(STRING_WITH_LEN(" SSL"));
139 break;
140 case SSL_TYPE_NOT_SPECIFIED:
141 /* fall-thru */
142 case SSL_TYPE_NONE:
143 rlb->append(STRING_WITH_LEN(" NONE"));
144 break;
145 }
146 }
147 }
148
rewrite_user_resources(LEX * lex,String * rlb)149 void rewrite_user_resources(LEX *lex, String *rlb)
150 {
151 if (lex->mqh.specified_limits || (lex->grant & GRANT_ACL))
152 {
153 rlb->append(STRING_WITH_LEN(" WITH"));
154 if (lex->grant & GRANT_ACL)
155 rlb->append(STRING_WITH_LEN(" GRANT OPTION"));
156
157 append_int(rlb, false, STRING_WITH_LEN(" MAX_QUERIES_PER_HOUR "),
158 lex->mqh.questions,
159 lex->mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR);
160
161 append_int(rlb, false, STRING_WITH_LEN(" MAX_UPDATES_PER_HOUR "),
162 lex->mqh.updates,
163 lex->mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR);
164
165 append_int(rlb, false, STRING_WITH_LEN(" MAX_CONNECTIONS_PER_HOUR "),
166 lex->mqh.conn_per_hour,
167 lex->mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR);
168
169 append_int(rlb, false, STRING_WITH_LEN(" MAX_USER_CONNECTIONS "),
170 lex->mqh.user_conn,
171 lex->mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS);
172 }
173 }
174
rewrite_account_lock(LEX * lex,String * rlb)175 void rewrite_account_lock(LEX *lex, String *rlb)
176 {
177 if (lex->alter_password.account_locked)
178 {
179 rlb->append(STRING_WITH_LEN(" ACCOUNT LOCK"));
180 }
181 else
182 {
183 rlb->append(STRING_WITH_LEN(" ACCOUNT UNLOCK"));
184 }
185 }
186
187 /**
188 Rewrite a GRANT statement.
189
190 @param thd The THD to rewrite for.
191 @param rlb An empty String object to put the rewritten query in.
192 */
193
mysql_rewrite_grant(THD * thd,String * rlb)194 void mysql_rewrite_grant(THD *thd, String *rlb)
195 {
196 LEX *lex= thd->lex;
197 TABLE_LIST *first_table= lex->select_lex->table_list.first;
198 bool comma= FALSE, comma_inner;
199 bool proxy_grant= lex->type == TYPE_ENUM_PROXY;
200 String cols(1024);
201 int c;
202
203 rlb->append(STRING_WITH_LEN("GRANT "));
204
205 if (proxy_grant)
206 rlb->append(STRING_WITH_LEN("PROXY"));
207 else if (lex->all_privileges)
208 rlb->append(STRING_WITH_LEN("ALL PRIVILEGES"));
209 else
210 {
211 ulong priv;
212
213 for (c= 0, priv= SELECT_ACL; priv <= GLOBAL_ACLS; c++, priv <<= 1)
214 {
215 if (priv == GRANT_ACL)
216 continue;
217
218 comma_inner= FALSE;
219
220 if (lex->columns.elements) // show columns, if any
221 {
222 class LEX_COLUMN *column;
223 List_iterator <LEX_COLUMN> column_iter(lex->columns);
224
225 cols.length(0);
226 cols.append(STRING_WITH_LEN(" ("));
227
228 /*
229 If the statement was GRANT SELECT(f2), INSERT(f3), UPDATE(f1,f3, f2),
230 our list cols will contain the order f2, f3, f1, and thus that's
231 the order we'll recreate the privilege: UPDATE (f2, f3, f1)
232 */
233
234 while ((column= column_iter++))
235 {
236 if (column->rights & priv)
237 {
238 if (comma_inner)
239 cols.append(STRING_WITH_LEN(", "));
240 else
241 comma_inner= TRUE;
242 append_identifier(thd, &cols, column->column.ptr(), column->column.length());
243 }
244 }
245 cols.append(STRING_WITH_LEN(")"));
246 }
247
248 if (comma_inner || (lex->grant & priv)) // show privilege name
249 {
250 if (comma)
251 rlb->append(STRING_WITH_LEN(", "));
252 else
253 comma= TRUE;
254 rlb->append(command_array[c],command_lengths[c]);
255 if (!(lex->grant & priv)) // general outranks specific
256 rlb->append(cols);
257 }
258 }
259 if (!comma) // no privs, default to USAGE
260 rlb->append(STRING_WITH_LEN("USAGE"));
261 }
262
263 rlb->append(STRING_WITH_LEN(" ON "));
264 switch(lex->type)
265 {
266 case TYPE_ENUM_PROCEDURE: rlb->append(STRING_WITH_LEN("PROCEDURE ")); break;
267 case TYPE_ENUM_FUNCTION: rlb->append(STRING_WITH_LEN("FUNCTION ")); break;
268 default: break;
269 }
270
271 LEX_USER *user_name, *tmp_user_name;
272 List_iterator <LEX_USER> user_list(lex->users_list);
273 comma= FALSE;
274
275 if (proxy_grant)
276 {
277 tmp_user_name= user_list++;
278 user_name= get_current_user(thd, tmp_user_name);
279 if (user_name)
280 append_user_new(thd, rlb, user_name, comma);
281 }
282 else if (first_table)
283 {
284 if (first_table->is_view())
285 {
286 append_identifier(thd, rlb, first_table->view_db.str,
287 first_table->view_db.length);
288 rlb->append(STRING_WITH_LEN("."));
289 append_identifier(thd, rlb, first_table->view_name.str,
290 first_table->view_name.length);
291 }
292 else
293 {
294 append_identifier(thd, rlb, first_table->db, strlen(first_table->db));
295 rlb->append(STRING_WITH_LEN("."));
296 append_identifier(thd, rlb, first_table->table_name,
297 strlen(first_table->table_name));
298 }
299 }
300 else
301 {
302 if (lex->current_select()->db)
303 append_identifier(thd, rlb, lex->current_select()->db,
304 strlen(lex->current_select()->db));
305 else
306 rlb->append("*");
307 rlb->append(STRING_WITH_LEN(".*"));
308 }
309
310 rlb->append(STRING_WITH_LEN(" TO "));
311 {
312 while ((tmp_user_name= user_list++))
313 {
314 if ((user_name= get_current_user(thd, tmp_user_name)))
315 {
316 if (opt_log_builtin_as_identified_by_password)
317 append_user(thd, rlb, user_name, comma, true);
318 else
319 append_user_new(thd, rlb, user_name, comma);
320 comma= TRUE;
321 }
322 }
323 }
324 rewrite_ssl_properties(lex, rlb);
325 rewrite_user_resources(lex, rlb);
326 }
327
328
329 /**
330 Rewrite a SET statement.
331
332 @param thd The THD to rewrite for.
333 @param rlb An empty String object to put the rewritten query in.
334 */
335
mysql_rewrite_set(THD * thd,String * rlb)336 static void mysql_rewrite_set(THD *thd, String *rlb)
337 {
338 LEX *lex= thd->lex;
339 List_iterator_fast<set_var_base> it(lex->var_list);
340 set_var_base *var;
341 bool comma= FALSE;
342
343 rlb->append(STRING_WITH_LEN("SET "));
344
345 while ((var= it++))
346 {
347 if (comma)
348 rlb->append(STRING_WITH_LEN(","));
349 else
350 comma= TRUE;
351
352 var->print(thd, rlb);
353 }
354 }
355
356 /**
357 Rewrite CREATE/ALTER USER statement.
358
359 @param thd The THD to rewrite for.
360 @param rlb An empty String object to put the rewritten query in.
361 @param hide_password_hash If password hash has to be shown as <secret> or not.
362 */
363
mysql_rewrite_create_alter_user(THD * thd,String * rlb,std::set<LEX_USER * > * extra_users,bool hide_password_hash)364 void mysql_rewrite_create_alter_user(THD *thd, String *rlb,
365 std::set<LEX_USER *> *extra_users,
366 bool hide_password_hash)
367 {
368 LEX *lex= thd->lex;
369 LEX_USER *user_name, *tmp_user_name;
370 List_iterator <LEX_USER> user_list(lex->users_list);
371 bool comma= FALSE;
372
373 if (thd->lex->sql_command == SQLCOM_CREATE_USER ||
374 thd->lex->sql_command == SQLCOM_SHOW_CREATE_USER)
375 rlb->append(STRING_WITH_LEN("CREATE USER "));
376 else
377 rlb->append(STRING_WITH_LEN("ALTER USER "));
378
379 if (thd->lex->sql_command == SQLCOM_CREATE_USER &&
380 thd->lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
381 rlb->append(STRING_WITH_LEN("IF NOT EXISTS "));
382 if (thd->lex->sql_command == SQLCOM_ALTER_USER &&
383 thd->lex->drop_if_exists)
384 rlb->append(STRING_WITH_LEN("IF EXISTS "));
385
386 while ((tmp_user_name= user_list++))
387 {
388 if ((user_name= get_current_user(thd, tmp_user_name)))
389 {
390 if (opt_log_builtin_as_identified_by_password &&
391 thd->lex->sql_command != SQLCOM_ALTER_USER)
392 append_user(thd, rlb, user_name, comma, true);
393 else
394 append_user_new(thd, rlb, user_name, comma, hide_password_hash);
395 comma= TRUE;
396 }
397 }
398
399 rewrite_ssl_properties(lex, rlb);
400 rewrite_user_resources(lex, rlb);
401
402 /* rewrite password expired */
403 if (lex->alter_password.update_password_expired_fields)
404 {
405 if (lex->alter_password.update_password_expired_column)
406 {
407 rlb->append(STRING_WITH_LEN(" PASSWORD EXPIRE"));
408 }
409 else if (lex->alter_password.expire_after_days)
410 {
411 append_int(rlb, false, STRING_WITH_LEN(" PASSWORD EXPIRE INTERVAL "),
412 lex->alter_password.expire_after_days, TRUE);
413 rlb->append(STRING_WITH_LEN(" DAY"));
414 }
415 else if (lex->alter_password.use_default_password_lifetime)
416 {
417 rlb->append(STRING_WITH_LEN(" PASSWORD EXPIRE DEFAULT"));
418 }
419 else
420 {
421 rlb->append(STRING_WITH_LEN(" PASSWORD EXPIRE NEVER"));
422 }
423 }
424
425 if (lex->alter_password.update_account_locked_column)
426 {
427 rewrite_account_lock(lex, rlb);
428 }
429
430 if ((lex->sql_command == SQLCOM_CREATE_USER ||
431 lex->sql_command == SQLCOM_ALTER_USER) &&
432 extra_users && extra_users->size())
433 {
434 String warn_user;
435 bool comma= false;
436 bool log_warning= false;
437 std::set<LEX_USER *>::iterator it;
438 for (it = extra_users->begin(); it != extra_users->end(); it++)
439 {
440 /*
441 Consider for warning if one of the following is true:
442 1. If SQLCOM_CREATE_USER and IF NOT EXISTS clause is used and
443 IDENTIFIED WITH clause is not used
444 2. If SQLCOM_ALTER_USER and IF EXISTS clause is used and
445 IDENTIFIED WITH clause is not used
446 */
447 LEX_USER* extra_user= *it;
448 if (!extra_user->uses_identified_with_clause &&
449 (lex->sql_command == SQLCOM_CREATE_USER ||
450 extra_user->uses_identified_by_clause))
451 {
452 append_user(thd, &warn_user, extra_user, comma, false);
453 comma= true;
454 log_warning= true;
455 }
456 }
457 if (log_warning)
458 {
459 if (lex->sql_command == SQLCOM_CREATE_USER)
460 {
461 sql_print_warning("Following users were specified in CREATE USER "
462 "IF NOT EXISTS but they already exist. "
463 "Corresponding entry in binary log used default "
464 "authentication plugin '%s' to rewrite "
465 "authentication information(if any) for them: %s\n",
466 default_auth_plugin, warn_user.c_ptr_safe());
467 }
468 else if (lex->sql_command == SQLCOM_ALTER_USER)
469 {
470 sql_print_warning("Following users were specified in ALTER USER "
471 "IF EXISTS but they do not exist. "
472 "Corresponding entry in binary log used default "
473 "authentication plugin '%s' to rewrite "
474 "authentication information(if any) for them: %s\n",
475 default_auth_plugin, warn_user.c_ptr_safe());
476 }
477 }
478 warn_user.mem_free();
479 }
480 }
481
482 /**
483 Rewrite a CHANGE MASTER statement.
484
485 @param thd The THD to rewrite for.
486 @param rlb An empty String object to put the rewritten query in.
487 */
488
mysql_rewrite_change_master(THD * thd,String * rlb)489 static void mysql_rewrite_change_master(THD *thd, String *rlb)
490 {
491 LEX *lex= thd->lex;
492
493 rlb->append(STRING_WITH_LEN("CHANGE MASTER TO"));
494
495 if (lex->mi.host)
496 {
497 rlb->append(STRING_WITH_LEN(" MASTER_HOST = '"));
498 rlb->append(lex->mi.host);
499 rlb->append(STRING_WITH_LEN("'"));
500 }
501 if (lex->mi.user)
502 {
503 rlb->append(STRING_WITH_LEN(" MASTER_USER = '"));
504 rlb->append(lex->mi.user);
505 rlb->append(STRING_WITH_LEN("'"));
506 }
507 if (lex->mi.password)
508 {
509 rlb->append(STRING_WITH_LEN(" MASTER_PASSWORD = <secret>"));
510 }
511 if (lex->mi.port)
512 {
513 rlb->append(STRING_WITH_LEN(" MASTER_PORT = "));
514 rlb->append_ulonglong(lex->mi.port);
515 }
516 if (lex->mi.connect_retry)
517 {
518 rlb->append(STRING_WITH_LEN(" MASTER_CONNECT_RETRY = "));
519 rlb->append_ulonglong(lex->mi.connect_retry);
520 }
521 if (lex->mi.ssl)
522 {
523 rlb->append(STRING_WITH_LEN(" MASTER_SSL = "));
524 rlb->append(lex->mi.ssl == LEX_MASTER_INFO::LEX_MI_ENABLE ? "1" : "0");
525 }
526 if (lex->mi.ssl_ca)
527 {
528 rlb->append(STRING_WITH_LEN(" MASTER_SSL_CA = '"));
529 rlb->append(lex->mi.ssl_ca);
530 rlb->append(STRING_WITH_LEN("'"));
531 }
532 if (lex->mi.ssl_capath)
533 {
534 rlb->append(STRING_WITH_LEN(" MASTER_SSL_CAPATH = '"));
535 rlb->append(lex->mi.ssl_capath);
536 rlb->append(STRING_WITH_LEN("'"));
537 }
538
539 if (lex->mi.tls_version)
540 {
541 rlb->append(STRING_WITH_LEN(" MASTER_TLS_VERSION = '"));
542 rlb->append(lex->mi.tls_version);
543 rlb->append(STRING_WITH_LEN("'"));
544 }
545
546 if (lex->mi.ssl_cert)
547 {
548 rlb->append(STRING_WITH_LEN(" MASTER_SSL_CERT = '"));
549 rlb->append(lex->mi.ssl_cert);
550 rlb->append(STRING_WITH_LEN("'"));
551 }
552 if (lex->mi.ssl_cipher)
553 {
554 rlb->append(STRING_WITH_LEN(" MASTER_SSL_CIPHER = '"));
555 rlb->append(lex->mi.ssl_cipher);
556 rlb->append(STRING_WITH_LEN("'"));
557 }
558 if (lex->mi.ssl_key)
559 {
560 rlb->append(STRING_WITH_LEN(" MASTER_SSL_KEY = '"));
561 rlb->append(lex->mi.ssl_key);
562 rlb->append(STRING_WITH_LEN("'"));
563 }
564 if (lex->mi.log_file_name)
565 {
566 rlb->append(STRING_WITH_LEN(" MASTER_LOG_FILE = '"));
567 rlb->append(lex->mi.log_file_name);
568 rlb->append(STRING_WITH_LEN("'"));
569 }
570 if (lex->mi.pos)
571 {
572 rlb->append(STRING_WITH_LEN(" MASTER_LOG_POS = "));
573 rlb->append_ulonglong(lex->mi.pos);
574 }
575 if (lex->mi.relay_log_name)
576 {
577 rlb->append(STRING_WITH_LEN(" RELAY_LOG_FILE = '"));
578 rlb->append(lex->mi.relay_log_name);
579 rlb->append(STRING_WITH_LEN("'"));
580 }
581 if (lex->mi.relay_log_pos)
582 {
583 rlb->append(STRING_WITH_LEN(" RELAY_LOG_POS = "));
584 rlb->append_ulonglong(lex->mi.relay_log_pos);
585 }
586
587 if (lex->mi.ssl_verify_server_cert)
588 {
589 rlb->append(STRING_WITH_LEN(" MASTER_SSL_VERIFY_SERVER_CERT = "));
590 rlb->append(lex->mi.ssl_verify_server_cert == LEX_MASTER_INFO::LEX_MI_ENABLE ? "1" : "0");
591 }
592 if (lex->mi.repl_ignore_server_ids_opt)
593 {
594 bool first= TRUE;
595 rlb->append(STRING_WITH_LEN(" IGNORE_SERVER_IDS = ( "));
596 for (size_t i= 0; i < lex->mi.repl_ignore_server_ids.size(); i++)
597 {
598 ulong s_id= lex->mi.repl_ignore_server_ids[i];
599 if (first)
600 first= FALSE;
601 else
602 rlb->append(STRING_WITH_LEN(", "));
603 rlb->append_ulonglong(s_id);
604 }
605 rlb->append(STRING_WITH_LEN(" )"));
606 }
607 if (lex->mi.heartbeat_opt != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
608 {
609 rlb->append(STRING_WITH_LEN(" MASTER_HEARTBEAT_PERIOD = "));
610 if (lex->mi.heartbeat_opt == LEX_MASTER_INFO::LEX_MI_DISABLE)
611 rlb->append(STRING_WITH_LEN("0"));
612 else
613 {
614 char buf[64];
615 my_snprintf(buf, 64, "%f", lex->mi.heartbeat_period);
616 rlb->append(buf);
617 }
618 }
619 }
620
621
622 /**
623 Rewrite a START SLAVE statement.
624
625 @param thd The THD to rewrite for.
626 @param rlb An empty String object to put the rewritten query in.
627 */
628
mysql_rewrite_start_slave(THD * thd,String * rlb)629 static void mysql_rewrite_start_slave(THD *thd, String *rlb)
630 {
631 LEX *lex= thd->lex;
632
633 if (!lex->slave_connection.password)
634 return;
635
636 rlb->append(STRING_WITH_LEN("START SLAVE"));
637
638 if (lex->slave_thd_opt & SLAVE_IO)
639 rlb->append(STRING_WITH_LEN(" IO_THREAD"));
640
641 /* we have printed the IO THREAD related options */
642 if (lex->slave_thd_opt & SLAVE_IO &&
643 lex->slave_thd_opt & SLAVE_SQL)
644 rlb->append(STRING_WITH_LEN(","));
645
646 if (lex->slave_thd_opt & SLAVE_SQL)
647 rlb->append(STRING_WITH_LEN(" SQL_THREAD"));
648
649 /* until options */
650 if (lex->mi.log_file_name || lex->mi.relay_log_name)
651 {
652 rlb->append(STRING_WITH_LEN(" UNTIL"));
653 if (lex->mi.log_file_name)
654 {
655 rlb->append(STRING_WITH_LEN(" MASTER_LOG_FILE = '"));
656 rlb->append(lex->mi.log_file_name);
657 rlb->append(STRING_WITH_LEN("', "));
658 rlb->append(STRING_WITH_LEN("MASTER_LOG_POS = "));
659 rlb->append_ulonglong(lex->mi.pos);
660 }
661
662 if (lex->mi.relay_log_name)
663 {
664 rlb->append(STRING_WITH_LEN(" RELAY_LOG_FILE = '"));
665 rlb->append(lex->mi.relay_log_name);
666 rlb->append(STRING_WITH_LEN("', "));
667 rlb->append(STRING_WITH_LEN("RELAY_LOG_POS = "));
668 rlb->append_ulonglong(lex->mi.relay_log_pos);
669 }
670 }
671
672 /* connection options */
673 if (lex->slave_connection.user)
674 {
675 rlb->append(STRING_WITH_LEN(" USER = '"));
676 rlb->append(lex->slave_connection.user);
677 rlb->append(STRING_WITH_LEN("'"));
678 }
679
680 if (lex->slave_connection.password)
681 rlb->append(STRING_WITH_LEN(" PASSWORD = '<secret>'"));
682
683 if (lex->slave_connection.plugin_auth)
684 {
685 rlb->append(STRING_WITH_LEN(" DEFAULT_AUTH = '"));
686 rlb->append(lex->slave_connection.plugin_auth);
687 rlb->append(STRING_WITH_LEN("'"));
688 }
689
690 if (lex->slave_connection.plugin_dir)
691 {
692 rlb->append(STRING_WITH_LEN(" PLUGIN_DIR = '"));
693 rlb->append(lex->slave_connection.plugin_dir);
694 rlb->append(STRING_WITH_LEN("'"));
695 }
696 }
697
698
699 /**
700 Rewrite a SERVER OPTIONS clause (for CREATE SERVER and ALTER SERVER).
701
702 @param thd The THD to rewrite for.
703 @param rlb An empty String object to put the rewritten query in.
704 */
705
mysql_rewrite_server_options(THD * thd,String * rlb)706 static void mysql_rewrite_server_options(THD *thd, String *rlb)
707 {
708 LEX *lex= thd->lex;
709
710 rlb->append(STRING_WITH_LEN(" OPTIONS ( "));
711
712 rlb->append(STRING_WITH_LEN("PASSWORD '<secret>'"));
713 append_str(rlb, true, "USER", lex->server_options.get_username());
714 append_str(rlb, true, "HOST", lex->server_options.get_host());
715 append_str(rlb, true, "DATABASE", lex->server_options.get_db());
716 append_str(rlb, true, "OWNER", lex->server_options.get_owner());
717 append_str(rlb, true, "SOCKET", lex->server_options.get_socket());
718 append_int(rlb, true, STRING_WITH_LEN("PORT "),
719 lex->server_options.get_port(),
720 lex->server_options.get_port() != Server_options::PORT_NOT_SET);
721
722 rlb->append(STRING_WITH_LEN(" )"));
723 }
724
725
726 /**
727 Rewrite a CREATE SERVER statement.
728
729 @param thd The THD to rewrite for.
730 @param rlb An empty String object to put the rewritten query in.
731 */
732
mysql_rewrite_create_server(THD * thd,String * rlb)733 static void mysql_rewrite_create_server(THD *thd, String *rlb)
734 {
735 LEX *lex= thd->lex;
736
737 if (!lex->server_options.get_password())
738 return;
739
740 rlb->append(STRING_WITH_LEN("CREATE SERVER "));
741
742 rlb->append(lex->server_options.m_server_name.str ?
743 lex->server_options.m_server_name.str : "");
744
745 rlb->append(STRING_WITH_LEN(" FOREIGN DATA WRAPPER '"));
746 rlb->append(lex->server_options.get_scheme() ?
747 lex->server_options.get_scheme() : "");
748 rlb->append(STRING_WITH_LEN("'"));
749
750 mysql_rewrite_server_options(thd, rlb);
751 }
752
753
754 /**
755 Rewrite a ALTER SERVER statement.
756
757 @param thd The THD to rewrite for.
758 @param rlb An empty String object to put the rewritten query in.
759 */
760
mysql_rewrite_alter_server(THD * thd,String * rlb)761 static void mysql_rewrite_alter_server(THD *thd, String *rlb)
762 {
763 LEX *lex= thd->lex;
764
765 if (!lex->server_options.get_password())
766 return;
767
768 rlb->append(STRING_WITH_LEN("ALTER SERVER "));
769
770 rlb->append(lex->server_options.m_server_name.str ?
771 lex->server_options.m_server_name.str : "");
772
773 mysql_rewrite_server_options(thd, rlb);
774 }
775
776
777
778
779 /**
780 Rewrite a PREPARE statement.
781
782 @param thd The THD to rewrite for.
783 @param rlb An empty String object to put the rewritten query in.
784 */
785
mysql_rewrite_prepare(THD * thd,String * rlb)786 static void mysql_rewrite_prepare(THD *thd, String *rlb)
787 {
788 LEX *lex= thd->lex;
789
790 if (lex->prepared_stmt_code_is_varref)
791 return;
792
793 rlb->append(STRING_WITH_LEN("PREPARE "));
794 rlb->append(lex->prepared_stmt_name.str,
795 lex->prepared_stmt_name.length);
796 rlb->append(STRING_WITH_LEN(" FROM ..."));
797 }
798
799
800
801
802 /**
803 Rewrite a query (to obfuscate passwords etc.)
804
805 Side-effects:
806
807 - thd->m_rewritten_query will contain a rewritten query,
808 or be cleared if no rewriting took place.
809 LOCK_thd_query will be temporarily acquired to make that change.
810
811 @note Keep in mind that these side-effects will only happen when
812 calling this top-level function, but not when calling
813 individual sub-functions directly!
814
815 @param thd The THD to rewrite for.
816 */
817
mysql_rewrite_query(THD * thd)818 void mysql_rewrite_query(THD *thd)
819 {
820 String rlb;
821
822 // We should not come through here twice for the same query.
823 assert(thd->rewritten_query().length() == 0);
824
825 if (thd->lex->contains_plaintext_password)
826 {
827 switch(thd->lex->sql_command)
828 {
829 case SQLCOM_GRANT: mysql_rewrite_grant(thd, &rlb); break;
830 case SQLCOM_SET_OPTION: mysql_rewrite_set(thd, &rlb); break;
831 case SQLCOM_CREATE_USER:
832 case SQLCOM_ALTER_USER:
833 mysql_rewrite_create_alter_user(thd, &rlb); break;
834 case SQLCOM_CHANGE_MASTER: mysql_rewrite_change_master(thd, &rlb); break;
835 case SQLCOM_SLAVE_START: mysql_rewrite_start_slave(thd, &rlb); break;
836 case SQLCOM_CREATE_SERVER: mysql_rewrite_create_server(thd, &rlb); break;
837 case SQLCOM_ALTER_SERVER: mysql_rewrite_alter_server(thd, &rlb); break;
838
839 /*
840 PREPARE stmt FROM <string> is rewritten so that <string> is
841 not logged. The statement in <string> will in turn be logged
842 by the prepare and the execute functions in sql_prepare.cc.
843 They do call rewrite so they can safely log the statement,
844 but when they call us, it'll be with sql_command set to reflect
845 the statement in question, not SQLCOM_PREPARE or SQLCOM_EXECUTE.
846 Therefore, there is no SQLCOM_EXECUTE case here, and all
847 SQLCOM_PREPARE does is remove <string>; the "other half",
848 i.e. printing what string we prepare from happens when the
849 prepare function calls the logger (and comes by here with
850 sql_command set to the command being prepared).
851 */
852 case SQLCOM_PREPARE: mysql_rewrite_prepare(thd, &rlb); break;
853 default: /* unhandled query types are legal. */ break;
854 }
855 }
856
857 // Note that we succeeded in rewriting (where applicable).
858 if (rlb.length() > 0)
859 thd->swap_rewritten_query(rlb);
860 }
861