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

📄 hba.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * hba.c *	  Routines to handle host based authentication (that's the scheme *	  wherein you authenticate a user by seeing what IP address the system *	  says he comes from and possibly using ident). * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.149 2005/10/17 16:24:19 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <ctype.h>#include <pwd.h>#include <fcntl.h>#include <sys/param.h>#include <sys/socket.h>#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)#include <sys/uio.h>#include <sys/ucred.h>#endif#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include "libpq/crypt.h"#include "libpq/libpq.h"#include "miscadmin.h"#include "nodes/pg_list.h"#include "storage/fd.h"#include "utils/flatfiles.h"#include "utils/guc.h"#define atooid(x)  ((Oid) strtoul((x), NULL, 10))#define atoxid(x)  ((TransactionId) strtoul((x), NULL, 10))/* Max size of username ident server can return */#define IDENT_USERNAME_MAX 512/* Standard TCP port number for Ident service.	Assigned by IANA */#define IDENT_PORT 113/* This is used to separate values in multi-valued column strings */#define MULTI_VALUE_SEP "\001"#define MAX_TOKEN	256/* * These variables hold the pre-parsed contents of the hba and ident * configuration files, as well as the flat auth file. * Each is a list of sublists, one sublist for * each (non-empty, non-comment) line of the file.	Each sublist's * first item is an integer line number (so we can give somewhat-useful * location info in error messages).  Remaining items are palloc'd strings, * one string per token on the line.  Note there will always be at least * one token, since blank lines are not entered in the data structure. *//* pre-parsed content of HBA config file and corresponding line #s */static List *hba_lines = NIL;static List *hba_line_nums = NIL;/* pre-parsed content of ident usermap file and corresponding line #s */static List *ident_lines = NIL;static List *ident_line_nums = NIL;/* pre-parsed content of flat auth file and corresponding line #s */static List *role_lines = NIL;static List *role_line_nums = NIL;/* sorted entries so we can do binary search lookups */static List **role_sorted = NULL;		/* sorted role list, for bsearch() */static int	role_length;static void tokenize_file(const char *filename, FILE *file,			  List **lines, List **line_nums);static char *tokenize_inc_file(const char *outer_filename,				  const char *inc_filename);/* * isblank() exists in the ISO C99 spec, but it's not very portable yet, * so provide our own version. */static boolpg_isblank(const char c){	return c == ' ' || c == '\t' || c == '\r';}/* * Grab one token out of fp. Tokens are strings of non-blank * characters bounded by blank characters, commas, beginning of line, and * end of line. Blank means space or tab. Tokens can be delimited by * double quotes (and usually are, in current usage). * * The token, if any, is returned at *buf (a buffer of size bufsz). * * If successful: store null-terminated token at *buf and return TRUE. * If no more tokens on line: set *buf = '\0' and return FALSE. * * Leave file positioned at the character immediately after the token or EOF, * whichever comes first. If no more tokens on line, position the file to the * beginning of the next line or EOF, whichever comes first. * * Handle comments. Treat unquoted keywords that might be role names or * database names specially, by appending a newline to them. */static boolnext_token(FILE *fp, char *buf, int bufsz){	int			c;	char	   *start_buf = buf;	char	   *end_buf = buf + (bufsz - 2);	bool		in_quote = false;	bool		was_quote = false;	bool		saw_quote = false;	Assert(end_buf > start_buf);	/* Move over initial whitespace and commas */	while ((c = getc(fp)) != EOF && (pg_isblank(c) || c == ','))		;	if (c == EOF || c == '\n')	{		*buf = '\0';		return false;	}	/*	 * Build a token in buf of next characters up to EOF, EOL, unquoted comma,	 * or unquoted whitespace.	 */	while (c != EOF && c != '\n' &&		   (!pg_isblank(c) || in_quote == true))	{		/* skip comments to EOL */		if (c == '#' && !in_quote)		{			while ((c = getc(fp)) != EOF && c != '\n')				;			/* If only comment, consume EOL too; return EOL */			if (c != EOF && buf == start_buf)				c = getc(fp);			break;		}		if (buf >= end_buf)		{			*buf = '\0';			ereport(LOG,					(errcode(ERRCODE_CONFIG_FILE_ERROR),			   errmsg("authentication file token too long, skipping: \"%s\"",					  start_buf)));			/* Discard remainder of line */			while ((c = getc(fp)) != EOF && c != '\n')				;			break;		}		if (c != '"' || (c == '"' && was_quote))			*buf++ = c;		/* We pass back the comma so the caller knows there is more */		if ((pg_isblank(c) || c == ',') && !in_quote)			break;		/* Literal double-quote is two double-quotes */		if (in_quote && c == '"')			was_quote = !was_quote;		else			was_quote = false;		if (c == '"')		{			in_quote = !in_quote;			saw_quote = true;		}		c = getc(fp);	}	/*	 * Put back the char right after the token (critical in case it is EOL,	 * since we need to detect end-of-line at next call).	 */	if (c != EOF)		ungetc(c, fp);	*buf = '\0';	if (!saw_quote &&		(strcmp(start_buf, "all") == 0 ||		 strcmp(start_buf, "sameuser") == 0 ||		 strcmp(start_buf, "samegroup") == 0 ||		 strcmp(start_buf, "samerole") == 0))	{		/* append newline to a magical keyword */		*buf++ = '\n';		*buf = '\0';	}	return (saw_quote || buf > start_buf);}/* *	 Tokenize file and handle file inclusion and comma lists. We have *	 to  break	apart  the	commas	to	expand	any  file names then *	 reconstruct with commas. * * The result is a palloc'd string, or NULL if we have reached EOL. */static char *next_token_expand(const char *filename, FILE *file){	char		buf[MAX_TOKEN];	char	   *comma_str = pstrdup("");	bool		got_something = false;	bool		trailing_comma;	char	   *incbuf;	int			needed;	do	{		if (!next_token(file, buf, sizeof(buf)))			break;		got_something = true;		if (strlen(buf) > 0 && buf[strlen(buf) - 1] == ',')		{			trailing_comma = true;			buf[strlen(buf) - 1] = '\0';		}		else			trailing_comma = false;		/* Is this referencing a file? */		if (buf[0] == '@')			incbuf = tokenize_inc_file(filename, buf + 1);		else			incbuf = pstrdup(buf);		needed = strlen(comma_str) + strlen(incbuf) + 1;		if (trailing_comma)			needed++;		comma_str = repalloc(comma_str, needed);		strcat(comma_str, incbuf);		if (trailing_comma)			strcat(comma_str, MULTI_VALUE_SEP);		pfree(incbuf);	} while (trailing_comma);	if (!got_something)	{		pfree(comma_str);		return NULL;	}	return comma_str;}/* * Free memory used by lines/tokens (i.e., structure built by tokenize_file) */static voidfree_lines(List **lines, List **line_nums){	/*	 * Either both must be non-NULL, or both must be NULL	 */	Assert((*lines != NIL && *line_nums != NIL) ||		   (*lines == NIL && *line_nums == NIL));	if (*lines)	{		/*		 * "lines" is a list of lists; each of those sublists consists of		 * palloc'ed tokens, so we want to free each pointed-to token in a		 * sublist, followed by the sublist itself, and finally the whole		 * list.		 */		ListCell   *line;		foreach(line, *lines)		{			List	   *ln = lfirst(line);			ListCell   *token;			foreach(token, ln)				pfree(lfirst(token));			/* free the sublist structure itself */			list_free(ln);		}		/* free the list structure itself */		list_free(*lines);		/* clear the static variable */		*lines = NIL;	}	if (*line_nums)	{		list_free(*line_nums);		*line_nums = NIL;	}}static char *tokenize_inc_file(const char *outer_filename,				  const char *inc_filename){	char	   *inc_fullname;	FILE	   *inc_file;	List	   *inc_lines;	List	   *inc_line_nums;	ListCell   *line;	char	   *comma_str;	if (is_absolute_path(inc_filename))	{		/* absolute path is taken as-is */		inc_fullname = pstrdup(inc_filename);	}	else	{		/* relative path is relative to dir of calling file */		inc_fullname = (char *) palloc(strlen(outer_filename) + 1 +									   strlen(inc_filename) + 1);		strcpy(inc_fullname, outer_filename);		get_parent_directory(inc_fullname);		join_path_components(inc_fullname, inc_fullname, inc_filename);		canonicalize_path(inc_fullname);	}	inc_file = AllocateFile(inc_fullname, "r");	if (inc_file == NULL)	{		ereport(LOG,				(errcode_for_file_access(),				 errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",						inc_filename, inc_fullname)));		pfree(inc_fullname);		/* return single space, it matches nothing */		return pstrdup(" ");	}	/* There is possible recursion here if the file contains @ */	tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums);	FreeFile(inc_file);	pfree(inc_fullname);	/* Create comma-separated string from List */	comma_str = pstrdup("");	foreach(line, inc_lines)	{		List	   *token_list = (List *) lfirst(line);		ListCell   *token;		foreach(token, token_list)		{			int			oldlen = strlen(comma_str);			int			needed;			needed = oldlen + strlen(lfirst(token)) + 1;			if (oldlen > 0)				needed++;			comma_str = repalloc(comma_str, needed);			if (oldlen > 0)				strcat(comma_str, MULTI_VALUE_SEP);			strcat(comma_str, lfirst(token));		}	}	free_lines(&inc_lines, &inc_line_nums);	/* if file is empty, return single space rather than empty string */	if (strlen(comma_str) == 0)	{		pfree(comma_str);		return pstrdup(" ");	}	return comma_str;}/* * Tokenize the given file, storing the resulting data into two lists: * a list of sublists, each sublist containing the tokens in a line of * the file, and a list of line numbers. * * filename must be the absolute path to the target file. */static voidtokenize_file(const char *filename, FILE *file,			  List **lines, List **line_nums){	List	   *current_line = NIL;	int			line_number = 1;	char	   *buf;	*lines = *line_nums = NIL;	while (!feof(file))	{		buf = next_token_expand(filename, file);		/* add token to list, unless we are at EOL or comment start */		if (buf)		{			if (current_line == NIL)			{				/* make a new line List, record its line number */				current_line = lappend(current_line, buf);				*lines = lappend(*lines, current_line);				*line_nums = lappend_int(*line_nums, line_number);			}			else			{				/* append token to current line's list */				current_line = lappend(current_line, buf);			}		}		else		{			/* we are at real or logical EOL, so force a new line List */			current_line = NIL;			/* Advance line number whenever we reach EOL */			line_number++;		}	}}/* * Compare two lines based on their role/member names. * * Used for bsearch() lookup. */static introle_bsearch_cmp(const void *role, const void *list){	char	   *role2 = linitial(*(List **) list);	return strcmp(role, role2);}/* * Lookup a role name in the pg_auth file */List	  **get_role_line(const char *role){	/* On some versions of Solaris, bsearch of zero items dumps core */	if (role_length == 0)		return NULL;	return (List **) bsearch((void *) role,							 (void *) role_sorted,							 role_length,							 sizeof(List *),							 role_bsearch_cmp);}/* * Does user belong to role? * * user is always the name given as the attempted login identifier. * We check to see if it is a member of the specified role name. */static boolis_member(const char *user, const char *role){	List	  **line;	ListCell   *line_item;	if ((line = get_role_line(user)) == NULL)		return false;			/* if user not exist, say "no" */	/* A user always belongs to its own role */	if (strcmp(user, role) == 0)		return true;	/*	 * skip over the role name, password, valuntil, examine all the membership	 * entries	 */	if (list_length(*line) < 4)		return false;	for_each_cell(line_item, lnext(lnext(lnext(list_head(*line)))))	{		if (strcmp((char *) lfirst(line_item), role) == 0)			return true;	}	return false;}/* * Check comma-separated list for a match to role, allowing group names. * * NB: param_str is destructively modified!  In current usage, this is * okay only because this code is run after forking off from the postmaster, * and so it doesn't matter that we clobber the stored hba info. */static boolcheck_role(const char *role, char *param_str){	char	   *tok;	for (tok = strtok(param_str, MULTI_VALUE_SEP);		 tok != NULL;		 tok = strtok(NULL, MULTI_VALUE_SEP))	{		if (tok[0] == '+')		{			if (is_member(role, tok + 1))				return true;		}		else if (strcmp(tok, role) == 0 ||				 strcmp(tok, "all\n") == 0)			return true;	}	return false;}/* * Check to see if db/role combination matches param string. * * NB: param_str is destructively modified!  In current usage, this is * okay only because this code is run after forking off from the postmaster, * and so it doesn't matter that we clobber the stored hba info. */static bool

⌨️ 快捷键说明

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