Index: src/backend/libpq/auth.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/libpq/auth.c,v
retrieving revision 1.167
diff -c -r1.167 auth.c
*** src/backend/libpq/auth.c	1 Aug 2008 11:41:12 -0000	1.167
--- src/backend/libpq/auth.c	16 Aug 2008 15:44:20 -0000
***************
*** 211,217 ****
  	if (status == STATUS_EOF)
  		proc_exit(0);
  
! 	switch (port->auth_method)
  	{
  		case uaReject:
  			errstr = gettext_noop("authentication failed for user \"%s\": host rejected");
--- 211,217 ----
  	if (status == STATUS_EOF)
  		proc_exit(0);
  
! 	switch (port->hba->auth_method)
  	{
  		case uaReject:
  			errstr = gettext_noop("authentication failed for user \"%s\": host rejected");
***************
*** 279,285 ****
  				 errmsg("missing or erroneous pg_hba.conf file"),
  				 errhint("See server log for details.")));
  
! 	switch (port->auth_method)
  	{
  		case uaReject:
  
--- 279,285 ----
  				 errmsg("missing or erroneous pg_hba.conf file"),
  				 errhint("See server log for details.")));
  
! 	switch (port->hba->auth_method)
  	{
  		case uaReject:
  
***************
*** 1761,1767 ****
  /*
   *	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).
--- 1761,1767 ----
  /*
   *	Determine the username of the initiator of the connection described
   *	by "port".	Then look in the usermap file under the usermap
!  *	port->hba->usermap 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).
***************
*** 1799,1805 ****
  			(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;
--- 1799,1805 ----
  			(errmsg("Ident protocol identifies remote user as \"%s\"",
  					ident_user)));
  
! 	if (check_ident_usermap(port->hba->usermap, port->user_name, ident_user))
  		return STATUS_OK;
  	else
  		return STATUS_ERROR;
Index: src/backend/libpq/crypt.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/libpq/crypt.c,v
retrieving revision 1.74
diff -c -r1.74 crypt.c
*** src/backend/libpq/crypt.c	1 Jan 2008 19:45:49 -0000	1.74
--- src/backend/libpq/crypt.c	16 Aug 2008 15:44:20 -0000
***************
*** 54,60 ****
  		return STATUS_ERROR;
  
  	/* We can't do crypt with MD5 passwords */
! 	if (isMD5(shadow_pass) && port->auth_method == uaCrypt)
  	{
  		ereport(LOG,
  				(errmsg("cannot use authentication method \"crypt\" because password is MD5-encrypted")));
--- 54,60 ----
  		return STATUS_ERROR;
  
  	/* We can't do crypt with MD5 passwords */
! 	if (isMD5(shadow_pass) && port->hba->auth_method == uaCrypt)
  	{
  		ereport(LOG,
  				(errmsg("cannot use authentication method \"crypt\" because password is MD5-encrypted")));
***************
*** 65,71 ****
  	 * Compare with the encrypted or plain password depending on the
  	 * authentication method being used for this connection.
  	 */
! 	switch (port->auth_method)
  	{
  		case uaMD5:
  			crypt_pwd = palloc(MD5_PASSWD_LEN + 1);
--- 65,71 ----
  	 * Compare with the encrypted or plain password depending on the
  	 * authentication method being used for this connection.
  	 */
! 	switch (port->hba->auth_method)
  	{
  		case uaMD5:
  			crypt_pwd = palloc(MD5_PASSWD_LEN + 1);
***************
*** 155,161 ****
  		}
  	}
  
! 	if (port->auth_method == uaMD5)
  		pfree(crypt_pwd);
  	if (crypt_client_pass != client_pass)
  		pfree(crypt_client_pass);
--- 155,161 ----
  		}
  	}
  
! 	if (port->hba->auth_method == uaMD5)
  		pfree(crypt_pwd);
  	if (crypt_client_pass != client_pass)
  		pfree(crypt_client_pass);
Index: src/backend/libpq/hba.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/libpq/hba.c,v
retrieving revision 1.166
diff -c -r1.166 hba.c
*** src/backend/libpq/hba.c	1 Aug 2008 09:09:49 -0000	1.166
--- src/backend/libpq/hba.c	16 Aug 2008 15:44:20 -0000
***************
*** 41,48 ****
  
  #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
--- 41,51 ----
  
  #define MAX_TOKEN	256
  
+ /* pre-parsed content of HBA config file */
+ static List *parsed_hba_lines = NIL;
+ 
  /*
!  * These variables hold the pre-parsed contents of the 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
***************
*** 52,61 ****
   * 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;
--- 55,60 ----
***************
*** 566,696 ****
  
  
  /*
!  *	Scan the rest of a host record (after the mask field)
!  *	and return the interpretation of it as *userauth_p, *auth_arg_p, and
!  *	*error_p.  *line_item points to the next token of the line, and is
!  *	advanced over successfully-read tokens.
   */
! static void
! parse_hba_auth(ListCell **line_item, UserAuth *userauth_p,
! 			   char **auth_arg_p, bool *error_p)
! {
! 	char	   *token;
! 
! 	*auth_arg_p = NULL;
! 
! 	if (!*line_item)
! 	{
! 		*error_p = true;
! 		return;
! 	}
! 
! 	token = lfirst(*line_item);
! 	if (strcmp(token, "trust") == 0)
! 		*userauth_p = uaTrust;
! 	else if (strcmp(token, "ident") == 0)
! 		*userauth_p = uaIdent;
! 	else if (strcmp(token, "password") == 0)
! 		*userauth_p = uaPassword;
! 	else if (strcmp(token, "krb5") == 0)
! 		*userauth_p = uaKrb5;
! 	else if (strcmp(token, "gss") == 0)
! 		*userauth_p = uaGSS;
! 	else if (strcmp(token, "sspi") == 0)
! 		*userauth_p = uaSSPI;
! 	else if (strcmp(token, "reject") == 0)
! 		*userauth_p = uaReject;
! 	else if (strcmp(token, "md5") == 0)
! 		*userauth_p = uaMD5;
! 	else if (strcmp(token, "crypt") == 0)
! 		*userauth_p = uaCrypt;
! #ifdef USE_PAM
! 	else if (strcmp(token, "pam") == 0)
! 		*userauth_p = uaPAM;
! #endif
! #ifdef USE_LDAP
! 	else if (strcmp(token, "ldap") == 0)
! 		*userauth_p = uaLDAP;
! #endif
! 	else
! 	{
! 		*error_p = true;
! 		return;
! 	}
! 	*line_item = lnext(*line_item);
! 
! 	/* Get the authentication argument token, if any */
! 	if (*line_item)
! 	{
! 		token = lfirst(*line_item);
! 		*auth_arg_p = pstrdup(token);
! 		*line_item = lnext(*line_item);
! 		/* If there is more on the line, it is an error */
! 		if (*line_item)
! 			*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 void
! parse_hba(List *line, int line_num, hbaPort *port,
! 		  bool *found_p, bool *error_p)
  {
  	char	   *token;
- 	char	   *db;
- 	char	   *role;
  	struct addrinfo *gai_result;
  	struct addrinfo hints;
  	int			ret;
- 	struct sockaddr_storage addr;
- 	struct sockaddr_storage mask;
  	char	   *cidr_slash;
  	ListCell   *line_item;
  
  	line_item = list_head(line);
  	/* Check the record type. */
  	token = lfirst(line_item);
  	if (strcmp(token, "local") == 0)
  	{
! 		/* Get the database. */
! 		line_item = lnext(line_item);
! 		if (!line_item)
! 			goto hba_syntax;
! 		db = lfirst(line_item);
! 
! 		/* Get the role. */
! 		line_item = lnext(line_item);
! 		if (!line_item)
! 			goto hba_syntax;
! 		role = lfirst(line_item);
! 
! 		line_item = lnext(line_item);
! 		if (!line_item)
! 			goto hba_syntax;
! 
! 		/* Read the rest of the line. */
! 		parse_hba_auth(&line_item, &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 == 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
--- 565,593 ----
  
  
  /*
!  * Parse one line in the hba config file and store the result in
!  * a HbaLine structure.
   */
! static bool
! parse_hba_line(List *line, int line_num, HbaLine *parsedline)
  {
  	char	   *token;
  	struct addrinfo *gai_result;
  	struct addrinfo hints;
  	int			ret;
  	char	   *cidr_slash;
+ 	char	   *unsupauth;
  	ListCell   *line_item;
  
  	line_item = list_head(line);
+ 
+ 	parsedline->linenumber = line_num;
+ 
  	/* Check the record type. */
  	token = lfirst(line_item);
  	if (strcmp(token, "local") == 0)
  	{
! 		parsedline->conntype = ctLocal;
  	}
  	else if (strcmp(token, "host") == 0
  			 || strcmp(token, "hostssl") == 0
***************
*** 700,713 ****
  		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;
--- 597,603 ----
  		if (token[4] == 's')	/* "hostssl" */
  		{
  #ifdef USE_SSL
! 			parsedline->conntype = ctHostSSL;
  #else
  			/* We don't accept this keyword at all if no SSL support */
  			goto hba_syntax;
***************
*** 716,744 ****
  #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_item = lnext(line_item);
! 		if (!line_item)
! 			goto hba_syntax;
! 		db = lfirst(line_item);
  
! 		/* Get the role. */
! 		line_item = lnext(line_item);
! 		if (!line_item)
! 			goto hba_syntax;
! 		role = lfirst(line_item);
  
  		/* Read the IP address field. (with or without CIDR netmask) */
  		line_item = lnext(line_item);
  		if (!line_item)
  			goto hba_syntax;
! 		token = lfirst(line_item);
  
  		/* Check if it has a CIDR suffix and if so isolate it */
  		cidr_slash = strchr(token, '/');
--- 606,642 ----
  #ifdef USE_SSL
  		else if (token[4] == 'n')		/* "hostnossl" */
  		{
! 			parsedline->conntype = ctHostNoSSL;
  		}
  #endif
+ 		else 
+ 		{
+ 			/* "host", or "hostnossl" and SSL support not built in */
+ 			parsedline->conntype = ctHost;
+ 		}
+ 	} /* record type */
+ 	else
+ 		goto hba_syntax;
  
! 	/* Get the database. */
! 	line_item = lnext(line_item);
! 	if (!line_item)
! 		goto hba_syntax;
! 	parsedline->database = pstrdup(lfirst(line_item));
  
! 	/* Get the role. */
! 	line_item = lnext(line_item);
! 	if (!line_item)
! 		goto hba_syntax;
! 	parsedline->role = pstrdup(lfirst(line_item));
  
+ 	if (parsedline->conntype != ctLocal)
+ 	{
  		/* Read the IP address field. (with or without CIDR netmask) */
  		line_item = lnext(line_item);
  		if (!line_item)
  			goto hba_syntax;
! 		token = pstrdup(lfirst(line_item));
  
  		/* Check if it has a CIDR suffix and if so isolate it */
  		cidr_slash = strchr(token, '/');
***************
*** 760,768 ****
  		{
  			ereport(LOG,
  					(errcode(ERRCODE_CONFIG_FILE_ERROR),
! 			   errmsg("invalid IP address \"%s\" in file \"%s\" line %d: %s",
! 					  token, HbaFileName, line_num,
! 					  gai_strerror(ret))));
  			if (cidr_slash)
  				*cidr_slash = '/';
  			if (gai_result)
--- 658,666 ----
  		{
  			ereport(LOG,
  					(errcode(ERRCODE_CONFIG_FILE_ERROR),
! 					 errmsg("invalid IP address \"%s\" in file \"%s\" line %d: %s",
! 							token, HbaFileName, line_num,
! 							gai_strerror(ret))));
  			if (cidr_slash)
  				*cidr_slash = '/';
  			if (gai_result)
***************
*** 773,786 ****
  		if (cidr_slash)
  			*cidr_slash = '/';
  
! 		memcpy(&addr, gai_result->ai_addr, gai_result->ai_addrlen);
  		pg_freeaddrinfo_all(hints.ai_family, gai_result);
  
  		/* Get the netmask */
  		if (cidr_slash)
  		{
! 			if (pg_sockaddr_cidr_mask(&mask, cidr_slash + 1,
! 									  addr.ss_family) < 0)
  				goto hba_syntax;
  		}
  		else
--- 671,684 ----
  		if (cidr_slash)
  			*cidr_slash = '/';
  
! 		memcpy(&parsedline->addr, gai_result->ai_addr, gai_result->ai_addrlen);
  		pg_freeaddrinfo_all(hints.ai_family, gai_result);
  
  		/* Get the netmask */
  		if (cidr_slash)
  		{
! 			if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
! 									  parsedline->addr.ss_family) < 0)
  				goto hba_syntax;
  		}
  		else
***************
*** 796,813 ****
  			{
  				ereport(LOG,
  						(errcode(ERRCODE_CONFIG_FILE_ERROR),
! 				  errmsg("invalid IP mask \"%s\" in file \"%s\" line %d: %s",
! 						 token, HbaFileName, line_num,
! 						 gai_strerror(ret))));
  				if (gai_result)
  					pg_freeaddrinfo_all(hints.ai_family, gai_result);
  				goto hba_other_error;
  			}
  
! 			memcpy(&mask, gai_result->ai_addr, gai_result->ai_addrlen);
  			pg_freeaddrinfo_all(hints.ai_family, gai_result);
  
! 			if (addr.ss_family != mask.ss_family)
  			{
  				ereport(LOG,
  						(errcode(ERRCODE_CONFIG_FILE_ERROR),
--- 694,711 ----
  			{
  				ereport(LOG,
  						(errcode(ERRCODE_CONFIG_FILE_ERROR),
! 						 errmsg("invalid IP mask \"%s\" in file \"%s\" line %d: %s",
! 								token, HbaFileName, line_num,
! 								gai_strerror(ret))));
  				if (gai_result)
  					pg_freeaddrinfo_all(hints.ai_family, gai_result);
  				goto hba_other_error;
  			}
  
! 			memcpy(&parsedline->mask, gai_result->ai_addr, gai_result->ai_addrlen);
  			pg_freeaddrinfo_all(hints.ai_family, gai_result);
  
! 			if (parsedline->addr.ss_family != parsedline->mask.ss_family)
  			{
  				ereport(LOG,
  						(errcode(ERRCODE_CONFIG_FILE_ERROR),
***************
*** 816,877 ****
  				goto hba_other_error;
  			}
  		}
  
! 		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)
  			{
! 				pg_promote_v4_to_v6_addr(&addr);
! 				pg_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 (!pg_range_sockaddr(&port->raddr.addr, &addr, &mask))
- 			return;
- 
- 		/* Read the rest of the line. */
- 		line_item = lnext(line_item);
- 		if (!line_item)
- 			goto hba_syntax;
- 		parse_hba_auth(&line_item, &port->auth_method,
- 					   &port->auth_arg, error_p);
- 		if (*error_p)
- 			goto hba_syntax;
  	}
! 	else
! 		goto hba_syntax;
! 
! 	/* Does the entry match database and role? */
! 	if (!check_db(port->database_name, port->user_name, db))
! 		return;
! 	if (!check_role(port->user_name, role))
! 		return;
! 
! 	/* Success */
! 	*found_p = true;
! 	return;
  
  hba_syntax:
  	if (line_item)
  		ereport(LOG,
  				(errcode(ERRCODE_CONFIG_FILE_ERROR),
! 			  errmsg("invalid entry in file \"%s\" at line %d, token \"%s\"",
! 					 HbaFileName, line_num,
! 					 (char *) lfirst(line_item))));
  	else
  		ereport(LOG,
  				(errcode(ERRCODE_CONFIG_FILE_ERROR),
--- 714,841 ----
  				goto hba_other_error;
  			}
  		}
+ 	} /* != ctLocal */
+ 
+ 	/* Get the authentication method */
+ 	line_item = lnext(line_item);
+ 	if (!line_item)
+ 		goto hba_syntax;
+ 	token = lfirst(line_item);
+ 
+ 	unsupauth = NULL;
+ 	if (strcmp(token, "trust") == 0)
+ 		parsedline->auth_method = uaTrust;
+ 	else if (strcmp(token, "ident") == 0)
+ 		parsedline->auth_method = uaIdent;
+ 	else if (strcmp(token, "password") == 0)
+ 		parsedline->auth_method = uaPassword;
+ 	else if (strcmp(token, "krb5") == 0)
+ #ifdef KRB5
+ 		parsedline->auth_method = uaKrb5;
+ #else
+ 		unsupauth = "krb5";
+ #endif
+ 	else if (strcmp(token, "gss") == 0)
+ #ifdef ENABLE_GSS
+ 		parsedline->auth_method = uaGSS;
+ #else
+ 		unsupauth = "gss";
+ #endif
+ 	else if (strcmp(token, "sspi") == 0)
+ #ifdef ENABLE_SSPI
+ 		parsedline->auth_method = uaSSPI;
+ #else
+ 		unsupauth = "sspi";
+ #endif
+ 	else if (strcmp(token, "reject") == 0)
+ 		parsedline->auth_method = uaReject;
+ 	else if (strcmp(token, "md5") == 0)
+ 		parsedline->auth_method = uaMD5;
+ 	else if (strcmp(token, "crypt") == 0)
+ 		parsedline->auth_method = uaCrypt;
+ 	else if (strcmp(token, "pam") == 0)
+ #ifdef USE_PAM
+ 		parsedline->auth_method = uaPAM;
+ #else
+ 		unsupauth = "pam";
+ #endif
+ 	else if (strcmp(token, "ldap") == 0)
+ #ifdef USE_LDAP
+ 		parsedline->auth_method = uaLDAP;
+ #else
+ 		unsupauth = "ldap";
+ #endif
+ 	else
+ 	{
+ 		ereport(LOG,
+ 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
+ 				 errmsg("invalid authentication method \"%s\" in file \"%s\" line %d",
+ 						token, HbaFileName, line_num)));
+ 		goto hba_other_error;
+ 	}
+ 
+ 	if (unsupauth)
+ 	{
+ 		ereport(LOG,
+ 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
+ 				 errmsg("invalid authentication method \"%s\" in file \"%s\" line %d: not supported on this platform",
+ 						token, HbaFileName, line_num)));
+ 		goto hba_other_error;
+ 	}
+ 
+ 	/* Invalid authentication combinations */
+ 	if (parsedline->conntype == ctLocal &&
+ 		parsedline->auth_method == uaKrb5)
+ 	{
+ 		ereport(LOG,
+ 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
+ 				 errmsg("krb5 authentication is not supported on local sockets in file \"%s\" line %d",
+ 						HbaFileName, line_num)));
+ 		goto hba_other_error;
+ 	}
+ 
+ 	/* Get the authentication argument token, if any */
+ 	line_item = lnext(line_item);
+ 	if (line_item)
+ 	{
+ 		token = lfirst(line_item);
+ 		parsedline->auth_arg= pstrdup(token);
+ 	}
  
! 	/* 
! 	 * backwards compatible format of ident authentication - support "naked" ident map
! 	 * name, as well as "sameuser"/"samerole"
! 	 */
! 	if (parsedline->auth_method == uaIdent)
! 	{
! 		if (parsedline->auth_arg && strlen(parsedline->auth_arg))
  		{
! 			if (strcmp(parsedline->auth_arg, "sameuser\n") == 0 ||
! 				strcmp(parsedline->auth_arg, "samerole\n") == 0)
  			{
! 				/* This is now the default */
! 				pfree(parsedline->auth_arg);
! 				parsedline->auth_arg = NULL;
! 				parsedline->usermap = NULL;
  			}
  			else
  			{
! 				/* Specific ident map specified */
! 				parsedline->usermap = parsedline->auth_arg;
! 				parsedline->auth_arg = NULL;
  			}
  		}
  	}
! 	
! 	return true;
  
  hba_syntax:
  	if (line_item)
  		ereport(LOG,
  				(errcode(ERRCODE_CONFIG_FILE_ERROR),
! 				 errmsg("invalid entry in file \"%s\" at line %d, token \"%s\"",
! 						HbaFileName, line_num,
! 						(char *) lfirst(line_item))));
  	else
  		ereport(LOG,
  				(errcode(ERRCODE_CONFIG_FILE_ERROR),
***************
*** 880,886 ****
  
  	/* Come here if suitable message already logged */
  hba_other_error:
! 	*error_p = true;
  }
  
  
--- 844,850 ----
  
  	/* Come here if suitable message already logged */
  hba_other_error:
! 	return false;
  }
  
  
***************
*** 891,918 ****
  static bool
  check_hba(hbaPort *port)
  {
- 	bool		found_entry = false;
- 	bool		error = false;
  	ListCell   *line;
! 	ListCell   *line_num;
  
! 	forboth(line, hba_lines, line_num, hba_line_nums)
  	{
! 		parse_hba(lfirst(line), lfirst_int(line_num),
! 				  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;
  }
  
  
--- 855,950 ----
  static bool
  check_hba(hbaPort *port)
  {
  	ListCell   *line;
! 	HbaLine	   *hba;
  
! 	foreach(line, parsed_hba_lines)
  	{
! 		hba = (HbaLine *) lfirst(line);
  
! 		/* Check connection type */
! 		if (hba->conntype == ctLocal)
! 		{
! 			if (!IS_AF_UNIX(port->raddr.addr.ss_family))
! 				continue;
! 		}
! 		else
! 		{
! 			if (IS_AF_UNIX(port->raddr.addr.ss_family))
! 				continue;
! 
! 			/* Check SSL state */
! #ifdef USE_SSL
! 			if (port->ssl)
! 			{
! 				/* Connection is SSL, match both "host" and "hostssl" */
! 				if (hba->conntype == ctHostNoSSL)
! 					continue;
! 			}
! 			else
! 			{
! 				/* Connection is not SSL, match both "host" and "hostnossl" */
! 				if (hba->conntype == ctHostSSL)
! 					continue;
! 			}
! #else
! 			/* No SSL support, so reject "hostssl" lines */
! 			if (hba->conntype == ctHostSSL)
! 				continue;
! #endif
! 
! 			/* Check IP address */
! 			if (port->raddr.addr.ss_family == hba->addr.ss_family)
! 			{
! 				if (!pg_range_sockaddr(&port->raddr.addr, &hba->addr, &hba->mask))
! 					continue;
! 			}
! #ifdef HAVE_IPV6
! 			else  if (hba->addr.ss_family == AF_INET &&
! 					  port->raddr.addr.ss_family == AF_INET6)
! 			{
! 				/*
! 				 * 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.
! 				 */
! 				struct sockaddr_storage addrcopy, maskcopy;
! 				memcpy(&addrcopy, &hba->addr, sizeof(addrcopy));
! 				memcpy(&maskcopy, &hba->mask, sizeof(maskcopy));
! 				pg_promote_v4_to_v6_addr(&addrcopy);
! 				pg_promote_v4_to_v6_mask(&maskcopy);
! 				
! 				if (!pg_range_sockaddr(&port->raddr.addr, &addrcopy, &maskcopy))
! 					continue;
! 			}
! #endif /* HAVE_IPV6 */
! 			else
! 				/* Wrong address family, no IPV6 */
! 				continue;
! 		} /* != ctLocal */
! 
! 		/* Check database and role */
! 		if (!check_db(port->database_name, port->user_name, hba->database))
! 			continue;
! 
! 		if (!check_role(port->user_name, hba->role))
! 			continue;
! 
! 		/* Found a record that matched! */
! 		port->hba = hba;
  		return true;
  	}
! 
! 	/* If no matching entry was found, synthesize 'reject' entry. */
! 	hba = palloc0(sizeof(HbaLine));
! 	hba->auth_method = uaReject;
! 	port->hba = hba;
! 	return true;
! 
! 	/* XXX:
! 	 * Return false only happens if we have a parsing error, which we can 
! 	 * no longer have (parsing now in postmaster). Consider changing API.
! 	 */
  }
  
  
***************
*** 967,983 ****
  	}
  }
  
  
  /*
!  * Read the config file and create a List of Lists of tokens in the file.
   */
! void
  load_hba(void)
  {
  	FILE	   *file;
! 
! 	if (hba_lines || hba_line_nums)
! 		free_lines(&hba_lines, &hba_line_nums);
  
  	file = AllocateFile(HbaFileName, "r");
  	/* Failure is fatal since with no HBA entries we can do nothing... */
--- 999,1050 ----
  	}
  }
  
+ /*
+  * Free the contents of a hba record
+  */
+ static void
+ free_hba_record(HbaLine *record)
+ {
+ 	if (record->database)
+ 		pfree(record->database);
+ 	if (record->role)
+ 		pfree(record->role);
+ 	if (record->auth_arg)
+ 		pfree(record->auth_arg);
+ }
  
  /*
!  * Free all records on the parsed HBA list
   */
! static void
! clean_hba_list(List *lines)
! {
! 	ListCell	*line;
! 
! 	foreach(line, lines)
! 	{
! 		HbaLine *parsed = (HbaLine *)lfirst(line);
! 		if (parsed)
! 			free_hba_record(parsed);
! 	}
! 	list_free(lines);
! }
! 
! /*
!  * Read the config file and create a List of HbaLine records for the contents.
!  *
!  * The configuration is read into a temporary list, and if any parse error occurs
!  * the old list is kept in place and false is returned. Only if the whole file
!  * parses Ok is the list replaced, and the function returns true.
!  */
! bool
  load_hba(void)
  {
  	FILE	   *file;
! 	List *hba_lines = NIL;
! 	List *hba_line_nums = NIL;
! 	ListCell   *line, *line_num;
! 	List *new_parsed_lines = NIL;
  
  	file = AllocateFile(HbaFileName, "r");
  	/* Failure is fatal since with no HBA entries we can do nothing... */
***************
*** 989,994 ****
--- 1056,1090 ----
  
  	tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums);
  	FreeFile(file);
+ 
+ 	/* Now parse all the lines */
+ 	forboth(line, hba_lines, line_num, hba_line_nums)
+ 	{
+ 		HbaLine *newline;
+ 
+ 		newline = palloc0(sizeof(HbaLine));
+ 
+ 		if (!parse_hba_line(lfirst(line), lfirst_int(line_num), newline))
+ 		{
+ 			/* Parse error in the file, so bail out */
+ 			free_hba_record(newline);
+ 			pfree(newline);
+ 			clean_hba_list(new_parsed_lines);
+ 			/* Error has already been reported in the parsing function */
+ 			return false;
+ 		}
+ 
+ 		new_parsed_lines = lappend(new_parsed_lines, newline);
+ 	}
+ 
+ 	/* Loaded new file successfully, replace the one we use */
+ 	clean_hba_list(parsed_hba_lines);
+ 	parsed_hba_lines = new_parsed_lines;
+ 
+ 	/* Free the temporary lists */
+ 	free_lines(&hba_lines, &hba_line_nums);
+ 
+ 	return true;
  }
  
  /*
***************
*** 1100,1106 ****
   *	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.
   *
--- 1196,1203 ----
   *	See if the user with ident username "ident_user" is allowed to act
   *	as Postgres user "pgrole" according to usermap "usermap_name".
   *
!  *  Special case: Usermap NULL, equivalent to what was previously called
!  *  "sameuser" or "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.
   *
***************
*** 1116,1129 ****
  
  	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
--- 1213,1218 ----
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.561
diff -c -r1.561 postmaster.c
*** src/backend/postmaster/postmaster.c	26 Jun 2008 02:47:19 -0000	1.561
--- src/backend/postmaster/postmaster.c	16 Aug 2008 15:44:20 -0000
***************
*** 888,894 ****
  	/*
  	 * Load configuration files for client authentication.
  	 */
! 	load_hba();
  	load_ident();
  
  	/*
--- 888,902 ----
  	/*
  	 * Load configuration files for client authentication.
  	 */
! 	if (!load_hba())
! 	{
! 		/* 
! 		 * It makes no sense continue if we fail to load the HBA file, since 
! 		 * there is no way to connect to the database in this case.
! 		 */
! 		ereport(FATAL,
! 				(errmsg("could not load pg_hba.conf")));
! 	}
  	load_ident();
  
  	/*
***************
*** 1926,1932 ****
  		/* PgStatPID does not currently need SIGHUP */
  
  		/* Reload authentication config files too */
! 		load_hba();
  		load_ident();
  
  #ifdef EXEC_BACKEND
--- 1934,1943 ----
  		/* PgStatPID does not currently need SIGHUP */
  
  		/* Reload authentication config files too */
! 		if (!load_hba())
! 			ereport(WARNING,
! 					(errmsg("pg_hba.conf not reloaded")));
! 
  		load_ident();
  
  #ifdef EXEC_BACKEND
***************
*** 3080,3086 ****
  											  ALLOCSET_DEFAULT_MAXSIZE);
  	MemoryContextSwitchTo(PostmasterContext);
  
! 	load_hba();
  	load_ident();
  	load_role();
  #endif
--- 3091,3105 ----
  											  ALLOCSET_DEFAULT_MAXSIZE);
  	MemoryContextSwitchTo(PostmasterContext);
  
! 	if (!load_hba())
! 	{
! 		/* 
! 		 * It makes no sense continue if we fail to load the HBA file, since 
! 		 * there is no way to connect to the database in this case.
! 		 */
! 		ereport(FATAL,
! 				(errmsg("could not load pg_hba.conf")));
! 	}
  	load_ident();
  	load_role();
  #endif
Index: src/include/libpq/hba.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/libpq/hba.h,v
retrieving revision 1.48
diff -c -r1.48 hba.h
*** src/include/libpq/hba.h	1 Aug 2008 09:09:48 -0000	1.48
--- src/include/libpq/hba.h	16 Aug 2008 15:44:20 -0000
***************
*** 33,42 ****
  #endif
  } UserAuth;
  
  typedef struct Port hbaPort;
  
  extern List **get_role_line(const char *role);
! extern void load_hba(void);
  extern void load_ident(void);
  extern void load_role(void);
  extern int	hba_getauthmethod(hbaPort *port);
--- 33,63 ----
  #endif
  } UserAuth;
  
+ typedef enum ConnType
+ {
+ 	ctLocal,
+ 	ctHost,
+ 	ctHostSSL,
+ 	ctHostNoSSL
+ } ConnType;
+ 
+ typedef struct 
+ {
+ 	int			linenumber;
+ 	ConnType	conntype;
+ 	char	   *database;
+ 	char	   *role;
+ 	struct sockaddr_storage addr;
+ 	struct sockaddr_storage mask;
+ 	UserAuth	auth_method;
+ 	char	   *usermap;
+ 	char	   *auth_arg;
+ } HbaLine;
+ 
  typedef struct Port hbaPort;
  
  extern List **get_role_line(const char *role);
! extern bool load_hba(void);
  extern void load_ident(void);
  extern void load_role(void);
  extern int	hba_getauthmethod(hbaPort *port);
Index: src/include/libpq/libpq-be.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/libpq/libpq-be.h,v
retrieving revision 1.66
diff -c -r1.66 libpq-be.h
*** src/include/libpq/libpq-be.h	26 Apr 2008 22:47:40 -0000	1.66
--- src/include/libpq/libpq-be.h	16 Aug 2008 15:44:20 -0000
***************
*** 121,128 ****
  	/*
  	 * Information that needs to be held during the authentication cycle.
  	 */
! 	UserAuth	auth_method;
! 	char	   *auth_arg;
  	char		md5Salt[4];		/* Password salt */
  	char		cryptSalt[2];	/* Password salt */
  
--- 121,127 ----
  	/*
  	 * Information that needs to be held during the authentication cycle.
  	 */
! 	HbaLine	   *hba;
  	char		md5Salt[4];		/* Password salt */
  	char		cryptSalt[2];	/* Password salt */
  
