MySQL新特性之mysql_config_editor源碼解析
從mysql5.6開始,mysql推出了加密工具mysql_config_editor。在此之前我們通過將帳號和密碼明文放入my.cnf,從而使用mysql用戶端登入時,無需指定帳號密碼就可以登入資料庫。而有了mysql_config_editor工具之後,我們將加密後的帳號密碼放入二進位檔案。在登入時,用戶端通過解密該檔案來登入資料庫。由於加密解密都在記憶體中進行,所以無法明文的顯示檔案內容。只要我們將檔案許可權儲存好,就可以防止不懷好意的人解密我們的資料庫密碼了.
mysql_config_editor的使用過程如下:
mysql_config_editor set --login-path=client --host=localhost --user=localuser --password
這樣我們就配置了一個為本地的資料來源資訊:
login-path :指定通過mysql用戶端登入時的標識
host:我們要串連的資料庫
user: 通過本地串連資料庫時,使用的帳號
password:指定通過本地串連時,使用的資料庫密碼(這裡假設輸入的密碼為password1)
當然,如果通過遠端連線,我們可能還要加上特定的連接埠資訊。這樣,當我們登入資料庫時,只需要如下命令就可以串連到該資料庫了:
mysql —login-path=client
這樣我們就串連到本機資料庫了。
下面我們來看看mysql_config_editor的細節部分:
由於該工具包含set/remove/print/reset/help,所以我們僅分析set功能的實現:
set功能是通過set_command函數實現的,該函數主要用於配置帳號密碼等資料來源資訊,並將該資訊儲存到二進位檔案:
點擊(此處)摺疊或開啟
static int set_command(void)
{
DBUG_ENTER("set_command");
DYNAMIC_STRING file_buf, path_buf;
init_dynamic_string(&path_buf, "", MY_LINE_MAX, MY_LINE_MAX);
init_dynamic_string(&file_buf, "", file_size, 3 * MY_LINE_MAX);
if (tty_password)
opt_password= get_tty_password(NullS);
if (file_size)
{
if (read_and_decrypt_file(&file_buf) == -1) //如果檔案存在,就讀取檔案,並將檔案的密文解密後存放到file_buf中.
goto error;
}
dynstr_append(&path_buf, "["); /* --login=path */
if (opt_login_path)
dynstr_append(&path_buf, opt_login_path);
else
dynstr_append(&path_buf, "client");
dynstr_append(&path_buf, "]");
if (opt_user) /* --user */
{
dynstr_append(&path_buf, "\nuser = ");
dynstr_append(&path_buf, opt_user);
}
if (opt_password) /* --password */
{
dynstr_append(&path_buf, "\npassword = ");
dynstr_append(&path_buf, opt_password);
}
if (opt_host) /* --host */
{
dynstr_append(&path_buf, "\nhost = ");
dynstr_append(&path_buf, opt_host);
}
if (opt_socket)
{
dynstr_append(&path_buf, "\nsocket = ");
dynstr_append(&path_buf, opt_socket);
}
if (opt_port)
{
dynstr_append(&path_buf, "\nport = ");
dynstr_append(&path_buf, opt_port);
}
dynstr_append(&path_buf, "\n");
/* Warn if login path already exists */
if (opt_warn && ((locate_login_path (&file_buf, opt_login_path)) //判斷該login-path是否已經存在
!= NULL))
{
int choice;
printf ("WARNING : \'%s\' path already exists and will be "
"overwritten. \n Continue? (Press y|Y for Yes, any "
"other key for No) : ",
opt_login_path);
choice= getchar();
if (choice != (int) 'y' && choice != (int) 'Y’) //如果login-path存在是否選擇覆蓋
goto done; /* skip */
}
/* Remove the login path. */
remove_login_path(&file_buf, opt_login_path); //從原來檔案中讀取的內容中,刪掉該login-path資訊
/* Append the new login path to the file buffer. */
dynstr_append(&file_buf, path_buf.str); //將該login-path的資訊加到file_buf的末尾
if (encrypt_and_write_file(&file_buf) == -1) //將包含新的log-path的所有資訊和原來的資訊加密寫入檔案
goto error;
done:
dynstr_free(&file_buf);
dynstr_free(&path_buf);
DBUG_RETURN(0);
error:
dynstr_free(&file_buf);
dynstr_free(&path_buf);
DBUG_RETURN(-1);
}
代碼的具體邏輯如下:
在這裡我們重點看看其中涉及的幾個重要的函數:
read_and_decrypt_file (讀取檔案內容,並解密後放到動態字元緩衝中)
locate_login_path(判斷該login-path是否已經存在)
remove_login_path(如果login-path存在,則刪除該login-path)
dynstr_append(&file_buf, path_buf.str); 將新的login-path添加到file_buf 末尾
encrypt_and_write_file(&file_buf) 將file_buf中的資訊解碼後寫入到檔案中
首先我們來看看加密後的檔案格式如下:
這裡我們假設之前已經存在加密的檔案了.
更多詳情見請繼續閱讀下一頁的精彩內容: