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

📄 hba.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * 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). * *	$Id: hba.c,v 1.43 1999/05/25 16:08:59 momjian Exp $ * *------------------------------------------------------------------------- */#include <stdio.h>#include <string.h>#include <errno.h>#include <pwd.h>#include <sys/types.h>#include <fcntl.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <postgres.h>#include <miscadmin.h>#include <libpq/libpq.h>#include <libpq/pqcomm.h>#include <libpq/hba.h>#include <port/inet_aton.h>		/* For inet_aton() */#include <storage/fd.h>/* Some standard C libraries, including GNU, have an isblank() function.   Others, including Solaris, do not.  So we have our own.*/static boolisblank(const char c){	return c == ' ' || c == 9 /* tab */ ;}static voidnext_token(FILE *fp, char *buf, const int bufsz){/*--------------------------------------------------------------------------  Grab one token out of fp.  Tokens are strings of non-blank  characters bounded by blank characters, beginning of line, and end  of line.	Blank means space or tab.  Return the token as *buf.  Leave file positioned to character immediately after the token or  EOF, whichever comes first.  If no more tokens on line, return null  string as *buf and position file to beginning of next line or EOF,  whichever comes first.--------------------------------------------------------------------------*/	int			c;	char	   *eb = buf + (bufsz - 1);	/* Move over inital token-delimiting blanks */	while (isblank(c = getc(fp)));	if (c != '\n')	{		/*		 * build a token in buf of next characters up to EOF, eol, or		 * blank.		 */		while (c != EOF && c != '\n' && !isblank(c))		{			if (buf < eb)				*buf++ = c;			c = getc(fp);			/*			 * Put back the char right after the token (putting back EOF			 * is ok)			 */		}		ungetc(c, fp);	}	*buf = '\0';}static voidread_through_eol(FILE *file){	int			c;	do		c = getc(file);	while (c != '\n' && c != EOF);}static voidread_hba_entry2(FILE *file, UserAuth *userauth_p, char *auth_arg,				bool *error_p){/*--------------------------------------------------------------------------  Read from file FILE the rest of a host record, after the mask field,  and return the interpretation of it as *userauth_p, auth_arg, and  *error_p.---------------------------------------------------------------------------*/	char		buf[MAX_TOKEN];	/* Get authentication type token. */	next_token(file, buf, sizeof(buf));	if (strcmp(buf, "trust") == 0)		*userauth_p = uaTrust;	else if (strcmp(buf, "ident") == 0)		*userauth_p = uaIdent;	else if (strcmp(buf, "password") == 0)		*userauth_p = uaPassword;	else if (strcmp(buf, "krb4") == 0)		*userauth_p = uaKrb4;	else if (strcmp(buf, "krb5") == 0)		*userauth_p = uaKrb5;	else if (strcmp(buf, "reject") == 0)		*userauth_p = uaReject;	else if (strcmp(buf, "crypt") == 0)		*userauth_p = uaCrypt;	else	{		*error_p = true;		if (buf[0] != '\0')			read_through_eol(file);	}	if (!*error_p)	{		/* Get the authentication argument token, if any */		next_token(file, buf, sizeof(buf));		if (buf[0] == '\0')			auth_arg[0] = '\0';		else		{			StrNCpy(auth_arg, buf, MAX_AUTH_ARG - 1);			next_token(file, buf, sizeof(buf));			if (buf[0] != '\0')			{				*error_p = true;				read_through_eol(file);			}		}	}}static voidprocess_hba_record(FILE *file, SockAddr *raddr, const char *user,				   const char *database, bool *matches_p, bool *error_p,				   UserAuth *userauth_p, char *auth_arg){/*---------------------------------------------------------------------------  Process the non-comment record in the config file that is next on the file.  See if it applies to a connection to a host with IP address "*raddr"  to a database named "*database".	If so, return *matches_p true  and *userauth_p and *auth_arg as the values from the entry.  If not, leave *matches_p as it was.  If the record has a syntax error,  return *error_p true, after issuing a message to stderr.	If no error,  leave *error_p as it was.---------------------------------------------------------------------------*/	char		db[MAX_TOKEN],				buf[MAX_TOKEN];	/* Read the record type field. */	next_token(file, buf, sizeof(buf));	if (buf[0] == '\0')		return;	/* Check the record type. */	if (strcmp(buf, "local") == 0)	{		/* Get the database. */		next_token(file, db, sizeof(db));		if (db[0] == '\0')			goto syntax;		/* Read the rest of the line. */		read_hba_entry2(file, userauth_p, auth_arg, error_p);		/*		 * For now, disallow methods that need AF_INET sockets to work.		 */		if (!*error_p &&			(*userauth_p == uaIdent ||			 *userauth_p == uaKrb4 ||			 *userauth_p == uaKrb5))			*error_p = true;		if (*error_p)			goto syntax;		/*		 * If this record isn't for our database, or this is the wrong		 * sort of connection, ignore it.		 */		if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0 &&		 (strcmp(db, "sameuser") != 0 || strcmp(database, user) != 0)) ||			raddr->sa.sa_family != AF_UNIX)			return;	}	else if (strcmp(buf, "host") == 0)	{		struct in_addr file_ip_addr,					mask;		/* Get the database. */		next_token(file, db, sizeof(db));		if (db[0] == '\0')			goto syntax;		/* Read the IP address field. */		next_token(file, buf, sizeof(buf));		if (buf[0] == '\0')			goto syntax;		/* Remember the IP address field and go get mask field. */		if (!inet_aton(buf, &file_ip_addr))		{			read_through_eol(file);			goto syntax;		}		/* Read the mask field. */		next_token(file, buf, sizeof(buf));		if (buf[0] == '\0')			goto syntax;		if (!inet_aton(buf, &mask))		{			read_through_eol(file);			goto syntax;		}		/*		 * This is the record we're looking for.  Read the rest of the		 * info from it.		 */		read_hba_entry2(file, userauth_p, auth_arg, error_p);		if (*error_p)			goto syntax;		/*		 * If this record isn't for our database, or this is the wrong		 * sort of connection, ignore it.		 */		if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0 &&		 (strcmp(db, "sameuser") != 0 || strcmp(database, user) != 0)) ||			raddr->sa.sa_family != AF_INET ||			((file_ip_addr.s_addr ^ raddr->in.sin_addr.s_addr) & mask.s_addr) != 0x0000)			return;	}	else	{		read_through_eol(file);		goto syntax;	}	*matches_p = true;	return;syntax:	snprintf(PQerrormsg, ERROR_MSG_LENGTH,			 "process_hba_record: invalid syntax in pg_hba.conf file\n");	fputs(PQerrormsg, stderr);	pqdebug("%s", PQerrormsg);	*error_p = true;}static voidprocess_open_config_file(FILE *file, SockAddr *raddr, const char *user,						 const char *database, bool *hba_ok_p,						 UserAuth *userauth_p, char *auth_arg){/*---------------------------------------------------------------------------  This function does the same thing as find_hba_entry, only with  the config file already open on stream descriptor "file".----------------------------------------------------------------------------*/	bool		found_entry = false;	/* found an applicable entry? */	bool		error = false;	/* found an erroneous entry? */	bool		eof = false;	/* end of hba file */	while (!eof && !found_entry && !error)	{		/* Process a line from the config file */		int			c = getc(file);		if (c == EOF)			eof = true;		else		{			ungetc(c, file);			if (c == '#')				read_through_eol(file);			else				process_hba_record(file, raddr, user, database,							 &found_entry, &error, userauth_p, auth_arg);		}	}	if (!error)	{		/* If no matching entry was found, synthesize 'reject' entry. */		if (!found_entry)			*userauth_p = uaReject;		*hba_ok_p = true;	}}static voidfind_hba_entry(SockAddr *raddr, const char *user, const char *database,			   bool *hba_ok_p, UserAuth *userauth_p, char *auth_arg){/* * Read the config file and find an entry that allows connection from * host "raddr", user "user", to database "database".  If found, * return *hba_ok_p = true and *userauth_p and *auth_arg representing * the contents of that entry.	If there is no matching entry, we * set *hba_ok_p = true, *userauth_p = uaReject. * * If the config file is unreadable or contains invalid syntax, we * issue a diagnostic message to stderr (ie, the postmaster log file) * and return without changing *hba_ok_p. * * 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. */	int			fd,				bufsize;	FILE	   *file;			/* The config file we have to read */	char	   *old_conf_file;	/* The name of old config file that better not exist. */	/* Fail if config file by old name exists. */	/* put together the full pathname to the old config file */	bufsize = (strlen(DataDir) + strlen(OLD_CONF_FILE) + 2) * sizeof(char);	old_conf_file = (char *) palloc(bufsize);	snprintf(old_conf_file, bufsize, "%s/%s", DataDir, OLD_CONF_FILE);#ifndef __CYGWIN32__	if ((fd = open(old_conf_file, O_RDONLY, 0)) != -1)#else	if ((fd = open(old_conf_file, O_RDONLY | O_BINARY, 0)) != -1)#endif	{		/* Old config file exists.	Tell this guy he needs to upgrade. */		close(fd);		snprintf(PQerrormsg, ERROR_MSG_LENGTH,		  "A file exists by the name used for host-based authentication "		   "in prior releases of Postgres (%s).  The name and format of "		   "the configuration file have changed, so this file should be "				 "converted.\n",				 old_conf_file);		fputs(PQerrormsg, stderr);		pqdebug("%s", PQerrormsg);	}	else	{		char	   *conf_file;	/* The name of the config file we have to								 * read */		/* 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)		{			/* The open of the config file failed.	*/			snprintf(PQerrormsg, ERROR_MSG_LENGTH,				 "find_hba_entry: Host-based authentication config file "				"does not exist or permissions are not setup correctly! "					 "Unable to open file \"%s\".\n",					 conf_file);			fputs(PQerrormsg, stderr);			pqdebug("%s", PQerrormsg);		}		else		{			process_open_config_file(file, raddr, user, database, hba_ok_p,									 userauth_p, auth_arg);			FreeFile(file);		}		pfree(conf_file);	}	pfree(old_conf_file);}static voidinterpret_ident_response(char *ident_response,						 bool *error_p, char *ident_username){/*----------------------------------------------------------------------------  Parse the string "*ident_response" as a response from a query to an Ident  server.  If it's a normal response indicating a username, return  *error_p == false and the username as *ident_username.  If it's anything  else, return *error_p == true and *ident_username undefined.----------------------------------------------------------------------------*/	char	   *cursor;			/* Cursor into *ident_response */	cursor = &ident_response[0];	/*	 * Ident's response, in the telnet tradition, should end in crlf	 * (\r\n).	 */	if (strlen(ident_response) < 2)		*error_p = true;	else if (ident_response[strlen(ident_response) - 2] != '\r')		*error_p = true;	else	{		while (*cursor != ':' && *cursor != '\r')			cursor++;			/* skip port field */		if (*cursor != ':')			*error_p = true;		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 (isblank(*cursor))				cursor++;		/* skip blanks */			i = 0;			while (*cursor != ':' && *cursor != '\r' && !isblank(*cursor)				   && i < sizeof(response_type) - 1)				response_type[i++] = *cursor++;			response_type[i] = '\0';			while (isblank(*cursor))				cursor++;		/* skip blanks */			if (strcmp(response_type, "USERID") != 0)				*error_p = true;			else			{				/*				 * It's a USERID response.  Good.  "cursor" should be				 * pointing to the colon that precedes the operating				 * system type.				 */				if (*cursor != ':')					*error_p = true;				else				{					cursor++;	/* Go over colon */					/* Skip over operating system field. */					while (*cursor != ':' && *cursor != '\r')						cursor++;					if (*cursor != ':')						*error_p = true;					else					{						int			i;	/* Index into *ident_username */						cursor++;		/* Go over colon */						while (isblank(*cursor))							cursor++;	/* skip blanks */						/* Rest of line is username.  Copy it over. */						i = 0;						while (*cursor != '\r' && i < IDENT_USERNAME_MAX)							ident_username[i++] = *cursor++;						ident_username[i] = '\0';						*error_p = false;					}				}			}		}	}}static voidident(const struct in_addr remote_ip_addr, const struct in_addr local_ip_addr,	  const ushort remote_port, const ushort local_port,	  bool *ident_failed, char *ident_username){/*--------------------------------------------------------------------------  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 username the  ident server gives as "*ident_username".  IP addresses and port numbers are in network byte order.  But iff we're unable to get the information from ident, return  *ident_failed == true (and *ident_username undefined).----------------------------------------------------------------------------*/	int			sock_fd,		/* File descriptor for socket on which we								 * talk to Ident */				rc;				/* Return code from a locally called								 * function */	sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);	if (sock_fd == -1)

⌨️ 快捷键说明

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