postgresql ident驗證機制的實現

  postgresql 數據庫中提供了ident驗證機制。postgresql中的ident驗證機制的實現方式是向客戶端的113號端口發送消息來查詢系統用戶信息。經過系統用戶信息來驗證客戶的安全性。sql

1. 113號端口

   113號端口是一個許多計算機上運行的協議,用於鑑別TCP鏈接的用戶。使用標準的這種服務能夠得到許多計算機的信息。可是它可做爲許多服務的記錄器,尤爲是FTP、POP、IMAP、SMTP和IRC等服務。數據庫

2. ident驗證機制的使用

    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

3. 實現的原理

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的實現仍是比較簡單的。

相關文章
相關標籤/搜索