探索MySQL源代码-客户端连接过程和用户认证体系
2015-06-05 11:14
513 查看
本文从源代码角度详细解释使用mysql客户端连上MySQL的服务端的过程以及通过用户认证的过程。
用户在客户端键入
mysql -h a.b.c.d -u root -pxxxx
最终都会调用到mysql_real_connect(sql/client.c的1856行的宏CLI_MYSQL_REAL_CONNECT),我们从这个函数出发。
先上图
1 客户端发起socket连接,等待三次握手的通过。
2 三次握手通过之后,客户端进入client_safe_read阻塞,同时服务端从handle_connection_sockets函数的select处返回,获知有新的连接。
3 服务端创建线程(这里就不说thread cache了),然后开始对这个连接进行校验。
4 login_connection(sql/sql_connect.c)下的check_connection为的主校验函数。
5 check_connection 首先回调用acl_check_host(sql/sql_acl.cc) 判断该ip是否能够连接。
acl_check_host 依次查找2个对象来做判断:一个是动态数组acl_wild_hosts,另一个是hash表acl_check_hosts。
VOID(my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
acl_users.elements,1));
VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0,
(hash_get_key) check_get_key,0,0));
这2个对象都是在mysqld启动的时候,通过init_check_host()函数从mysq.users表里读出并加载的。
其中acl_wild_hosts用于存放有统配符的主机,acl_check_hosts存放具体的主机。
6 通过acl_check_host校验后,来到create_random_string(sql/sql_connect.c)函数。这个函数随机的产生一个20字节的scramble串,用于接下来密码SHA1加密。
(gdb) p
thd->scramble
$3 = "p}DwPf4kCJ+8vk5cuD3q
7 服务端通过net_write_command函数把这个scramble以及当前的服务端版本发送给客户端,然后自己阻塞在my_net_read里,等待客户端的命令,这里的阻塞有个最小握手时间MIN_HANDSHAKE_SIZE。
8 客户端从cli_safe_read阻塞中返回,获知版本和scramble。进行版本匹配后,对输入的密码进行sha1加密(加密的公司后面详细说明),然后再发送给服务端。
9 服务端从my_net_read返回来,拿到登录的用户名和密码。
10 来到check_user(sql/sql_connect.c)函数,其中的acl_getroot是对密码进行了校验,关键函数是check_scramble。下面详细说明密码比较过程,伪代码方便理解。
===客户端的 scrabmle======
password 来自于用户键入的密码
scramble 来自于create_random_string 产生的20字节的随机字符
reply 就是发送给服务端的加密密码
scramble(password, scramble)
{
hash_stage1 = sha1(password)
hash_stage2 = sha1(hash_stage1)
to = sha1(scramble, hash_stage2)
reply = xor(to, hash_stage1)
}
===服务端的check_scramble =====
reply 来自于客户端发送的加密密码
scramble create_random_string 产生的随机字符
store_password 就是mysql.user 表的password的字段(password函数实际上进行了两次的sha1加密)
check_scramble(reply, scramble, store_password)
{
to = sha1(scramble, store_password)
my_hash_stage1 = xor(to, reply)
return store_password == sha1(my_hash_stage1)
}
拿reply进行异或的逆运算得到sha1加密的密码,然后与数据库内的做比较。
关键点就是异或的特点 A XOR B XOR B = A
11 acl_getroot通过后,连接就通过了用户认证。
12 告知客户端认证正常,接下来的sql执行步骤可见我以前的博文
用户在客户端键入
mysql -h a.b.c.d -u root -pxxxx
最终都会调用到mysql_real_connect(sql/client.c的1856行的宏CLI_MYSQL_REAL_CONNECT),我们从这个函数出发。
先上图
1 客户端发起socket连接,等待三次握手的通过。
2 三次握手通过之后,客户端进入client_safe_read阻塞,同时服务端从handle_connection_sockets函数的select处返回,获知有新的连接。
3 服务端创建线程(这里就不说thread cache了),然后开始对这个连接进行校验。
4 login_connection(sql/sql_connect.c)下的check_connection为的主校验函数。
5 check_connection 首先回调用acl_check_host(sql/sql_acl.cc) 判断该ip是否能够连接。
acl_check_host 依次查找2个对象来做判断:一个是动态数组acl_wild_hosts,另一个是hash表acl_check_hosts。
VOID(my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
acl_users.elements,1));
VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0,
(hash_get_key) check_get_key,0,0));
这2个对象都是在mysqld启动的时候,通过init_check_host()函数从mysq.users表里读出并加载的。
其中acl_wild_hosts用于存放有统配符的主机,acl_check_hosts存放具体的主机。
6 通过acl_check_host校验后,来到create_random_string(sql/sql_connect.c)函数。这个函数随机的产生一个20字节的scramble串,用于接下来密码SHA1加密。
(gdb) p
thd->scramble
$3 = "p}DwPf4kCJ+8vk5cuD3q
7 服务端通过net_write_command函数把这个scramble以及当前的服务端版本发送给客户端,然后自己阻塞在my_net_read里,等待客户端的命令,这里的阻塞有个最小握手时间MIN_HANDSHAKE_SIZE。
8 客户端从cli_safe_read阻塞中返回,获知版本和scramble。进行版本匹配后,对输入的密码进行sha1加密(加密的公司后面详细说明),然后再发送给服务端。
9 服务端从my_net_read返回来,拿到登录的用户名和密码。
10 来到check_user(sql/sql_connect.c)函数,其中的acl_getroot是对密码进行了校验,关键函数是check_scramble。下面详细说明密码比较过程,伪代码方便理解。
===客户端的 scrabmle======
password 来自于用户键入的密码
scramble 来自于create_random_string 产生的20字节的随机字符
reply 就是发送给服务端的加密密码
scramble(password, scramble)
{
hash_stage1 = sha1(password)
hash_stage2 = sha1(hash_stage1)
to = sha1(scramble, hash_stage2)
reply = xor(to, hash_stage1)
}
===服务端的check_scramble =====
reply 来自于客户端发送的加密密码
scramble create_random_string 产生的随机字符
store_password 就是mysql.user 表的password的字段(password函数实际上进行了两次的sha1加密)
check_scramble(reply, scramble, store_password)
{
to = sha1(scramble, store_password)
my_hash_stage1 = xor(to, reply)
return store_password == sha1(my_hash_stage1)
}
拿reply进行异或的逆运算得到sha1加密的密码,然后与数据库内的做比较。
关键点就是异或的特点 A XOR B XOR B = A
11 acl_getroot通过后,连接就通过了用户认证。
12 告知客户端认证正常,接下来的sql执行步骤可见我以前的博文
相关文章推荐
- Mysql 创建,授权,删除用户
- 如何查看mysql数据库表所使用的引擎(转载)
- 报错:1130-host ... is not allowed to connect to this MySql server 开放mysql远程连接 不使用localhost
- MySQL安装
- mysql 常用命令
- mysql主从复制讲解
- mysql主从复制讲解
- mysql导入导出sql文件
- MySQL事物系列:3:innodb_flush_log_at_trx_commit小实验
- mysql主从同步配置详解
- mysql主从
- 前台、后台、mysql,出现中文乱码或“???”
- mysql多表查询、子查询
- Mysql事务,并发问题,锁机制
- Mysql慢查询配置
- Mysql中事务隔离级别与binlog_format的一点理解
- mysql事务和锁InnoDB
- mysql数据库锁机制
- mysql修改密码
- MySQL搭建Amoeba_读写分离