1 /* Copyright (c) 2010, 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 02110-1301 USA */
22
23 #include <stdio.h>
24 #include <m_ctype.h>
25 #include <mysql/plugin.h>
26 #include <mysql/plugin_audit.h>
27 #include <my_sys.h>
28 #include <mysqld_error.h>
29 #include "my_compiler.h"
30
31 /** Event strings. */
32 LEX_CSTRING event_names[][6] = {
33 /** MYSQL_AUDIT_GENERAL_CLASS */
34 { { C_STRING_WITH_LEN("MYSQL_AUDIT_GENERAL_LOG") },
35 { C_STRING_WITH_LEN("MYSQL_AUDIT_GENERAL_ERROR") },
36 { C_STRING_WITH_LEN("MYSQL_AUDIT_GENERAL_RESULT") },
37 { C_STRING_WITH_LEN("MYSQL_AUDIT_GENERAL_STATUS") },
38 },
39 /** MYSQL_AUDIT_CONNECTION_CLASS */
40 { { C_STRING_WITH_LEN("MYSQL_AUDIT_CONNECTION_CONNECT") },
41 { C_STRING_WITH_LEN("MYSQL_AUDIT_CONNECTION_DISCONNECT") },
42 { C_STRING_WITH_LEN("MYSQL_AUDIT_CONNECTION_CHANGE_USER") },
43 { C_STRING_WITH_LEN("MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE") },
44 },
45 /** MYSQL_AUDIT_PARSE_CLASS */
46 { { C_STRING_WITH_LEN("MYSQL_AUDIT_PARSE_PREPARSE") },
47 { C_STRING_WITH_LEN("MYSQL_AUDIT_PARSE_POSTPARSE") },
48 },
49 /** MYSQL_AUDIT_AUTHORIZATION_CLASS */
50 { { C_STRING_WITH_LEN("MYSQL_AUDIT_AUTHORIZATION_USER") },
51 { C_STRING_WITH_LEN("MYSQL_AUDIT_AUTHORIZATION_DB") },
52 { C_STRING_WITH_LEN("MYSQL_AUDIT_AUTHORIZATION_TABLE") },
53 { C_STRING_WITH_LEN("MYSQL_AUDIT_AUTHORIZATION_COLUMN") },
54 { C_STRING_WITH_LEN("MYSQL_AUDIT_AUTHORIZATION_PROCEDURE") },
55 { C_STRING_WITH_LEN("MYSQL_AUDIT_AUTHORIZATION_PROXY") },
56 },
57 /** MYSQL_AUDIT_TABLE_ROW_ACCES_CLASS */
58 {
59 { C_STRING_WITH_LEN("MYSQL_AUDIT_TABLE_ACCESS_READ") },
60 { C_STRING_WITH_LEN("MYSQL_AUDIT_TABLE_ACCESS_INSERT") },
61 { C_STRING_WITH_LEN("MYSQL_AUDIT_TABLE_ACCESS_UPDATE") },
62 { C_STRING_WITH_LEN("MYSQL_AUDIT_TABLE_ACCESS_DELETE") },
63 },
64 /** MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS */
65 {
66 { C_STRING_WITH_LEN("MYSQL_AUDIT_GLOBAL_VARIABLE_GET") },
67 { C_STRING_WITH_LEN("MYSQL_AUDIT_GLOBAL_VARIABLE_SET") },
68 },
69 /** MYSQL_AUDIT_SERVER_STARTUP_CLASS */
70 {
71 { C_STRING_WITH_LEN("MYSQL_AUDIT_SERVER_STARTUP_STARTUP") },
72 },
73 /** MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS */
74 {
75 { C_STRING_WITH_LEN("MYSQL_AUDIT_SERVER_SHUTDOWN_SHUTDOWN") },
76 },
77 /** MYSQL_AUDIT_COMMAND_CLASS */
78 {
79 { C_STRING_WITH_LEN("MYSQL_AUDIT_COMMAND_START") },
80 { C_STRING_WITH_LEN("MYSQL_AUDIT_COMMAND_END") },
81 },
82 /** MYSQL_AUDIT_QUERY_CLASS */
83 {
84 { C_STRING_WITH_LEN("MYSQL_AUDIT_QUERY_START") },
85 { C_STRING_WITH_LEN("MYSQL_AUDIT_QUERY_NESTED_START") },
86 { C_STRING_WITH_LEN("MYSQL_AUDIT_QUERY_STATUS_END") },
87 { C_STRING_WITH_LEN("MYSQL_AUDIT_QUERY_NESTED_STATUS_END") },
88 },
89 /** MYSQL_AUDIT_STORED_PROGRAM_CLASS */
90 {
91 { C_STRING_WITH_LEN("MYSQL_AUDIT_STORED_PROGRAM_EXECUTE") },
92 }
93 };
94
95 static volatile int number_of_calls;
96
97 /*
98 Plugin has been installed.
99 */
100 static my_bool g_plugin_installed= FALSE;
101
102 /*
103 Record buffer mutex.
104 */
105 static mysql_mutex_t g_record_buffer_mutex;
106
107 /*
108 Event recording buffer.
109 */
110 static char *g_record_buffer;
111
112 #define AUDIT_NULL_VAR(x) static volatile int number_of_calls_ ## x;
113 #include "audit_null_variables.h"
114 #undef AUDIT_NULL_VAR
115
116 /*
117 Plugin status variables for SHOW STATUS
118 */
119
120 static struct st_mysql_show_var simple_status[] =
121 {
122 { "Audit_null_called",
123 (char *)&number_of_calls,
124 SHOW_INT, SHOW_SCOPE_GLOBAL },
125
126 #define AUDIT_NULL_VAR(x) { "Audit_null_" #x, (char*)&number_of_calls_ ## x, \
127 SHOW_INT, SHOW_SCOPE_GLOBAL },
128 #include "audit_null_variables.h"
129 #undef AUDIT_NULL_VAR
130
131 { 0, 0, 0, SHOW_SCOPE_GLOBAL }
132 };
133
134 /*
135 Define plugin variables.
136 */
137
138 static MYSQL_THDVAR_STR(abort_message,
139 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
140 "Custom message for event abort.", NULL, NULL, NULL);
141
142 static MYSQL_THDVAR_INT(abort_value,
143 PLUGIN_VAR_RQCMDARG,
144 "Event abort value.",
145 NULL, NULL, 1, -1, 150, 0);
146
147 static MYSQL_THDVAR_STR(event_order_check,
148 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
149 "Event order check string", NULL, NULL, NULL);
150
151 static MYSQL_THDVAR_UINT(event_order_check_consume_ignore_count,
152 PLUGIN_VAR_RQCMDARG,
153 "Do not consume event order string specified "
154 "number of times.",
155 NULL, NULL, 0, 0, UINT_MAX, 1);
156
157 static MYSQL_THDVAR_INT(event_order_started,
158 PLUGIN_VAR_RQCMDARG,
159 "Plugin is in the event order check.",
160 NULL, NULL, 0, 0, 1, 0);
161
162 static MYSQL_THDVAR_INT(event_order_check_exact,
163 PLUGIN_VAR_RQCMDARG,
164 "Plugin checks exact event order.",
165 NULL, NULL, 1, 0, 1, 0);
166
167 static MYSQL_THDVAR_STR(event_record_def,
168 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
169 "Event recording definition", NULL, NULL, NULL);
170
171 static MYSQL_THDVAR_STR(event_record,
172 PLUGIN_VAR_READONLY |
173 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
174 "Event recording", NULL, NULL, NULL);
175 /*
176 Initialize the plugin at server start or plugin installation.
177
178 SYNOPSIS
179 audit_null_plugin_init()
180
181 DESCRIPTION
182 Does nothing.
183
184 RETURN VALUE
185 0 success
186 1 failure (cannot happen)
187 */
188
audit_null_plugin_init(void * arg MY_ATTRIBUTE ((unused)))189 static int audit_null_plugin_init(void *arg MY_ATTRIBUTE((unused)))
190 {
191 struct st_mysql_show_var *var;
192
193 for (var= simple_status; var->value != 0; var++)
194 {
195 *((int*)var->value) = 0;
196 }
197
198 mysql_mutex_init(PSI_NOT_INSTRUMENTED,
199 &g_record_buffer_mutex,
200 MY_MUTEX_INIT_FAST);
201
202 g_record_buffer= NULL;
203 g_plugin_installed= TRUE;
204
205 return(0);
206 }
207
208
209 /*
210 Terminate the plugin at server shutdown or plugin deinstallation.
211
212 SYNOPSIS
213 audit_null_plugin_deinit()
214 Does nothing.
215
216 RETURN VALUE
217 0 success
218 1 failure (cannot happen)
219
220 */
221
audit_null_plugin_deinit(void * arg MY_ATTRIBUTE ((unused)))222 static int audit_null_plugin_deinit(void *arg MY_ATTRIBUTE((unused)))
223 {
224 if (g_plugin_installed == TRUE)
225 {
226 my_free((void *)(g_record_buffer));
227
228 g_record_buffer= NULL;
229
230 mysql_mutex_destroy(&g_record_buffer_mutex);
231
232 g_plugin_installed= FALSE;
233 }
234
235 return(0);
236 }
237
238 /**
239 @brief Converts event_class and event_subclass into a string.
240
241 @param event_class[in] Event class value.
242 @param event_subclass[in] Event subclass value.
243
244 @retval Event name.
245 */
event_to_str(unsigned int event_class,unsigned long event_subclass)246 static LEX_CSTRING event_to_str(unsigned int event_class,
247 unsigned long event_subclass)
248 {
249 int count;
250 for (count= 0; event_subclass; count++, event_subclass >>= 1);
251
252 return event_names[event_class][count - 1];
253 }
254
255 /**
256 @brief Read token delimited by a semicolon from a string.
257
258 @param str[in,out] Pointer to a string containing text.
259 Pointer is moved to a new token after the function ends.
260
261 @retval Token retrieved from a string.
262 */
get_token(const char ** str)263 static LEX_CSTRING get_token(const char **str)
264 {
265 LEX_CSTRING ret = { NULL, 0 };
266
267 if (*str != NULL)
268 {
269 ret.str= *str;
270
271 if (*ret.str != '\0')
272 {
273 /* Find a param delimiter. */
274 while (**str && **str != ';') (*str)++;
275
276 ret.length= *str - ret.str;
277
278 /* Skip a delimiter. */
279 if (**str == ';') (*str)++;
280 }
281 }
282
283 return ret;
284 }
285
add_event(const char * var,LEX_CSTRING event,const char * data,size_t data_length)286 static char *add_event(const char *var, LEX_CSTRING event,
287 const char *data, size_t data_length)
288 {
289 LEX_CSTRING str;
290 size_t size;
291 char *buffer;
292
293 lex_cstring_set(&str, var);
294
295 size= str.length + event.length + data_length + 4;
296 buffer= (char *)my_malloc(PSI_NOT_INSTRUMENTED, size, MYF(MY_FAE));
297
298 my_snprintf(buffer, size, "%s%s%s;%s;", var, str.length == 0 ? "" : "\n",
299 event.str, data);
300
301 buffer[size - (str.length == 0 ? 2 : 1)] = '\0';
302
303 return buffer;
304 }
305
process_event_record(MYSQL_THD thd,LEX_CSTRING event_name,const char * data,size_t data_length)306 static void process_event_record(MYSQL_THD thd, LEX_CSTRING event_name,
307 const char *data, size_t data_length)
308 {
309 const char *record_str = (const char *)THDVAR(thd, event_record_def);
310 LEX_CSTRING record_begin = get_token(&record_str);
311 LEX_CSTRING record_end = get_token(&record_str);
312
313 if (record_str == NULL)
314 {
315 return;
316 }
317
318 if (record_end.length == 0)
319 {
320 /* We are already in the consuming phase. Add a new event name into
321 a record variable */
322
323 const char *buffer= THDVAR(thd, event_record);
324 char *new_buffer= NULL;
325
326 /* Add event. */
327 mysql_mutex_lock(&g_record_buffer_mutex);
328
329 /* Only one THD is capable of adding events into the buffer. */
330 if (buffer && (buffer == g_record_buffer))
331 {
332 new_buffer= add_event(buffer, event_name, data, data_length);
333 g_record_buffer= new_buffer;
334 my_free((void *)(buffer));
335 }
336
337 mysql_mutex_unlock(&g_record_buffer_mutex);
338
339 THDVAR(thd, event_record)= new_buffer;
340
341 if (!my_charset_latin1.coll->strnncoll(&my_charset_latin1,
342 (const uchar *)record_begin.str,
343 record_begin.length,
344 (const uchar *)event_name.str,
345 event_name.length, FALSE))
346 {
347 /* Do not expect any more events. */
348 THDVAR(thd, event_record_def)= 0;
349 }
350 }
351 else
352 {
353 const char *buffer;
354
355 /* We have not started recording of events yet. */
356 if (my_charset_latin1.coll->strnncoll(&my_charset_latin1,
357 (const uchar *)record_begin.str,
358 record_begin.length,
359 (const uchar *)event_name.str,
360 event_name.length, FALSE))
361 {
362 /* Event not matching. */
363 return;
364 }
365
366 buffer= THDVAR(thd, event_record);
367
368 mysql_mutex_lock(&g_record_buffer_mutex);
369
370 if (buffer == g_record_buffer)
371 {
372 my_free((void *)(buffer));
373
374 g_record_buffer= add_event("", event_name, data, data_length);
375
376 THDVAR(thd, event_record)= g_record_buffer;
377 }
378
379 mysql_mutex_unlock(&g_record_buffer_mutex);
380
381 /* Add event. */
382
383 record_str = (const char *)THDVAR(thd, event_record_def);
384
385 /* Remove starting event. */
386 memmove((char *)record_str, (void *)record_end.str, record_end.length + 1);
387 }
388 }
389
process_command(MYSQL_THD thd,LEX_CSTRING event_command,my_bool consume_event)390 static int process_command(MYSQL_THD thd, LEX_CSTRING event_command,
391 my_bool consume_event)
392 {
393 LEX_CSTRING abort_ret_command= { C_STRING_WITH_LEN("ABORT_RET") };
394
395 if (!my_charset_latin1.coll->strnncoll(&my_charset_latin1,
396 (const uchar *)event_command.str,
397 event_command.length,
398 (const uchar *)abort_ret_command.str,
399 abort_ret_command.length, 0))
400 {
401 int ret_code = (int)THDVAR(thd, abort_value);
402 const char *err_message = (const char *)THDVAR(thd, abort_message);
403 LEX_CSTRING status = { C_STRING_WITH_LEN("EVENT-ORDER-ABORT") };
404 LEX_CSTRING order_cstr;
405
406 lex_cstring_set(&order_cstr,
407 (const char *)THDVAR(thd, event_order_check));
408
409 /* Do not replace order string yet. */
410 if (consume_event)
411 {
412 memmove((char *) order_cstr.str,
413 (void *) status.str, status.length + 1);
414
415 THDVAR(thd, abort_value)= 1;
416 THDVAR(thd, abort_message)= 0;
417 }
418
419 if (err_message)
420 {
421 my_message(ER_AUDIT_API_ABORT, err_message, MYF(0));
422 THDVAR(thd, event_order_check)= (char *)order_cstr.str;
423 }
424
425 return ret_code;
426 }
427
428 return 0;
429 }
430
431 /**
432 @brief Plugin function handler.
433
434 @param thd[in] Connection context.
435 @param event_class[in] Event class value.
436 @param event[in] Event data.
437
438 @retval Value indicating, whether the server should abort continuation
439 of the current oparation.
440 */
audit_null_notify(MYSQL_THD thd,mysql_event_class_t event_class,const void * event)441 static int audit_null_notify(MYSQL_THD thd,
442 mysql_event_class_t event_class,
443 const void *event)
444 {
445 char buffer[2000]= { 0, };
446 int buffer_data= 0;
447 unsigned long event_subclass= (unsigned long)*(int *)event;
448 const char *order_str= (const char *)THDVAR(thd, event_order_check);
449 int event_order_started= (int)THDVAR(thd, event_order_started);
450 int exact_check= (int)THDVAR(thd, event_order_check_exact);
451 LEX_CSTRING event_name= event_to_str(event_class, event_subclass);
452 LEX_CSTRING event_token= get_token(&order_str);
453 LEX_CSTRING event_data= get_token(&order_str);
454 LEX_CSTRING event_command= get_token(&order_str);
455 my_bool consume_event= TRUE;
456
457 /* prone to races, oh well */
458 number_of_calls++;
459
460 if (event_class == MYSQL_AUDIT_GENERAL_CLASS)
461 {
462 const struct mysql_event_general *event_general=
463 (const struct mysql_event_general *)event;
464
465 switch (event_general->event_subclass)
466 {
467 case MYSQL_AUDIT_GENERAL_LOG:
468 number_of_calls_general_log++;
469 break;
470 case MYSQL_AUDIT_GENERAL_ERROR:
471 number_of_calls_general_error++;
472 break;
473 case MYSQL_AUDIT_GENERAL_RESULT:
474 number_of_calls_general_result++;
475 break;
476 case MYSQL_AUDIT_GENERAL_STATUS:
477 number_of_calls_general_status++;
478 break;
479 default:
480 break;
481 }
482 }
483 else if (event_class == MYSQL_AUDIT_CONNECTION_CLASS)
484 {
485 const struct mysql_event_connection *event_connection=
486 (const struct mysql_event_connection *) event;
487
488 switch (event_connection->event_subclass)
489 {
490 case MYSQL_AUDIT_CONNECTION_CONNECT:
491 number_of_calls_connection_connect++;
492 break;
493 case MYSQL_AUDIT_CONNECTION_DISCONNECT:
494 number_of_calls_connection_disconnect++;
495 break;
496 case MYSQL_AUDIT_CONNECTION_CHANGE_USER:
497 number_of_calls_connection_change_user++;
498 break;
499 case MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE:
500 number_of_calls_connection_pre_authenticate++;
501 break;
502 default:
503 break;
504 }
505 }
506 else if (event_class == MYSQL_AUDIT_PARSE_CLASS)
507 {
508 const struct mysql_event_parse *event_parse =
509 (const struct mysql_event_parse *)event;
510
511 switch (event_parse->event_subclass)
512 {
513 case MYSQL_AUDIT_PARSE_PREPARSE:
514 number_of_calls_parse_preparse++;
515 break;
516 case MYSQL_AUDIT_PARSE_POSTPARSE:
517 number_of_calls_parse_postparse++;
518 break;
519 default:
520 break;
521 }
522 }
523 /**
524 Currently events not active.
525
526 else if (event_class == MYSQL_AUDIT_AUTHORIZATION_CLASS)
527 {
528 const struct mysql_event_authorization *event_grant =
529 (const struct mysql_event_authorization *)event;
530
531 buffer_data= sprintf(buffer, "db=\"%s\" table=\"%s\" object=\"%s\" "
532 "requested=\"0x%08x\" granted=\"0x%08x\"",
533 event_grant->database.str ? event_grant->database.str : "<NULL>",
534 event_grant->table.str ? event_grant->table.str : "<NULL>",
535 event_grant->object.str ? event_grant->object.str : "<NULL>",
536 event_grant->requested_privilege,
537 event_grant->granted_privilege);
538
539 switch (event_grant->event_subclass)
540 {
541 case MYSQL_AUDIT_AUTHORIZATION_USER:
542 number_of_calls_authorization_user++;
543 break;
544 case MYSQL_AUDIT_AUTHORIZATION_DB:
545 number_of_calls_authorization_db++;
546 break;
547 case MYSQL_AUDIT_AUTHORIZATION_TABLE:
548 number_of_calls_authorization_table++;
549 break;
550 case MYSQL_AUDIT_AUTHORIZATION_COLUMN:
551 number_of_calls_authorization_column++;
552 break;
553 case MYSQL_AUDIT_AUTHORIZATION_PROCEDURE:
554 number_of_calls_authorization_procedure++;
555 break;
556 case MYSQL_AUDIT_AUTHORIZATION_PROXY:
557 number_of_calls_authorization_proxy++;
558 break;
559 default:
560 break;
561 }
562 }
563 */
564 else if (event_class == MYSQL_AUDIT_SERVER_STARTUP_CLASS)
565 {
566 /* const struct mysql_event_server_startup *event_startup=
567 (const struct mysql_event_server_startup *) event; */
568 number_of_calls_server_startup++;
569 }
570 else if (event_class == MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS)
571 {
572 /* const struct mysql_event_server_shutdown *event_startup=
573 (const struct mysql_event_server_shutdown *) event; */
574 number_of_calls_server_shutdown++;
575 }
576 else if (event_class == MYSQL_AUDIT_COMMAND_CLASS)
577 {
578 const struct mysql_event_command *event_command=
579 (const struct mysql_event_command *)event;
580
581 buffer_data= sprintf(buffer, "command_id=\"%d\"", event_command->command_id);
582
583 switch (event_command->event_subclass)
584 {
585 case MYSQL_AUDIT_COMMAND_START:
586 number_of_calls_command_start++;
587 break;
588 case MYSQL_AUDIT_COMMAND_END:
589 number_of_calls_command_end++;
590 break;
591 default:
592 break;
593 }
594 }
595 else if (event_class == MYSQL_AUDIT_QUERY_CLASS)
596 {
597 const struct mysql_event_query *event_query=
598 (const struct mysql_event_query *)event;
599
600 buffer_data= sprintf(buffer, "sql_command_id=\"%d\"",
601 (int) event_query->sql_command_id);
602
603 switch (event_query->event_subclass)
604 {
605 case MYSQL_AUDIT_QUERY_START:
606 number_of_calls_query_start++;
607 break;
608 case MYSQL_AUDIT_QUERY_NESTED_START:
609 number_of_calls_query_nested_start++;
610 break;
611 case MYSQL_AUDIT_QUERY_STATUS_END:
612 number_of_calls_query_status_end++;
613 break;
614 case MYSQL_AUDIT_QUERY_NESTED_STATUS_END:
615 number_of_calls_query_nested_status_end++;
616 break;
617 default:
618 break;
619 }
620 }
621 else if (event_class == MYSQL_AUDIT_TABLE_ACCESS_CLASS)
622 {
623 const struct mysql_event_table_access *event_table=
624 (const struct mysql_event_table_access *)event;
625
626 buffer_data= sprintf(buffer, "db=\"%s\" table=\"%s\"",
627 event_table->table_database.str,
628 event_table->table_name.str);
629
630 switch (event_table->event_subclass)
631 {
632 case MYSQL_AUDIT_TABLE_ACCESS_INSERT:
633 number_of_calls_table_access_insert++;
634 break;
635 case MYSQL_AUDIT_TABLE_ACCESS_DELETE:
636 number_of_calls_table_access_delete++;
637 break;
638 case MYSQL_AUDIT_TABLE_ACCESS_UPDATE:
639 number_of_calls_table_access_update++;
640 break;
641 case MYSQL_AUDIT_TABLE_ACCESS_READ:
642 number_of_calls_table_access_read++;
643 break;
644 default:
645 break;
646 }
647 }
648 else if (event_class == MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS)
649 {
650 const struct mysql_event_global_variable *event_gvar =
651 (const struct mysql_event_global_variable *)event;
652
653 /* Copy the variable content into the buffer. We do not guarantee that the
654 variable value will fit into buffer. The buffer should be large enough
655 to be used for the test purposes. */
656 buffer_data= sprintf(buffer, "name=\"%.*s\"",
657 MY_MIN((int) event_gvar->variable_name.length,
658 (int) (sizeof(buffer) - 8)),
659 event_gvar->variable_name.str);
660
661 buffer_data+= sprintf(buffer + buffer_data, " value=\"%.*s\"",
662 MY_MIN((int) event_gvar->variable_value.length,
663 (int) (sizeof(buffer) - 16)),
664 event_gvar->variable_value.str);
665 buffer[buffer_data]= '\0';
666
667 switch (event_gvar->event_subclass)
668 {
669 case MYSQL_AUDIT_GLOBAL_VARIABLE_GET:
670 number_of_calls_global_variable_get++;
671 break;
672 case MYSQL_AUDIT_GLOBAL_VARIABLE_SET:
673 number_of_calls_global_variable_set++;
674 break;
675 default:
676 break;
677 }
678 }
679
680 process_event_record(thd, event_name, buffer, buffer_data);
681
682 if (my_charset_latin1.coll->strnncoll(&my_charset_latin1,
683 (const uchar *)event_name.str,
684 event_name.length,
685 (const uchar *)event_token.str,
686 event_token.length, 0))
687 {
688 /* Clear event command. */
689 event_command.str= NULL;
690 event_command.length= 0;
691
692 if (exact_check == 1 && event_order_started == 1)
693 {
694 if (!(event_class == MYSQL_AUDIT_GENERAL_CLASS &&
695 event_subclass == MYSQL_AUDIT_GENERAL_ERROR))
696 {
697 strxnmov(buffer, sizeof(buffer), event_name.str, " instead of ",
698 event_token.str, NullS);
699 my_message(ER_AUDIT_API_ABORT, buffer, MYF(0));
700 }
701
702 THDVAR(thd, event_order_started)= 0;
703 THDVAR(thd, event_order_check)= 0;
704
705 return 1;
706 }
707 }
708 else
709 {
710 LEX_CSTRING ignore= { C_STRING_WITH_LEN("<IGNORE>") };
711
712 /* When we are not in the event order check, check if the specified
713 data corresponds to the actual event data. */
714 if (my_charset_latin1.coll->strnncoll(&my_charset_latin1,
715 (const uchar *)event_data.str,
716 event_data.length,
717 (const uchar *) ignore.str,
718 ignore.length, 0) &&
719 my_charset_latin1.coll->strnncoll(&my_charset_latin1,
720 (const uchar *) event_data.str,
721 event_data.length,
722 (const uchar *)buffer,
723 (size_t)buffer_data, 0))
724 {
725 if (exact_check == 1 && event_order_started == 1)
726 {
727 char invalid_data_buffer[sizeof(buffer)]= { 0, };
728 LEX_CSTRING status= { C_STRING_WITH_LEN("EVENT-ORDER-INVALID-DATA") };
729 LEX_CSTRING order_cstr;
730
731 lex_cstring_set(&order_cstr,
732 (const char *)THDVAR(thd, event_order_check));
733
734 memmove((char *)order_cstr.str,
735 (void *)status.str, status.length + 1);
736
737 strxnmov(invalid_data_buffer, sizeof(invalid_data_buffer),
738 "Invalid data for '", event_name.str, "' -> ", buffer, NullS);
739 my_message(ER_AUDIT_API_ABORT, invalid_data_buffer, MYF(0));
740
741 THDVAR(thd, event_order_started)= 0;
742 THDVAR(thd, event_order_check)= (char *)order_cstr.str;
743
744 return 1;
745 }
746
747 /* Clear event command. */
748 event_command.str= NULL;
749 event_command.length= 0;
750 }
751 else
752 {
753 LEX_CSTRING order_cstr;
754 ulong consume= THDVAR(thd, event_order_check_consume_ignore_count);
755 lex_cstring_set(&order_cstr,
756 (const char *)THDVAR(thd, event_order_check));
757
758 THDVAR(thd, event_order_started)= 1;
759
760 if (consume)
761 {
762 /*
763 Do not consume event this time. Just decrease value and wait until
764 the next event is matched.
765 */
766 THDVAR(thd, event_order_check_consume_ignore_count)= consume - 1;
767 consume_event= FALSE;
768 }
769 else
770 {
771 /* Consume matched event. */
772 memmove((char*)order_cstr.str, (void*)order_str,
773 order_cstr.length - (order_str - order_cstr.str) + 1);
774
775 /* Count new length. */
776 lex_cstring_set(&order_cstr, order_cstr.str);
777
778 if (order_cstr.length == 0)
779 {
780 LEX_CSTRING status = { C_STRING_WITH_LEN("EVENT-ORDER-OK") };
781
782 memmove((char *)order_cstr.str,
783 (void *)status.str, status.length + 1);
784
785 /* event_order_started contains message. Do not verify it. */
786 THDVAR(thd, event_order_started)= 0;
787 }
788 }
789 }
790 }
791
792 return process_command(thd, event_command, consume_event);
793 }
794
795 /*
796 Plugin type-specific descriptor
797 */
798
799 static struct st_mysql_audit audit_null_descriptor=
800 {
801 MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */
802 NULL, /* release_thd function */
803 audit_null_notify, /* notify function */
804 { (unsigned long) MYSQL_AUDIT_GENERAL_ALL,
805 (unsigned long) MYSQL_AUDIT_CONNECTION_ALL,
806 (unsigned long) MYSQL_AUDIT_PARSE_ALL,
807 0, /* This event class is currently not supported. */
808 (unsigned long) MYSQL_AUDIT_TABLE_ACCESS_ALL,
809 (unsigned long) MYSQL_AUDIT_GLOBAL_VARIABLE_ALL,
810 (unsigned long) MYSQL_AUDIT_SERVER_STARTUP_ALL,
811 (unsigned long) MYSQL_AUDIT_SERVER_SHUTDOWN_ALL,
812 (unsigned long) MYSQL_AUDIT_COMMAND_ALL,
813 (unsigned long) MYSQL_AUDIT_QUERY_ALL,
814 (unsigned long) MYSQL_AUDIT_STORED_PROGRAM_ALL }
815 };
816
817 static struct st_mysql_sys_var* system_variables[] = {
818
819 MYSQL_SYSVAR(abort_message),
820 MYSQL_SYSVAR(abort_value),
821
822 MYSQL_SYSVAR(event_order_check),
823 MYSQL_SYSVAR(event_order_check_consume_ignore_count),
824 MYSQL_SYSVAR(event_order_started),
825 MYSQL_SYSVAR(event_order_check_exact),
826
827 MYSQL_SYSVAR(event_record_def),
828 MYSQL_SYSVAR(event_record),
829 NULL
830 };
831
832 /*
833 Plugin library descriptor
834 */
835
mysql_declare_plugin(audit_null)836 mysql_declare_plugin(audit_null)
837 {
838 MYSQL_AUDIT_PLUGIN, /* type */
839 &audit_null_descriptor, /* descriptor */
840 "NULL_AUDIT", /* name */
841 "Oracle Corp", /* author */
842 "Simple NULL Audit", /* description */
843 PLUGIN_LICENSE_GPL,
844 audit_null_plugin_init, /* init function (when loaded) */
845 audit_null_plugin_deinit, /* deinit function (when unloaded) */
846 0x0003, /* version */
847 simple_status, /* status variables */
848 system_variables, /* system variables */
849 NULL,
850 0,
851 }
852 mysql_declare_plugin_end;
853