⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hba.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
			(errcode(ERRCODE_CONFIG_FILE_ERROR),			 errmsg("missing entry in file \"%s\" at end of line %d",					IdentFileName, line_number)));	*error_p = true;}/* *	Scan the (pre-parsed) ident usermap file line by line, looking for a match * *	See if the user with ident username "ident_user" is allowed to act *	as Postgres user "pgrole" according to usermap "usermap_name". * *	Special case: For usermap "samerole", don't look in the usermap *	file.  That's an implied map where "pgrole" must be identical to *	"ident_user" in order to be authorized. * *	Iff authorized, return true. */static boolcheck_ident_usermap(const char *usermap_name,					const char *pg_role,					const char *ident_user){	bool		found_entry = false,				error = false;	if (usermap_name == NULL || usermap_name[0] == '\0')	{		ereport(LOG,				(errcode(ERRCODE_CONFIG_FILE_ERROR),		   errmsg("cannot use Ident authentication without usermap field")));		found_entry = false;	}	else if (strcmp(usermap_name, "sameuser\n") == 0 ||			 strcmp(usermap_name, "samerole\n") == 0)	{		if (strcmp(pg_role, ident_user) == 0)			found_entry = true;		else			found_entry = false;	}	else	{		ListCell   *line_cell,				   *num_cell;		forboth(line_cell, ident_lines, num_cell, ident_line_nums)		{			parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell),								usermap_name, pg_role, ident_user,								&found_entry, &error);			if (found_entry || error)				break;		}	}	return found_entry;}/* * Read the ident config file and create a List of Lists of tokens in the file. */voidload_ident(void){	FILE	   *file;	if (ident_lines || ident_line_nums)		free_lines(&ident_lines, &ident_line_nums);	file = AllocateFile(IdentFileName, "r");	if (file == NULL)	{		/* not fatal ... we just won't do any special ident maps */		ereport(LOG,				(errcode_for_file_access(),				 errmsg("could not open Ident usermap file \"%s\": %m",						IdentFileName)));	}	else	{		tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums);		FreeFile(file);	}}/* *	Parse the string "*ident_response" as a response from a query to an Ident *	server.  If it's a normal response indicating a user name, return true *	and store the user name at *ident_user. If it's anything else, *	return false. */static boolinterpret_ident_response(const char *ident_response,						 char *ident_user){	const char *cursor = ident_response;		/* Cursor into *ident_response */	/*	 * Ident's response, in the telnet tradition, should end in crlf (\r\n).	 */	if (strlen(ident_response) < 2)		return false;	else if (ident_response[strlen(ident_response) - 2] != '\r')		return false;	else	{		while (*cursor != ':' && *cursor != '\r')			cursor++;			/* skip port field */		if (*cursor != ':')			return false;		else		{			/* We're positioned to colon before response type field */			char		response_type[80];			int			i;		/* Index into *response_type */			cursor++;			/* Go over colon */			while (pg_isblank(*cursor))				cursor++;		/* skip blanks */			i = 0;			while (*cursor != ':' && *cursor != '\r' && !pg_isblank(*cursor) &&				   i < (int) (sizeof(response_type) - 1))				response_type[i++] = *cursor++;			response_type[i] = '\0';			while (pg_isblank(*cursor))				cursor++;		/* skip blanks */			if (strcmp(response_type, "USERID") != 0)				return false;			else			{				/*				 * It's a USERID response.  Good.  "cursor" should be pointing				 * to the colon that precedes the operating system type.				 */				if (*cursor != ':')					return false;				else				{					cursor++;	/* Go over colon */					/* Skip over operating system field. */					while (*cursor != ':' && *cursor != '\r')						cursor++;					if (*cursor != ':')						return false;					else					{						int			i;	/* Index into *ident_user */						cursor++;		/* Go over colon */						while (pg_isblank(*cursor))							cursor++;	/* skip blanks */						/* Rest of line is user name.  Copy it over. */						i = 0;						while (*cursor != '\r' && i < IDENT_USERNAME_MAX)							ident_user[i++] = *cursor++;						ident_user[i] = '\0';						return true;					}				}			}		}	}}/* *	Talk to the ident server on host "remote_ip_addr" and find out who *	owns the tcp connection from his port "remote_port" to port *	"local_port_addr" on host "local_ip_addr".	Return the user name the *	ident server gives as "*ident_user". * *	IP addresses and port numbers are in network byte order. * *	But iff we're unable to get the information from ident, return false. */static boolident_inet(const SockAddr remote_addr,		   const SockAddr local_addr,		   char *ident_user){	int			sock_fd,		/* File descriptor for socket on which we talk								 * to Ident */				rc;				/* Return code from a locally called function */	bool		ident_return;	char		remote_addr_s[NI_MAXHOST];	char		remote_port[NI_MAXSERV];	char		local_addr_s[NI_MAXHOST];	char		local_port[NI_MAXSERV];	char		ident_port[NI_MAXSERV];	char		ident_query[80];	char		ident_response[80 + IDENT_USERNAME_MAX];	struct addrinfo *ident_serv = NULL,			   *la = NULL,				hints;	/*	 * Might look a little weird to first convert it to text and then back to	 * sockaddr, but it's protocol independent.	 */	pg_getnameinfo_all(&remote_addr.addr, remote_addr.salen,					   remote_addr_s, sizeof(remote_addr_s),					   remote_port, sizeof(remote_port),					   NI_NUMERICHOST | NI_NUMERICSERV);	pg_getnameinfo_all(&local_addr.addr, local_addr.salen,					   local_addr_s, sizeof(local_addr_s),					   local_port, sizeof(local_port),					   NI_NUMERICHOST | NI_NUMERICSERV);	snprintf(ident_port, sizeof(ident_port), "%d", IDENT_PORT);	hints.ai_flags = AI_NUMERICHOST;	hints.ai_family = remote_addr.addr.ss_family;	hints.ai_socktype = SOCK_STREAM;	hints.ai_protocol = 0;	hints.ai_addrlen = 0;	hints.ai_canonname = NULL;	hints.ai_addr = NULL;	hints.ai_next = NULL;	rc = pg_getaddrinfo_all(remote_addr_s, ident_port, &hints, &ident_serv);	if (rc || !ident_serv)	{		if (ident_serv)			pg_freeaddrinfo_all(hints.ai_family, ident_serv);		return false;			/* we don't expect this to happen */	}	hints.ai_flags = AI_NUMERICHOST;	hints.ai_family = local_addr.addr.ss_family;	hints.ai_socktype = SOCK_STREAM;	hints.ai_protocol = 0;	hints.ai_addrlen = 0;	hints.ai_canonname = NULL;	hints.ai_addr = NULL;	hints.ai_next = NULL;	rc = pg_getaddrinfo_all(local_addr_s, NULL, &hints, &la);	if (rc || !la)	{		if (la)			pg_freeaddrinfo_all(hints.ai_family, la);		return false;			/* we don't expect this to happen */	}	sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype,					 ident_serv->ai_protocol);	if (sock_fd < 0)	{		ereport(LOG,				(errcode_for_socket_access(),				 errmsg("could not create socket for Ident connection: %m")));		ident_return = false;		goto ident_inet_done;	}	/*	 * Bind to the address which the client originally contacted, otherwise	 * the ident server won't be able to match up the right connection. This	 * is necessary if the PostgreSQL server is running on an IP alias.	 */	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;	}	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;	}	/* 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);	if (rc < 0)	{		ereport(LOG,				(errcode_for_socket_access(),				 errmsg("could not send query to Ident server at address \"%s\", port %s: %m",						remote_addr_s, ident_port)));		ident_return = false;		goto ident_inet_done;	}	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)));ident_inet_done:	if (sock_fd >= 0)		closesocket(sock_fd);	pg_freeaddrinfo_all(remote_addr.addr.ss_family, ident_serv);	pg_freeaddrinfo_all(local_addr.addr.ss_family, la);	return ident_return;}/* *	Ask kernel about the credentials of the connecting process and *	determine the symbolic name of the corresponding user. * *	Returns either true and the username put into "ident_user", *	or false if we were unable to determine the username. */#ifdef HAVE_UNIX_SOCKETSstatic boolident_unix(int sock, char *ident_user){#if defined(HAVE_GETPEEREID)	/* OpenBSD style:  */	uid_t		uid;	gid_t		gid;	struct passwd *pass;	errno = 0;	if (getpeereid(sock, &uid, &gid) != 0)	{		/* We didn't get a valid credentials struct. */		ereport(LOG,				(errcode_for_socket_access(),				 errmsg("could not get peer credentials: %m")));		return false;	}	pass = getpwuid(uid);	if (pass == NULL)	{		ereport(LOG,				(errmsg("local user with ID %d does not exist",						(int) uid)));		return false;	}	StrNCpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);	return true;#elif defined(SO_PEERCRED)	/* Linux style: use getsockopt(SO_PEERCRED) */	struct ucred peercred;	ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);	struct passwd *pass;	errno = 0;	if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 ||		so_len != sizeof(peercred))	{		/* We didn't get a valid credentials struct. */		ereport(LOG,				(errcode_for_socket_access(),				 errmsg("could not get peer credentials: %m")));		return false;	}	pass = getpwuid(peercred.uid);	if (pass == NULL)	{		ereport(LOG,				(errmsg("local user with ID %d does not exist",						(int) peercred.uid)));		return false;	}	StrNCpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);	return true;#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))	struct msghdr msg;/* Credentials structure */#if defined(HAVE_STRUCT_CMSGCRED)	typedef struct cmsgcred Cred;#define cruid cmcred_uid#elif defined(HAVE_STRUCT_FCRED)	typedef struct fcred Cred;#define cruid fc_uid#elif defined(HAVE_STRUCT_SOCKCRED)	typedef struct sockcred Cred;#define cruid sc_uid#endif	Cred	   *cred;	/* Compute size without padding */	char		cmsgmem[ALIGN(sizeof(struct cmsghdr)) + ALIGN(sizeof(Cred))];	/* for NetBSD */	/* Point to start of first structure */	struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;	struct iovec iov;	char		buf;	struct passwd *pw;	memset(&msg, 0, sizeof(msg));	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	msg.msg_control = (char *) cmsg;	msg.msg_controllen = sizeof(cmsgmem);	memset(cmsg, 0, sizeof(cmsgmem));	/*	 * The one character which is received here is not meaningful; its	 * purposes is only to make sure that recvmsg() blocks long enough for the	 * other side to send its credentials.	 */	iov.iov_base = &buf;	iov.iov_len = 1;	if (recvmsg(sock, &msg, 0) < 0 ||		cmsg->cmsg_len < sizeof(cmsgmem) ||		cmsg->cmsg_type != SCM_CREDS)	{		ereport(LOG,				(errcode_for_socket_access(),				 errmsg("could not get peer credentials: %m")));		return false;	}	cred = (Cred *) CMSG_DATA(cmsg);	pw = getpwuid(cred->cruid);	if (pw == NULL)	{		ereport(LOG,				(errmsg("local user with ID %d does not exist",						(int) cred->cruid)));		return false;	}	StrNCpy(ident_user, pw->pw_name, IDENT_USERNAME_MAX + 1);	return true;#else	ereport(LOG,			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),			 errmsg("Ident authentication is not supported on local connections on this platform")));	return false;#endif}#endif   /* HAVE_UNIX_SOCKETS *//* *	Determine the username of the initiator of the connection described *	by "port".	Then look in the usermap file under the usermap *	port->auth_arg and see if that user is equivalent to Postgres user *	port->user. * *	Return STATUS_OK if yes, STATUS_ERROR if no match (or couldn't get info). */intauthident(hbaPort *port){	char		ident_user[IDENT_USERNAME_MAX + 1];	switch (port->raddr.addr.ss_family)	{		case AF_INET:#ifdef	HAVE_IPV6		case AF_INET6:#endif			if (!ident_inet(port->raddr, port->laddr, ident_user))				return STATUS_ERROR;			break;#ifdef HAVE_UNIX_SOCKETS		case AF_UNIX:			if (!ident_unix(port->sock, ident_user))				return STATUS_ERROR;			break;#endif		default:			return STATUS_ERROR;	}	ereport(DEBUG2,			(errmsg("Ident protocol identifies remote user as \"%s\"",					ident_user)));	if (check_ident_usermap(port->auth_arg, port->user_name, ident_user))		return STATUS_OK;	else		return STATUS_ERROR;}/* *	Determine what authentication method should be used when accessing database *	"database" from frontend "raddr", user "user".	Return the method and *	an optional argument (stored in fields of *port), and STATUS_OK. * *	Note that STATUS_ERROR indicates a problem with the hba config file. *	If the file is OK but does not contain any entry matching the request, *	we return STATUS_OK and method = uaReject. */inthba_getauthmethod(hbaPort *port){	if (check_hba(port))		return STATUS_OK;	else		return STATUS_ERROR;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -