postgresql 数据库中提供了ident验证机制。postgresql中的ident验证机制的实现方式是向客户端的113号端口发送消息来查询系统用户信息。经过系统用户信息来验证客户的安全性。sql
113号端口是一个许多计算机上运行的协议,用于鉴别TCP链接的用户。使用标准的这种服务能够得到许多计算机的信息。可是它可做为许多服务的记录器,尤为是FTP、POP、IMAP、SMTP和IRC等服务。数据库
1)配置pg_ident.conf文件安全
这个文件配置的是系统用户与数据库用户之间的一种映射关系。这个文件的配置方法以下所示:socket
上面的例子是来自postgres官方文档,其中omicron是map name,一个map name能够对应多个系统用户与数据库用户的映射。在编写好这个映射文件后就须要配置pg_hba.conf文件。ide
2)配置pg_hba.conf文件函数
上图中172.30.12.0的客户端的验证方式是ident,map name为omicron。oop
ident验证方式的实现函数是ident_inet。post
1)建立一个socketspa
sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype, ident_serv->ai_protocol); if (sock_fd == PGINVALID_SOCKET) { ereport(LOG, (errcode_for_socket_access(), errmsg("could not create socket for Ident connection: %m"))); ident_return = false; goto ident_inet_done; }
2)绑定sock_fd到本地地址上面postgresql
rc = bind(sock_fd, la->ai_addr, la->ai_addrlen); if (rc != 0) { ereport(LOG, (errcode_for_socket_access(), errmsg("could not bind to local address \"%s\": %m", local_addr_s))); ident_return = false; goto ident_inet_done; }
3. 创建到客户端的链接
rc = connect(sock_fd, ident_serv->ai_addr,ident_serv->ai_addrlen); if (rc != 0) { ereport(LOG, (errcode_for_socket_access(), errmsg("could not connect to Ident server at address \"%s\", port %s: %m", remote_addr_s, ident_port))); ident_return = false; goto ident_inet_done; }
4.发送查询到客户端
/* The query we send to the Ident server */ snprintf(ident_query, sizeof(ident_query), "%s,%s\r\n", remote_port, local_port); /* loop in case send is interrupted */ do { rc = send(sock_fd, ident_query, strlen(ident_query), 0); } while (rc < 0 && errno == EINTR);
5. 接收并解析数据
do { rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0); } while (rc < 0 && errno == EINTR); if (rc < 0) { ereport(LOG, (errcode_for_socket_access(), errmsg("could not receive response from Ident server at address \"%s\", port %s: %m", remote_addr_s, ident_port))); ident_return = false; goto ident_inet_done; } ident_response[rc] = '\0'; ident_return = interpret_ident_response(ident_response, ident_user); if (!ident_return) ereport(LOG, (errmsg("invalidly formatted response from Ident server: \"%s\"", ident_response)));
接收到的数据相似于2000:USERID::harris\r\n这样的格式。其中2000是端口号,harris是系统用户名。经过interpret_ident_response函数解析出系统用户名。
6. 经过user map判断用户是否合法
if (ident_return) /* Success! Check the usermap */ return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
则合法就认为验证经过,不然认为验证失败。经过上面的整个过程来看ident的实现仍是比较简单的。