diff options
author | Sergei Golubchik <serg@mariadb.org> | 2015-09-02 09:58:08 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2015-09-04 10:33:55 +0200 |
commit | b85a00161e91080cb82b99e812c18eafb6467737 (patch) | |
tree | 3b502db8d25f0eb0a93901e3417d097626ecf8ea /sql/sql_repl.cc | |
parent | 41d68cabee1d9c2a8e8c7a006b17070392a85ed7 (diff) | |
download | mariadb-git-b85a00161e91080cb82b99e812c18eafb6467737.tar.gz |
MDEV-8264 encryption for binlog
* Start_encryption_log_event
* --encrypt-binlog command line option
based on google patches.
Diffstat (limited to 'sql/sql_repl.cc')
-rw-r--r-- | sql/sql_repl.cc | 160 |
1 files changed, 137 insertions, 23 deletions
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 2a4c26de1c9..5cf55d89d3e 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -644,6 +644,9 @@ void set_read_error(binlog_send_info *info, int error) case LOG_READ_CHECKSUM_FAILURE: info->errmsg= "event read from binlog did not pass crc check"; break; + case LOG_READ_DECRYPT: + info->errmsg= "event decryption failure"; + break; default: info->errmsg= "unknown error reading log event on the master"; break; @@ -918,9 +921,14 @@ get_gtid_list_event(IO_CACHE *cache, Gtid_list_log_event **out_gtid_list) typ= ev->get_type_code(); if (typ == GTID_LIST_EVENT) break; /* Done, found it */ + if (typ == START_ENCRYPTION_EVENT) + { + if (fdle->start_decryption((Start_encryption_log_event*) ev)) + errormsg= "Could not set up decryption for binlog."; + } delete ev; if (typ == ROTATE_EVENT || typ == STOP_EVENT || - typ == FORMAT_DESCRIPTION_EVENT) + typ == FORMAT_DESCRIPTION_EVENT || typ == START_ENCRYPTION_EVENT) continue; /* Continue looking */ /* We did not find any Gtid_list_log_event, must be old binlog. */ @@ -1437,7 +1445,7 @@ gtid_state_from_pos(const char *name, uint32 offset, break; packet.length(0); - err= Log_event::read_log_event(&cache, &packet, + err= Log_event::read_log_event(&cache, &packet, fdev, opt_master_verify_checksum ? current_checksum_alg : BINLOG_CHECKSUM_ALG_OFF); if (err) @@ -1474,6 +1482,20 @@ gtid_state_from_pos(const char *name, uint32 offset, delete fdev; fdev= tmp; } + else if (typ == START_ENCRYPTION_EVENT) + { + uint sele_len = packet.length(); + if (current_checksum_alg == BINLOG_CHECKSUM_ALG_CRC32) + { + sele_len -= BINLOG_CHECKSUM_LEN; + } + Start_encryption_log_event sele(packet.ptr(), sele_len, fdev); + if (fdev->start_decryption(&sele)) + { + errormsg= "Could not start decryption of binlog."; + goto end; + } + } else if (typ != FORMAT_DESCRIPTION_EVENT && !found_format_description_event) { errormsg= "Did not find format description log event while searching " @@ -2216,9 +2238,10 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, the binlog */ info->last_pos= my_b_tell(log); - error= Log_event::read_log_event(log, packet, + error= Log_event::read_log_event(log, packet, info->fdev, opt_master_verify_checksum - ? info->current_checksum_alg : BINLOG_CHECKSUM_ALG_OFF); + ? info->current_checksum_alg + : BINLOG_CHECKSUM_ALG_OFF); linfo->pos= my_b_tell(log); if (error) @@ -2268,10 +2291,13 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, return 1; } + uint ev_len= packet->length() - ev_offset; + if (info->current_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF) + ev_len-= BINLOG_CHECKSUM_LEN; + Format_description_log_event *tmp; - if (!(tmp= new Format_description_log_event(packet->ptr()+ev_offset, - packet->length()-ev_offset, - info->fdev))) + if (!(tmp= new Format_description_log_event(packet->ptr() + ev_offset, + ev_len, info->fdev))) { info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG; info->errmsg= "Corrupt Format_description event found " @@ -2338,6 +2364,57 @@ static int send_format_descriptor_event(binlog_send_info *info, IO_CACHE *log, return 1; } + /* + Read the following Start_encryption_log_event but don't send it to slave. + Slave doesn't need to know whether master's binlog is encrypted, + and if it'll want to encrypt its logs, it should generate its own + random nonce, not use the one from the master. + */ + packet->length(0); + info->last_pos= linfo->pos; + error= Log_event::read_log_event(log, packet, info->fdev, + opt_master_verify_checksum + ? info->current_checksum_alg + : BINLOG_CHECKSUM_ALG_OFF); + linfo->pos= my_b_tell(log); + + if (error) + { + set_read_error(info, error); + return 1; + } + + event_type= (Log_event_type)((uchar)(*packet)[LOG_EVENT_OFFSET]); + if (event_type == START_ENCRYPTION_EVENT) + { + Start_encryption_log_event *sele= (Start_encryption_log_event *) + Log_event::read_log_event(packet->ptr(), packet->length(), &info->errmsg, + info->fdev, BINLOG_CHECKSUM_ALG_OFF); + if (!sele) + { + info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG; + return 1; + } + + if (info->fdev->start_decryption(sele)) + { + info->error= ER_MASTER_FATAL_ERROR_READING_BINLOG; + info->errmsg= "Could not decrypt binlog: encryption key error"; + return 1; + } + delete sele; + } + else if (start_pos == BIN_LOG_HEADER_SIZE) + { + /* + not Start_encryption_log_event - seek back. But only if + send_one_binlog_file() isn't going to seek anyway + */ + my_b_seek(log, info->last_pos); + linfo->pos= info->last_pos; + } + + /** all done */ return 0; } @@ -2547,7 +2624,7 @@ static int send_events(binlog_send_info *info, IO_CACHE* log, LOG_INFO* linfo, return 1; info->last_pos= linfo->pos; - error= Log_event::read_log_event(log, packet, + error= Log_event::read_log_event(log, packet, info->fdev, opt_master_verify_checksum ? info->current_checksum_alg : BINLOG_CHECKSUM_ALG_OFF); linfo->pos= my_b_tell(log); @@ -2598,8 +2675,9 @@ static int send_events(binlog_send_info *info, IO_CACHE* log, LOG_INFO* linfo, }); #endif - if ((info->errmsg= send_event_to_slave(info, event_type, log, - ev_offset, &info->error_gtid))) + if (event_type != START_ENCRYPTION_EVENT && + ((info->errmsg= send_event_to_slave(info, event_type, log, + ev_offset, &info->error_gtid)))) return 1; if (unlikely(info->send_fake_gtid_list) && @@ -3876,38 +3954,52 @@ bool mysql_show_binlog_events(THD* thd) Read the first event in case it's a Format_description_log_event, to know the format. If there's no such event, we are 3.23 or 4.x. This code, like before, can't read 3.23 binlogs. + Also read the second event, in case it's a Start_encryption_log_event. This code will fail on a mixed relay log (one which has Format_desc then Rotate then Format_desc). */ - ev= Log_event::read_log_event(&log, (mysql_mutex_t*)0, description_event, - opt_master_verify_checksum); - if (ev) + + my_off_t scan_pos = BIN_LOG_HEADER_SIZE; + while (scan_pos < pos) { + ev= Log_event::read_log_event(&log, (mysql_mutex_t*)0, description_event, + opt_master_verify_checksum); + scan_pos = my_b_tell(&log); + if (ev == NULL || !ev->is_valid()) + { + mysql_mutex_unlock(log_lock); + errmsg = "Wrong offset or I/O error"; + goto err; + } if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT) { delete description_event; description_event= (Format_description_log_event*) ev; } else + { + if (ev->get_type_code() == START_ENCRYPTION_EVENT) + { + if (description_event->start_decryption((Start_encryption_log_event*) ev)) + { + delete ev; + mysql_mutex_unlock(log_lock); + errmsg = "Could not initialize decryption of binlog."; + goto err; + } + } delete ev; + break; + } } my_b_seek(&log, pos); - if (!description_event->is_valid()) - { - errmsg="Invalid Format_description event; could be out of memory"; - goto err; - } - for (event_count = 0; (ev = Log_event::read_log_event(&log, (mysql_mutex_t*) 0, description_event, opt_master_verify_checksum)); ) { - if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT) - description_event->checksum_alg= ev->checksum_alg; - if (event_count >= limit_start && ev->net_send(thd, protocol, linfo.log_file_name, pos)) { @@ -3917,8 +4009,30 @@ bool mysql_show_binlog_events(THD* thd) goto err; } + if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT) + { + Format_description_log_event* new_fdle= + (Format_description_log_event*) ev; + new_fdle->copy_crypto_data(description_event); + delete description_event; + description_event= new_fdle; + } + else + { + if (ev->get_type_code() == START_ENCRYPTION_EVENT) + { + if (description_event->start_decryption((Start_encryption_log_event*) ev)) + { + errmsg = "Error starting decryption"; + delete ev; + mysql_mutex_unlock(log_lock); + goto err; + } + } + delete ev; + } + pos = my_b_tell(&log); - delete ev; if (++event_count >= limit_end) break; |