Hi,

I was having trouble with user authentication, so I submerged myself in 
the source (UTSL ie. Use The Source luke ;) to see if I could figure out 
what I was doing wrong:

While using passwords stored in pg_shadow (pg_user), I cannot connect to 
the backend using the 'password' authentication, I can connect using 'crypt'.

Now, I found from the source that the routines that do crypt checking 
also seem to support plain passwords. But this code is never used, 
because apparently uaCrypt is never set for 'password', while my 
understanding is that this should be set when there is no password-file 
specified in pg_hba.conf.

AlthoughcCheckPassword() seems to provide for this, it appears not to be 
working.

Anybody knows what's going on here? I intent to fire up a debugger here 
to see if I can figure out what's wrong, but thought asking first doesn't 
do any harm.

btw. is there anywhere a good description on how control flows during 
this phase of connecting? It all looks very difficult, with lots of 
function pointer being passed around etc.

Maarten

_____________________________________________________________________________
| TU Delft, The Netherlands, Faculty of Information Technology and Systems  |
|                   Department of Electrical Engineering                    |
|           Computer Architecture and Digital Technique section             |
|                          M.Boekhold@et.tudelft.nl                         |
-----------------------------------------------------------------------------


Fri, 31 Jul 1998 21:23:10 +0200 (MET DST)
Maarten Boekhold <maartenb@dutepp0.et.tudelft.nl>
User authentication bug?
> Hi,
> 
> I was having trouble with user authentication, so I submerged myself in 
> the source (UTSL ie. Use The Source luke ;) to see if I could figure out 
> what I was doing wrong:
> 
> While using passwords stored in pg_shadow (pg_user), I cannot connect to 
> the backend using the 'password' authentication, I can connect using 'crypt'.
> 
> Now, I found from the source that the routines that do crypt checking 
> also seem to support plain passwords. But this code is never used, 
> because apparently uaCrypt is never set for 'password', while my 
> understanding is that this should be set when there is no password-file 
> specified in pg_hba.conf.
> 
> AlthoughcCheckPassword() seems to provide for this, it appears not to be 
> working.
> 
> Anybody knows what's going on here? I intent to fire up a debugger here 
> to see if I can figure out what's wrong, but thought asking first doesn't 
> do any harm.
> 
> btw. is there anywhere a good description on how control flows during 
> this phase of connecting? It all looks very difficult, with lots of 
> function pointer being passed around etc.

Yes, very confusing.  Only Tom Lane understands it, I think.  Maybe
Tatsuo too.

-- 
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Fri, 31 Jul 1998 15:53:25 -0400 (EDT)
Bruce Momjian <maillist@candle.pha.pa.us>
Re: [HACKERS] User authentication bug?
On Fri, 31 Jul 1998, Bruce Momjian wrote:

> > Hi,
> > 
> > I was having trouble with user authentication, so I submerged myself in 
> > the source (UTSL ie. Use The Source luke ;) to see if I could figure out 
> > what I was doing wrong:
> > 
> > While using passwords stored in pg_shadow (pg_user), I cannot connect to 
> > the backend using the 'password' authentication, I can connect using 'crypt'.
> > 
> > Now, I found from the source that the routines that do crypt checking 
> > also seem to support plain passwords. But this code is never used, 
> > because apparently uaCrypt is never set for 'password', while my 
> > understanding is that this should be set when there is no password-file 
> > specified in pg_hba.conf.
> > 
> > AlthoughcCheckPassword() seems to provide for this, it appears not to be 
> > working.
> > 
> > Anybody knows what's going on here? I intent to fire up a debugger here 
> > to see if I can figure out what's wrong, but thought asking first doesn't 
> > do any harm.

OK, I now know what's going on, at least at my home (I had this problem 
on another server, dunno if it's caused by the same thing):

	I had a password longer than 8 characters in pg_shadow.

when creating a user, postgres happily accepts more than 8 chars, and 
also stores them. apparently libpq-fe (or psql, dunno) only sends 8 
chars. And postgres internally (crypt_verify) also checks more than 8 
chars. The password-field in pg_shadow is of type text, so it can contain 
very long passwords.

2 options: either make psql/libpq-fe send more than 8 chars (don't know if
the protocol can handle it), or make the strcmp() in crypt_verify() a
strncmp(). 

Man, this was confusing.....

> > 
> > btw. is there anywhere a good description on how control flows during 
> > this phase of connecting? It all looks very difficult, with lots of 
> > function pointer being passed around etc.
> 
> Yes, very confusing.  Only Tom Lane understands it, I think.  Maybe
> Tatsuo too.

I'm so happy to know this. It means I'm not stupid. But I think I get it 
just a little bit. There's a lot of handling there to be able to handle 
more than 1 connection at a time, so therefore function pointers are 
stored to remember were the next input packet it supposed to be handled. 
IMO it would have been cleaner (ie. better readable) to have some 
integer plus a dispatch routine (large switch{} statement) to do this. 
Also much easier to debug I think.

Maarten

_____________________________________________________________________________
| TU Delft, The Netherlands, Faculty of Information Technology and Systems  |
|                   Department of Electrical Engineering                    |
|           Computer Architecture and Digital Technique section             |
|                          M.Boekhold@et.tudelft.nl                         |
-----------------------------------------------------------------------------


Fri, 31 Jul 1998 22:05:40 +0200 (MET DST)
Maarten Boekhold <maartenb@dutepp2.et.tudelft.nl>
Re: [HACKERS] User authentication bug?
On Fri, 31 Jul 1998, Maarten Boekhold wrote:

> Hi,
> 
> I was having trouble with user authentication, so I submerged myself in 
> the source (UTSL ie. Use The Source luke ;) to see if I could figure out 
> what I was doing wrong:
> 
> While using passwords stored in pg_shadow (pg_user), I cannot connect to 
> the backend using the 'password' authentication, I can connect using 'crypt'.

Until recently it was working. I'm not sure when or how it became broken,
as I haven't had things working right since I upgraded the machine a
couple of weeks ago.

> Now, I found from the source that the routines that do crypt checking 
> also seem to support plain passwords. But this code is never used, 
> because apparently uaCrypt is never set for 'password', while my 
> understanding is that this should be set when there is no password-file 
> specified in pg_hba.conf.

Thats right. I was looking through this part of the source when
implementing the authentication for JDBC. At that point it was going
though there.

It sounds like it could be higher up may be broken.

> AlthoughcCheckPassword() seems to provide for this, it appears not to be 
> working.
> 
> Anybody knows what's going on here? I intent to fire up a debugger here 
> to see if I can figure out what's wrong, but thought asking first doesn't 
> do any harm.
> 
> btw. is there anywhere a good description on how control flows during 
> this phase of connecting? It all looks very difficult, with lots of 
> function pointer being passed around etc.
> 
> Maarten
> 
> _____________________________________________________________________________
> | TU Delft, The Netherlands, Faculty of Information Technology and Systems  |
> |                   Department of Electrical Engineering                    |
> |           Computer Architecture and Digital Technique section             |
> |                          M.Boekhold@et.tudelft.nl                         |
> -----------------------------------------------------------------------------
> 
> 

-- 
Peter T Mount peter@retep.org.uk or petermount@earthling.net
Main Homepage: http://www.retep.org.uk
PostgreSQL JDBC Faq: http://www.retep.org.uk/postgres


Sat, 1 Aug 1998 09:18:42 +0100 (GMT)
Peter T Mount <peter@retep.org.uk>
Re: [HACKERS] User authentication bug?
Maarten Boekhold <maartenb@dutepp2.et.tudelft.nl> writes:
> OK, I now know what's going on, at least at my home (I had this problem 
> on another server, dunno if it's caused by the same thing):
> 	I had a password longer than 8 characters in pg_shadow.
> when creating a user, postgres happily accepts more than 8 chars, and 
> also stores them. apparently libpq-fe (or psql, dunno) only sends 8 
> chars.

It's not libpq's fault (at least not with the current sources).
It's psql's.  psql.c had a hardwired limit of 8 characters on
both the username and the password.  Ick.

With the attached patch, I have verified that long (> 8char anyway)
usernames and passwords work correctly in both "password" and "crypt"
authorization mode.  NOTE: at least on my machine, it seems that the
crypt() routines ignore the part of the password beyond 8 characters,
so there's no security gain from longer passwords in crypt auth mode.
But they don't fail.

The login-related part of psql has apparently not been touched since
roughly the fall of Rome ;-).  It was going through huge pushups to
get around the lack of username/login parameters to PQsetdb.  I don't
know when PQsetdbLogin was added to libpq, but it's there now ... so
I was able to rip out quite a lot of crufty code while I was at it.

It's possible that there are still bogus length limits on username
or password in some of the other PostgreSQL user interfaces besides
psql/libpq.  I will leave it to other folks to check that code.

			regards, tom lane


*** src/bin/psql/psql.c.orig	Sat Jul 18 14:34:14 1998
--- src/bin/psql/psql.c	Sat Aug  1 20:34:47 1998
***************
*** 132,140 ****
  static int	objectDescription(PsqlSettings *pset, char *object);
  static int	rightsList(PsqlSettings *pset);
  static void prompt_for_password(char *username, char *password);
- static char *
- make_connect_string(char *host, char *port, char *dbname,
- 					char *username, char *password);
  
  static char *gets_noreadline(char *prompt, FILE *source);
  static char *gets_readline(char *prompt, FILE *source);
--- 132,137 ----
***************
*** 1372,1406 ****
  	else
  	{
  		PGconn	   *olddb = pset->db;
- 		static char *userenv = NULL;
- 		char	   *old_userenv = NULL;
  		const char *dbparam;
! 
! 		if (new_user != NULL)
! 		{
! 
! 			/*
! 			 * PQsetdb() does not allow us to specify the user, so we have
! 			 * to do it via PGUSER
! 			 */
! 			if (userenv != NULL)
! 				old_userenv = userenv;
! 			userenv = malloc(strlen("PGUSER=") + strlen(new_user) + 1);
! 			sprintf(userenv, "PGUSER=%s", new_user);
! 			/* putenv() may continue to use memory as part of environment */
! 			putenv(userenv);
! 			/* can delete old memory if we malloc'ed it */
! 			if (old_userenv != NULL)
! 				free(old_userenv);
! 		}
  
  		if (strcmp(new_dbname, "-") != 0)
  			dbparam = new_dbname;
  		else
  			dbparam = PQdb(olddb);
  
! 		pset->db = PQsetdb(PQhost(olddb), PQport(olddb),
! 						   NULL, NULL, dbparam);
  		if (!pset->quiet)
  		{
  			if (!new_user)
--- 1369,1396 ----
  	else
  	{
  		PGconn	   *olddb = pset->db;
  		const char *dbparam;
! 		const char *userparam;
! 		const char *pwparam;
  
  		if (strcmp(new_dbname, "-") != 0)
  			dbparam = new_dbname;
  		else
  			dbparam = PQdb(olddb);
  
! 		if (new_user != NULL && strcmp(new_user, "-") != 0)
! 			userparam = new_user;
! 		else
! 			userparam = PQuser(olddb);
! 
! 		/* libpq doesn't provide an accessor function for the password,
! 		 * so we cheat here.
! 		 */
! 		pwparam = olddb->pgpass;
! 
! 		pset->db = PQsetdbLogin(PQhost(olddb), PQport(olddb),
! 								NULL, NULL, dbparam, userparam, pwparam);
! 
  		if (!pset->quiet)
  		{
  			if (!new_user)
***************
*** 2711,2726 ****
  
  	if (settings.getPassword)
  	{
! 		char		username[9];
! 		char		password[9];
! 		char	   *connect_string;
  
  		prompt_for_password(username, password);
  
! 		/* now use PQconnectdb so we can pass these options */
! 		connect_string = make_connect_string(host, port, dbname, username, password);
! 		settings.db = PQconnectdb(connect_string);
! 		free(connect_string);
  	}
  	else
  		settings.db = PQsetdb(host, port, NULL, NULL, dbname);
--- 2701,2713 ----
  
  	if (settings.getPassword)
  	{
! 		char		username[100];
! 		char		password[100];
  
  		prompt_for_password(username, password);
  
! 		settings.db = PQsetdbLogin(host, port, NULL, NULL, dbname,
! 								   username, password);
  	}
  	else
  		settings.db = PQsetdb(host, port, NULL, NULL, dbname);
***************
*** 2730,2736 ****
  	if (PQstatus(settings.db) == CONNECTION_BAD)
  	{
  		fprintf(stderr, "Connection to database '%s' failed.\n", dbname);
! 		fprintf(stderr, "%s", PQerrorMessage(settings.db));
  		PQfinish(settings.db);
  		exit(1);
  	}
--- 2717,2723 ----
  	if (PQstatus(settings.db) == CONNECTION_BAD)
  	{
  		fprintf(stderr, "Connection to database '%s' failed.\n", dbname);
! 		fprintf(stderr, "%s\n", PQerrorMessage(settings.db));
  		PQfinish(settings.db);
  		exit(1);
  	}
***************
*** 2964,2969 ****
--- 2951,2957 ----
  static void
  prompt_for_password(char *username, char *password)
  {
+ 	char buf[512];
  	int			length;
  
  #ifdef HAVE_TERMIOS_H
***************
*** 2973,2985 ****
  #endif
  
  	printf("Username: ");
! 	fgets(username, 9, stdin);
  	length = strlen(username);
  	/* skip rest of the line */
  	if (length > 0 && username[length - 1] != '\n')
  	{
- 		static char buf[512];
- 
  		do
  		{
  			fgets(buf, 512, stdin);
--- 2961,2971 ----
  #endif
  
  	printf("Username: ");
! 	fgets(username, 100, stdin);
  	length = strlen(username);
  	/* skip rest of the line */
  	if (length > 0 && username[length - 1] != '\n')
  	{
  		do
  		{
  			fgets(buf, 512, stdin);
***************
*** 2995,3001 ****
  	t.c_lflag &= ~ECHO;
  	tcsetattr(0, TCSADRAIN, &t);
  #endif
! 	fgets(password, 9, stdin);
  #ifdef HAVE_TERMIOS_H
  	tcsetattr(0, TCSADRAIN, &t_orig);
  #endif
--- 2981,2987 ----
  	t.c_lflag &= ~ECHO;
  	tcsetattr(0, TCSADRAIN, &t);
  #endif
! 	fgets(password, 100, stdin);
  #ifdef HAVE_TERMIOS_H
  	tcsetattr(0, TCSADRAIN, &t_orig);
  #endif
***************
*** 3004,3011 ****
  	/* skip rest of the line */
  	if (length > 0 && password[length - 1] != '\n')
  	{
- 		static char buf[512];
- 
  		do
  		{
  			fgets(buf, 512, stdin);
--- 2990,2995 ----
***************
*** 3015,3077 ****
  		password[length - 1] = '\0';
  
  	printf("\n\n");
- }
- 
- static char *
- make_connect_string(char *host, char *port, char *dbname,
- 					char *username, char *password)
- {
- 	int			connect_string_len = 0;
- 	char	   *connect_string;
- 
- 	if (host)
- 		connect_string_len += 6 + strlen(host); /* 6 == "host=" + " " */
- 	if (username)
- 		connect_string_len += 6 + strlen(username);		/* 6 == "user=" + " " */
- 	if (password)
- 		connect_string_len += 10 + strlen(password);	/* 10 == "password=" + "
- 														 * " */
- 	if (port)
- 		connect_string_len += 6 + strlen(port); /* 6 == "port=" + " " */
- 	if (dbname)
- 		connect_string_len += 8 + strlen(dbname);		/* 8 == "dbname=" + " " */
- 	connect_string_len += 18;	/* "authtype=password" + null */
- 
- 	connect_string = (char *) malloc(connect_string_len);
- 	if (!connect_string)
- 		return 0;
- 	connect_string[0] = '\0';
- 	if (host)
- 	{
- 		strcat(connect_string, "host=");
- 		strcat(connect_string, host);
- 		strcat(connect_string, " ");
- 	}
- 	if (username)
- 	{
- 		strcat(connect_string, "user=");
- 		strcat(connect_string, username);
- 		strcat(connect_string, " ");
- 	}
- 	if (password)
- 	{
- 		strcat(connect_string, "password=");
- 		strcat(connect_string, password);
- 		strcat(connect_string, " ");
- 	}
- 	if (port)
- 	{
- 		strcat(connect_string, "port=");
- 		strcat(connect_string, port);
- 		strcat(connect_string, " ");
- 	}
- 	if (dbname)
- 	{
- 		strcat(connect_string, "dbname=");
- 		strcat(connect_string, dbname);
- 		strcat(connect_string, " ");
- 	}
- 	strcat(connect_string, "authtype=password");
- 
- 	return connect_string;
  }
--- 2999,3002 ----

Sat, 01 Aug 1998 21:20:17 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: [HACKERS] User authentication bug? 
Maarten Boekhold <maartenb@dutepp2.et.tudelft.nl> writes:
> I'm so happy to know this. It means I'm not stupid. But I think I get it 
> just a little bit. There's a lot of handling there to be able to handle 
> more than 1 connection at a time, so therefore function pointers are 
> stored to remember were the next input packet it supposed to be handled. 

Right, the postmaster keeps a function pointer in the data for each
connection (specifically, in the Packet struct declared in libpq-be.h)
that defines what to do next on that connection ("next" meaning after
the current packet send or receive operation has been finished).
It can be a little confusing but I doubt it's worth changing.

(On the other hand, I'm used to that sort of thing from a dank past
of writing interrupt service routines.  If you're not, it might be
a lot confusing.)

			regards, tom lane

Sat, 01 Aug 1998 21:27:17 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: [HACKERS] User authentication bug? 
On Sat, 1 Aug 1998, Tom Lane wrote:

> Maarten Boekhold <maartenb@dutepp2.et.tudelft.nl> writes:
> > OK, I now know what's going on, at least at my home (I had this problem 
> > on another server, dunno if it's caused by the same thing):
> > 	I had a password longer than 8 characters in pg_shadow.
> > when creating a user, postgres happily accepts more than 8 chars, and 
> > also stores them. apparently libpq-fe (or psql, dunno) only sends 8 
> > chars.
> 
> It's not libpq's fault (at least not with the current sources).
> It's psql's.  psql.c had a hardwired limit of 8 characters on
> both the username and the password.  Ick.
> 
> With the attached patch, I have verified that long (> 8char anyway)
> usernames and passwords work correctly in both "password" and "crypt"
> authorization mode.  NOTE: at least on my machine, it seems that the
> crypt() routines ignore the part of the password beyond 8 characters,
> so there's no security gain from longer passwords in crypt auth mode.
> But they don't fail.
....
> 
> It's possible that there are still bogus length limits on username
> or password in some of the other PostgreSQL user interfaces besides
> psql/libpq.  I will leave it to other folks to check that code.

I think the perl-module behaves the same, but I'm not totally sure about 
it. I have a script where passing a 9 chars username to PQconnectdb() 
fails to connect to a backend, while if I truncate the username to 8 
chars it works.

Maarten

_____________________________________________________________________________
| TU Delft, The Netherlands, Faculty of Information Technology and Systems  |
|                   Department of Electrical Engineering                    |
|           Computer Architecture and Digital Technique section             |
|                          M.Boekhold@et.tudelft.nl                         |
-----------------------------------------------------------------------------


Sun, 2 Aug 1998 13:42:29 +0200 (MET DST)
Maarten Boekhold <maartenb@dutepp0.et.tudelft.nl>
Re: [HACKERS] User authentication bug?
Tom Lane <tgl@sss.pgh.pa.us> writes:

> With the attached patch, I have verified that long (> 8char anyway)
> usernames and passwords work correctly in both "password" and "crypt"
> authorization mode.  NOTE: at least on my machine, it seems that the
> crypt() routines ignore the part of the password beyond 8 characters,
> so there's no security gain from longer passwords in crypt auth mode.
> But they don't fail.

Which is why postgres should use MD5, salted with the username, as a
password one-way hash.  :)

--Michael

02 Aug 1998 12:54:57 -0700
Michael Graff <explorer@flame.org>
Re: [PATCHES] Re: [HACKERS] User authentication bug?
Maarten Boekhold <maartenb@dutepp0.et.tudelft.nl> writes:
> On Sat, 1 Aug 1998, Tom Lane wrote:
>> It's possible that there are still bogus length limits on username
>> or password in some of the other PostgreSQL user interfaces besides
>> psql/libpq.  I will leave it to other folks to check that code.

> I think the perl-module behaves the same, but I'm not totally sure about 
> it. I have a script where passing a 9 chars username to PQconnectdb() 
> fails to connect to a backend, while if I truncate the username to 8 
> chars it works.

Hmm.  What pgsql version are you using?  A quick glance at
src/interfaces/perl5 doesn't show any dependencies on username or
password length in it --- it's just a very simple wrapper for libpq.

			regards, tom lane

Sun, 02 Aug 1998 18:40:28 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: [INTERFACES] Re: [HACKERS] User authentication bug? 
On Sun, 2 Aug 1998, Tom Lane wrote:

> Maarten Boekhold <maartenb@dutepp0.et.tudelft.nl> writes:
> > On Sat, 1 Aug 1998, Tom Lane wrote:
> >> It's possible that there are still bogus length limits on username
> >> or password in some of the other PostgreSQL user interfaces besides
> >> psql/libpq.  I will leave it to other folks to check that code.
> 
> > I think the perl-module behaves the same, but I'm not totally sure about 
> > it. I have a script where passing a 9 chars username to PQconnectdb() 
> > fails to connect to a backend, while if I truncate the username to 8 
> > chars it works.
> 
> Hmm.  What pgsql version are you using?  A quick glance at
> src/interfaces/perl5 doesn't show any dependencies on username or
> password length in it --- it's just a very simple wrapper for libpq.

I'll have a quick try to see if it indeed does behave this way. Get back 
to you later.

Maarten

_____________________________________________________________________________
| TU Delft, The Netherlands, Faculty of Information Technology and Systems  |
|                   Department of Electrical Engineering                    |
|           Computer Architecture and Digital Technique section             |
|                          M.Boekhold@et.tudelft.nl                         |
-----------------------------------------------------------------------------


Mon, 3 Aug 1998 08:30:17 +0200 (MET DST)
Maarten Boekhold <maartenb@dutepp2.et.tudelft.nl>
Re: [INTERFACES] Re: [HACKERS] User authentication bug?
On Sun, 2 Aug 1998, Tom Lane wrote:

> Maarten Boekhold <maartenb@dutepp0.et.tudelft.nl> writes:
> > On Sat, 1 Aug 1998, Tom Lane wrote:
> >> It's possible that there are still bogus length limits on username
> >> or password in some of the other PostgreSQL user interfaces besides
> >> psql/libpq.  I will leave it to other folks to check that code.
> 
> > I think the perl-module behaves the same, but I'm not totally sure about 
> > it. I have a script where passing a 9 chars username to PQconnectdb() 
> > fails to connect to a backend, while if I truncate the username to 8 
> > chars it works.
> 
> Hmm.  What pgsql version are you using?  A quick glance at
> src/interfaces/perl5 doesn't show any dependencies on username or
> password length in it --- it's just a very simple wrapper for libpq.

I've tried it (wrote a little script to test it), and I got the following:

length(usename) == 9 : connect with usename of 9 : failed
length(usename) == 9 : connect with usename of 8 : failed
length(usename) == 8 : connect with usename of 9 : failed
length(usename) == 8 : connect with usename of 8 : succeeded

so it appears not to be working somehow...

Maarten

_____________________________________________________________________________
| TU Delft, The Netherlands, Faculty of Information Technology and Systems  |
|                   Department of Electrical Engineering                    |
|           Computer Architecture and Digital Technique section             |
|                          M.Boekhold@et.tudelft.nl                         |
-----------------------------------------------------------------------------


Mon, 3 Aug 1998 08:40:03 +0200 (MET DST)
Maarten Boekhold <maartenb@dutepp2.et.tudelft.nl>
Re: [INTERFACES] Re: [HACKERS] User authentication bug?