hba.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,584 行 · 第 1/3 页

C
1,584
字号
		else			*error_p = true;		line = lnext(line);	}	if (!*error_p)	{		/* Get the authentication argument token, if any */		if (line)		{			token = lfirst(line);			*auth_arg_p = pstrdup(token);			/* If there is more on the line, it is an error */			if (lnext(line))				*error_p = true;		}	}}/* *	Process one line from the hba config file. * *	See if it applies to a connection from a host with IP address port->raddr *	to a database named port->database.  If so, return *found_p true *	and fill in the auth arguments into the appropriate port fields. *	If not, leave *found_p as it was.  If the record has a syntax error, *	return *error_p true, after issuing a message to the log.  If no error, *	leave *error_p as it was. */static voidparse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p){	int			line_number;	char	   *token;	char	   *db;	char	   *user;	struct addrinfo *gai_result;	struct addrinfo hints;	int			ret;	struct sockaddr_storage addr;	struct sockaddr_storage mask;	char	   *cidr_slash;	Assert(line != NIL);	line_number = lfirsti(line);	line = lnext(line);	Assert(line != NIL);	/* Check the record type. */	token = lfirst(line);	if (strcmp(token, "local") == 0)	{		/* Get the database. */		line = lnext(line);		if (!line)			goto hba_syntax;		db = lfirst(line);		/* Get the user. */		line = lnext(line);		if (!line)			goto hba_syntax;		user = lfirst(line);		line = lnext(line);		if (!line)			goto hba_syntax;		/* Read the rest of the line. */		parse_hba_auth(line, &port->auth_method, &port->auth_arg, error_p);		if (*error_p)			goto hba_syntax;		/* Disallow auth methods that always need TCP/IP sockets to work */		if (port->auth_method == uaKrb4 ||			port->auth_method == uaKrb5)			goto hba_syntax;		/* Does not match if connection isn't AF_UNIX */		if (!IS_AF_UNIX(port->raddr.addr.ss_family))			return;	}	else if (strcmp(token, "host") == 0			 || strcmp(token, "hostssl") == 0			 || strcmp(token, "hostnossl") == 0)	{		if (token[4] == 's')	/* "hostssl" */		{#ifdef USE_SSL			/* Record does not match if we are not on an SSL connection */			if (!port->ssl)				return;			/* Placeholder to require specific SSL level, perhaps? */			/* Or a client certificate */			/* Since we were on SSL, proceed as with normal 'host' mode */#else			/* We don't accept this keyword at all if no SSL support */			goto hba_syntax;#endif		}#ifdef USE_SSL		else if (token[4] == 'n')		/* "hostnossl" */		{			/* Record does not match if we are on an SSL connection */			if (port->ssl)				return;		}#endif		/* Get the database. */		line = lnext(line);		if (!line)			goto hba_syntax;		db = lfirst(line);		/* Get the user. */		line = lnext(line);		if (!line)			goto hba_syntax;		user = lfirst(line);		/* Read the IP address field. (with or without CIDR netmask) */		line = lnext(line);		if (!line)			goto hba_syntax;		token = lfirst(line);		/* Check if it has a CIDR suffix and if so isolate it */		cidr_slash = strchr(token, '/');		if (cidr_slash)			*cidr_slash = '\0';		/* Get the IP address either way */		hints.ai_flags = AI_NUMERICHOST;		hints.ai_family = PF_UNSPEC;		hints.ai_socktype = 0;		hints.ai_protocol = 0;		hints.ai_addrlen = 0;		hints.ai_canonname = NULL;		hints.ai_addr = NULL;		hints.ai_next = NULL;		ret = getaddrinfo_all(token, NULL, &hints, &gai_result);		if (ret || !gai_result)		{			ereport(LOG,					(errcode(ERRCODE_CONFIG_FILE_ERROR),					 errmsg("invalid IP address \"%s\" in pg_hba.conf file: %s",							token, gai_strerror(ret))));			if (cidr_slash)				*cidr_slash = '/';			if (gai_result)				freeaddrinfo_all(hints.ai_family, gai_result);			goto hba_syntax;		}		if (cidr_slash)			*cidr_slash = '/';		memcpy(&addr, gai_result->ai_addr, gai_result->ai_addrlen);		freeaddrinfo_all(hints.ai_family, gai_result);		/* Get the netmask */		if (cidr_slash)		{			if (SockAddr_cidr_mask(&mask, cidr_slash + 1, addr.ss_family) < 0)				goto hba_syntax;		}		else		{			/* Read the mask field. */			line = lnext(line);			if (!line)				goto hba_syntax;			token = lfirst(line);			ret = getaddrinfo_all(token, NULL, &hints, &gai_result);			if (ret || !gai_result)			{				if (gai_result)					freeaddrinfo_all(hints.ai_family, gai_result);				goto hba_syntax;			}			memcpy(&mask, gai_result->ai_addr, gai_result->ai_addrlen);			freeaddrinfo_all(hints.ai_family, gai_result);			if (addr.ss_family != mask.ss_family)				goto hba_syntax;		}		if (addr.ss_family != port->raddr.addr.ss_family)		{			/*			 * Wrong address family.  We allow only one case: if the			 * file has IPv4 and the port is IPv6, promote the file			 * address to IPv6 and try to match that way.			 */#ifdef HAVE_IPV6			if (addr.ss_family == AF_INET &&				port->raddr.addr.ss_family == AF_INET6)			{				promote_v4_to_v6_addr(&addr);				promote_v4_to_v6_mask(&mask);			}			else#endif /* HAVE_IPV6 */			{				/* Line doesn't match client port, so ignore it. */				return;			}		}		/* Ignore line if client port is not in the matching addr range. */		if (!rangeSockAddr(&port->raddr.addr, &addr, &mask))			return;		/* Read the rest of the line. */		line = lnext(line);		if (!line)			goto hba_syntax;		parse_hba_auth(line, &port->auth_method, &port->auth_arg, error_p);		if (*error_p)			goto hba_syntax;	}	else		goto hba_syntax;	if (!check_db(port->database_name, port->user_name, db))		return;	if (!check_user(port->user_name, user))		return;	/* Success */	*found_p = true;	return;hba_syntax:	if (line)		ereport(LOG,				(errcode(ERRCODE_CONFIG_FILE_ERROR),				 errmsg("invalid entry in pg_hba.conf file at line %d, token \"%s\"",						line_number, (const char *) lfirst(line))));	else		ereport(LOG,				(errcode(ERRCODE_CONFIG_FILE_ERROR),			errmsg("missing field in pg_hba.conf file at end of line %d",				   line_number)));	*error_p = true;}/* *	Scan the (pre-parsed) hba file line by line, looking for a match *	to the port's connection request. */static boolcheck_hba(hbaPort *port){	bool		found_entry = false;	bool		error = false;	List	   *line;	foreach(line, hba_lines)	{		parse_hba(lfirst(line), port, &found_entry, &error);		if (found_entry || error)			break;	}	if (!error)	{		/* If no matching entry was found, synthesize 'reject' entry. */		if (!found_entry)			port->auth_method = uaReject;		return true;	}	else		return false;}/* * Open the group file if possible (return NULL if not) */static FILE *group_openfile(void){	char	   *filename;	FILE	   *groupfile;	filename = group_getfilename();	groupfile = AllocateFile(filename, "r");	if (groupfile == NULL && errno != ENOENT)		ereport(LOG,				(errcode_for_file_access(),				 errmsg("could not open file \"%s\": %m", filename)));	pfree(filename);	return groupfile;}/* * Open the password file if possible (return NULL if not) */static FILE *user_openfile(void){	char	   *filename;	FILE	   *pwdfile;	filename = user_getfilename();	pwdfile = AllocateFile(filename, "r");	if (pwdfile == NULL && errno != ENOENT)		ereport(LOG,				(errcode_for_file_access(),				 errmsg("could not open file \"%s\": %m", filename)));	pfree(filename);	return pwdfile;}/* *	 Load group/user name mapping file */voidload_group(void){	FILE	   *group_file;	List	   *line;	/* Discard any old data */	if (group_lines)		free_lines(&group_lines);	if (group_sorted)		pfree(group_sorted);	group_sorted = NULL;	group_length = 0;	group_file = group_openfile();	if (!group_file)		return;	group_lines = tokenize_file(group_file);	FreeFile(group_file);	/* create sorted lines for binary searching */	group_length = length(group_lines);	if (group_length)	{		int			i = 0;		group_sorted = palloc(group_length * sizeof(List *));		foreach(line, group_lines)			group_sorted[i++] = lfirst(line);		qsort((void *) group_sorted,			  group_length,			  sizeof(List *),			  user_group_qsort_cmp);	}}/* *	 Load user/password mapping file */voidload_user(void){	FILE	   *user_file;	List	   *line;	/* Discard any old data */	if (user_lines)		free_lines(&user_lines);	if (user_sorted)		pfree(user_sorted);	user_sorted = NULL;	user_length = 0;	user_file = user_openfile();	if (!user_file)		return;	user_lines = tokenize_file(user_file);	FreeFile(user_file);	/* create sorted lines for binary searching */	user_length = length(user_lines);	if (user_length)	{		int			i = 0;		user_sorted = palloc(user_length * sizeof(List *));		foreach(line, user_lines)			user_sorted[i++] = lfirst(line);		qsort((void *) user_sorted,			  user_length,			  sizeof(List *),			  user_group_qsort_cmp);	}}/* * Read the config file and create a List of Lists of tokens in the file. * If we find a file by the old name of the config file (pg_hba), we issue * an error message because it probably needs to be converted.	He didn't * follow directions and just installed his old hba file in the new database * system. */voidload_hba(void){	int			bufsize;	FILE	   *file;			/* The config file we have to read */	char	   *conf_file;		/* The name of the config file */	if (hba_lines)		free_lines(&hba_lines);	/* Put together the full pathname to the config file. */	bufsize = (strlen(DataDir) + strlen(CONF_FILE) + 2) * sizeof(char);	conf_file = (char *) palloc(bufsize);	snprintf(conf_file, bufsize, "%s/%s", DataDir, CONF_FILE);	file = AllocateFile(conf_file, "r");	if (file == NULL)		ereport(FATAL,				(errcode_for_file_access(),				 errmsg("could not open configuration file \"%s\": %m",						conf_file)));	hba_lines = tokenize_file(file);	FreeFile(file);	pfree(conf_file);}/* *	Process one line from the ident config file. * *	Take the line and compare it to the needed map, pg_user and ident_user. *	*found_p and *error_p are set according to our results. */static voidparse_ident_usermap(List *line, const char *usermap_name, const char *pg_user,					const char *ident_user, bool *found_p, bool *error_p){	int			line_number;	char	   *token;	char	   *file_map;	char	   *file_pguser;	char	   *file_ident_user;	*found_p = false;	*error_p = false;	Assert(line != NIL);	line_number = lfirsti(line);	line = lnext(line);	Assert(line != NIL);	/* Get the map token (must exist) */	token = lfirst(line);	file_map = token;	/* Get the ident user token (must be provided) */	line = lnext(line);	if (!line)		goto ident_syntax;	token = lfirst(line);	file_ident_user = token;	/* Get the PG username token */	line = lnext(line);	if (!line)		goto ident_syntax;	token = lfirst(line);	file_pguser = token;	/* Match? */	if (strcmp(file_map, usermap_name) == 0 &&		strcmp(file_pguser, pg_user) == 0 &&		strcmp(file_ident_user, ident_user) == 0)		*found_p = true;	return;ident_syntax:	if (line)		ereport(LOG,				(errcode(ERRCODE_CONFIG_FILE_ERROR),				 errmsg("invalid entry in pg_ident.conf file at line %d, token \"%s\"",						line_number, (const char *) lfirst(line))));	else		ereport(LOG,				(errcode(ERRCODE_CONFIG_FILE_ERROR),		  errmsg("missing entry in pg_ident.conf file at end of line %d",				 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 "pguser" according to usermap "usermap_name". * *	Special case: For usermap "sameuser", don't look in the usermap *	file.  That's an implied map where "pguser" must be identical to *	"ident_user" in order to be authorized.

⌨️ 快捷键说明

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