前端之家收集整理的这篇文章主要介绍了
postgresql 源码客户端认证,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
--在使用pg中登陆数据库是第一步,其代码结构如下:
--原始代码在如下文件中
src/backend/libpq/auth.c
--其入口函数为ClientAuthentication,其接受一个Port结构体
void
ClientAuthentication(Port *port)
{
--通过此函数解析客户的ip类型,确定其使用的是什么样的方式进行认证,比如能过local还是ip,是md5还是trust认证等
-- hba_getauthmethod 会调用函数 check_hba()
hba_getauthmethod(port);
CHECK_FOR_INTERRUPTS();
--匹配pg的认证方法,比如我们最常用的md5
switch (port->hba->auth_method)
{
case uaReject:
case uaMD5:
if (Db_user_namespace)
ereport(FATAL,(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
--提示用户输入密码并对用户输入的密码进行加密
sendAuthRequest(port,AUTH_REQ_MD5);
--比较用户输入的密码与数据库中存在的密码是否一致,其会调用md5_crypt_verify函数
status = recv_and_check_password_packet(port,&logdetail);
break;
}
--检查系统中中是否有hook,如果有,则调用
if (ClientAuthentication_hook)
(*ClientAuthentication_hook) (port,status);
--判断用户认证是否成功
if (status == STATUS_OK)
sendAuthRequest(port,AUTH_REQ_OK);
else
--如果认证失败,则发送失败信息给客户端
auth_Failed(port,status,logdetail);
}
--通过check_hba函数的foreach可知,pg是从上往下匹配pg_hba.conf的文件内容,如果为满足则其返回
--故在pg_hba.conf上面的认证方式如果与下面的认证方式会覆盖下面的认证方式
static void check_hba(hbaPort *port)
{
Oid roleid;
ListCell *line;
HbaLine *hba;
/* Get the target role's OID. Note we do not error out for bad role. */
roleid = get_role_oid(port->user_name,true);
--一行一行的对比pg_hba.conf的内容,直到匹配
foreach(line,parsed_hba_lines)
{
hba = (HbaLine *) lfirst(line);
/* Check connection type */
if (hba->conntype == ctLocal)
{
if (!IS_AF_UNIX(port->raddr.addr.ss_family))
continue;
}
else
{
do something;
} /* != ctLocal */
/* Check database and role */
if (!check_db(port->database_name,port->user_name,roleid,hba->databases))
continue;
if (!check_role(port->user_name,hba->roles))
continue;
/* Found a record that matched! */
port->hba = hba;
return;
}
/* If no matching entry was found,then implicitly reject. */
hba = palloc0(sizeof(HbaLine));
hba->auth_method = uaImplicitReject;
port->hba = hba;
}
--比较用户输入的密码与数据库中存在的密码是否一致
int md5_crypt_verify(const Port *port,const char *role,char *client_pass,char **logdetail)
{
--根据用户名,获取系统缓存的数据库密码
datum = SysCacheGetAttr(AUTHNAME,roleTup,Anum_pg_authid_rolpassword,&isnull);
if (isnull)
{
ReleaseSysCache(roleTup);
*logdetail = psprintf(_("User \"%s\" has no password assigned."),role);
return STATUS_ERROR; /* user has no password */
}
shadow_pass = TextDatumGetCString(datum);
--比较密码是否相同
if (strcmp(crypt_client_pass,crypt_pwd) == 0)
{
/*
* Password OK,now check to be sure we are not past rolvaliduntil
*/
if (isnull)
retval = STATUS_OK;
else if (vuntil < GetCurrentTimestamp())
{
*logdetail = psprintf(_("User \"%s\" has an expired password."),role);
retval = STATUS_ERROR;
}
else
retval = STATUS_OK;
}
return retval;
}
原文链接:https://www.f2er.com/postgresql/194716.html