Thread: Kerberos authentication, Active Directory, and PostgreSQL

Kerberos authentication, Active Directory, and PostgreSQL

From
"Turner, Ian"
Date:
Hello pgsql-bugs,

While trying to connect our PostgreSQL database to our Kerberos realm, we e=
ncountered the obscure message "Invalid message length". Tracking this down=
, we discovered that it was emitted by src/backend/libpq/pqcomm.c in respon=
se to a rather large Kerberos message. The root cause is as follows, and a =
patch is below.

The code in src/backend/libpq/auth.c contains a hard-coded limit on the siz=
e of GSS messages, and in particular on the message containing the client's=
 Kerberos ticket for the postgres server. The limit was 2,000 bytes, which =
is normally adequate for tickets based on TGTs issued by Unix KDCs. However=
, TGTs issued by Windows domain controllers contain an authorization field =
known as the PAC (privilege attribute certificate), which contains the user=
's Windows permissions (group memberships etc.). The PAC is copied into all=
 tickets obtained on the basis of this TGT (even those issued by Unix realm=
s which the Windows realm trusts), and can be several K in size. Thus, GSS =
authentication was failing with a "invalid message length" error. We simply=
 upped the limit to 32k, which ought to be sufficient.

The patch is quite brief:

--- postgresql-8.4-8.4.1/src/backend/libpq/auth.c=A0=A0=A0=A0=A0=A0 2009-06=
-25 12:30:08.000000000 +0100
+++ postgresql-8.4-8.4.1-fixed/src/backend/libpq/auth.c 2009-09-15 20:27:01=
.000000000 +0100
@@ -166,6 +166,8 @@
=A0#endif

=A0static int=A0=A0=A0=A0 pg_GSS_recvauth(Port *port);
+
+#define GSS_MAX_TOKEN_LENGTH (32767)
=A0#endif=A0=A0 /* ENABLE_GSS */


@@ -937,7 +939,7 @@

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /* Get the actual GSS token */
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 initStringInfo(&buf);
-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if (pq_getmessage(&buf, 2000))
+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if (pq_getmessage(&buf, GSS_MAX=
_TOKEN_LENGTH))
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 {
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /* EO=
F - pq_getmessage already logged error */
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 pfree=
(buf.data);


Please let me know if anything additional is required in order to get this =
fix into the next release.

Best regards,

--Ian Turner
  Sr. UNIX Systems Engineer
  D. E. Shaw & Co.

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Heikki Linnakangas
Date:
Turner, Ian wrote:
> While trying to connect our PostgreSQL database to our Kerberos realm, we encountered the obscure message "Invalid
messagelength". Tracking this down, we discovered that it was emitted by src/backend/libpq/pqcomm.c in response to a
ratherlarge Kerberos message. The root cause is as follows, and a patch is below. 
>
> The code in src/backend/libpq/auth.c contains a hard-coded limit on the size of GSS messages, and in particular on
themessage containing the client's Kerberos ticket for the postgres server. The limit was 2,000 bytes, which is
normallyadequate for tickets based on TGTs issued by Unix KDCs. However, TGTs issued by Windows domain controllers
containan authorization field known as the PAC (privilege attribute certificate), which contains the user's Windows
permissions(group memberships etc.). The PAC is copied into all tickets obtained on the basis of this TGT (even those
issuedby Unix realms which the Windows realm trusts), and can be several K in size. Thus, GSS authentication was
failingwith a "invalid message length" error. We simply upped the limit to 32k, which ought to be sufficient. 
>
> The patch is quite brief:
>
> --- postgresql-8.4-8.4.1/src/backend/libpq/auth.c       2009-06-25 12:30:08.000000000 +0100
> +++ postgresql-8.4-8.4.1-fixed/src/backend/libpq/auth.c 2009-09-15 20:27:01.000000000 +0100
> @@ -166,6 +166,8 @@
>  #endif
>
>  static int     pg_GSS_recvauth(Port *port);
> +
> +#define GSS_MAX_TOKEN_LENGTH (32767)
>  #endif   /* ENABLE_GSS */
>
>
> @@ -937,7 +939,7 @@
>
>                 /* Get the actual GSS token */
>                 initStringInfo(&buf);
> -               if (pq_getmessage(&buf, 2000))
> +               if (pq_getmessage(&buf, GSS_MAX_TOKEN_LENGTH))
>                 {
>                         /* EOF - pq_getmessage already logged error */
>                         pfree(buf.data);
>
>
> Please let me know if anything additional is required in order to get this fix into the next release.

The corresponding limit in pg_SSPI_recvauth() probably needs to be
raised too..

pq_getmessage() doesn't necessarily need a limit, we could accept
arbitrarily long tokens. Although I guess we want to avoid simple
denial-of-service attacks exhausting backend memory.

--
  Heikki Linnakangas
  EnterpriseDB   http://www.enterprisedb.com

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Magnus Hagander
Date:
2009/10/13 Heikki Linnakangas <heikki.linnakangas@enterprisedb.com>:
> Turner, Ian wrote:
>> While trying to connect our PostgreSQL database to our Kerberos realm, w=
e encountered the obscure message "Invalid message length". Tracking this d=
own, we discovered that it was emitted by src/backend/libpq/pqcomm.c in res=
ponse to a rather large Kerberos message. The root cause is as follows, and=
 a patch is below.
>>
>> The code in src/backend/libpq/auth.c contains a hard-coded limit on the =
size of GSS messages, and in particular on the message containing the clien=
t's Kerberos ticket for the postgres server. The limit was 2,000 bytes, whi=
ch is normally adequate for tickets based on TGTs issued by Unix KDCs. Howe=
ver, TGTs issued by Windows domain controllers contain an authorization fie=
ld known as the PAC (privilege attribute certificate), which contains the u=
ser's Windows permissions (group memberships etc.). The PAC is copied into =
all tickets obtained on the basis of this TGT (even those issued by Unix re=
alms which the Windows realm trusts), and can be several K in size. Thus, G=
SS authentication was failing with a "invalid message length" error. We sim=
ply upped the limit to 32k, which ought to be sufficient.
>>
>> The patch is quite brief:
>>
>> --- postgresql-8.4-8.4.1/src/backend/libpq/auth.c =A0 =A0 =A0 2009-06-25=
 12:30:08.000000000 +0100
>> +++ postgresql-8.4-8.4.1-fixed/src/backend/libpq/auth.c 2009-09-15 20:27=
:01.000000000 +0100
>> @@ -166,6 +166,8 @@
>> =A0#endif
>>
>> =A0static int =A0 =A0 pg_GSS_recvauth(Port *port);
>> +
>> +#define GSS_MAX_TOKEN_LENGTH (32767)
>> =A0#endif =A0 /* ENABLE_GSS */
>>
>>
>> @@ -937,7 +939,7 @@
>>
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Get the actual GSS token */
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 initStringInfo(&buf);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (pq_getmessage(&buf, 2000))
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (pq_getmessage(&buf, GSS_MAX_TOKEN_LENG=
TH))
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* EOF - pq_getmessage a=
lready logged error */
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pfree(buf.data);
>>
>>
>> Please let me know if anything additional is required in order to get th=
is fix into the next release.
>
> The corresponding limit in pg_SSPI_recvauth() probably needs to be
> raised too..

Probably, but ont entirely certainly. Given how SSPI works.

But for consistency that would certainly be a good idea :-)

> pq_getmessage() doesn't necessarily need a limit, we could accept
> arbitrarily long tokens. Although I guess we want to avoid simple
> denial-of-service attacks exhausting backend memory.

Yeah.
FWIW, the default max token size on Win2k is ~8Kb. In some service
pack and then in Win2003, it was increased to 12Kb. But it is possible
to increase that by a registry key on the domain controller - and I
read somewhere that Win2008 actually will increase this size
dynamically.

Actually, I found a note that said it's recommended to never increase
it about 65535 - so perhaps we should put our limit at that instead od
32767?

--=20
 Magnus Hagander
 Me: http://www.hagander.net/
 Work: http://www.redpill-linpro.com/

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Peter Eisentraut
Date:
On Mon, 2009-10-12 at 20:42 -0400, Turner, Ian wrote:
> --- postgresql-8.4-8.4.1/src/backend/libpq/auth.c       2009-06-25 12:30:08.000000000 +0100
> +++ postgresql-8.4-8.4.1-fixed/src/backend/libpq/auth.c 2009-09-15 20:27:01.000000000 +0100
> @@ -166,6 +166,8 @@
>  #endif
>
>  static int     pg_GSS_recvauth(Port *port);
> +
> +#define GSS_MAX_TOKEN_LENGTH (32767)
>  #endif   /* ENABLE_GSS */
>
>

A small wish in case we go with this: The constant should be named
something like PG_...; otherwise it looks like we are defining or
overriding an official symbol from the GSS API.

> @@ -937,7 +939,7 @@
>
>                 /* Get the actual GSS token */
>                 initStringInfo(&buf);
> -               if (pq_getmessage(&buf, 2000))
> +               if (pq_getmessage(&buf, GSS_MAX_TOKEN_LENGTH))
>                 {
>                         /* EOF - pq_getmessage already logged error */
>                         pfree(buf.data);

To wit, the above hunk looks quite misleading in isolation.

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Tom Lane
Date:
Peter Eisentraut <peter_e@gmx.net> writes:
> A small wish in case we go with this: The constant should be named
> something like PG_...; otherwise it looks like we are defining or
> overriding an official symbol from the GSS API.

I'd be inclined to just s/2000/32767/ and not bother with a symbol,
misleadingly named or otherwise.  If the value were actually being
used in more than one place, it'd be a different story, but to be
so used it would likely need a completely different name.

            regards, tom lane

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Bruce Momjian
Date:
Peter Eisentraut wrote:
> On Mon, 2009-10-12 at 20:42 -0400, Turner, Ian wrote:
> > --- postgresql-8.4-8.4.1/src/backend/libpq/auth.c       2009-06-25 12:30:08.000000000 +0100
> > +++ postgresql-8.4-8.4.1-fixed/src/backend/libpq/auth.c 2009-09-15 20:27:01.000000000 +0100
> > @@ -166,6 +166,8 @@
> >  #endif
> >
> >  static int     pg_GSS_recvauth(Port *port);
> > +
> > +#define GSS_MAX_TOKEN_LENGTH (32767)
> >  #endif   /* ENABLE_GSS */
> >
> >
>
> A small wish in case we go with this: The constant should be named
> something like PG_...; otherwise it looks like we are defining or
> overriding an official symbol from the GSS API.

Agreed.  In my first glance at the patch I thought GSS_MAX_TOKEN_LENGTH
was defined in a system include file.

--
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
"Turner, Ian"
Date:
Tom Lane:
> I'd be inclined to just s/2000/32767/ and not bother with a symbol,

Heikki Linnakangas:
> The corresponding limit in pg_SSPI_recvauth() probably needs to be
> raised too..

Magnus Hagander:
> Actually, I found a note that said it's recommended to never increase
> it [above] 65535 - so perhaps we should put our limit at that instead
> [of] 32767?


Perhaps the thing to do is to use a symbol, set its value to 65535, and use=
 the same symbol for all of GSS, SSPI, and KRB5.

--Ian

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Heikki Linnakangas
Date:
Magnus Hagander wrote:
> FWIW, the default max token size on Win2k is ~8Kb. In some service
> pack and then in Win2003, it was increased to 12Kb. But it is possible
> to increase that by a registry key on the domain controller - and I
> read somewhere that Win2008 actually will increase this size
> dynamically.
>
> Actually, I found a note that said it's recommended to never increase
> it about 65535 - so perhaps we should put our limit at that instead od
> 32767?

Yeah, setting it at 65535 seems like a good idea then. I'm tempted to
backport this, although it's not strictly speaking a bug fix. Any
objections?

--
  Heikki Linnakangas
  EnterpriseDB   http://www.enterprisedb.com

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Tom Lane
Date:
Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:
> Magnus Hagander wrote:
>> Actually, I found a note that said it's recommended to never increase
>> it about 65535 - so perhaps we should put our limit at that instead od
>> 32767?

> Yeah, setting it at 65535 seems like a good idea then. I'm tempted to
> backport this, although it's not strictly speaking a bug fix. Any
> objections?

Why isn't it a bug fix?  +1 for backport ...

            regards, tom lane

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Magnus Hagander
Date:
2009/10/13 Tom Lane <tgl@sss.pgh.pa.us>:
> Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:
>> Magnus Hagander wrote:
>>> Actually, I found a note that said it's recommended to never increase
>>> it about 65535 - so perhaps we should put our limit at that instead od
>>> 32767?
>
>> Yeah, setting it at 65535 seems like a good idea then. I'm tempted to
>> backport this, although it's not strictly speaking a bug fix. Any
>> objections?
>
> Why isn't it a bug fix? =A0+1 for backport ...

Yeah, +1 there.

--=20
 Magnus Hagander
 Me: http://www.hagander.net/
 Work: http://www.redpill-linpro.com/

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Heikki Linnakangas
Date:
Magnus Hagander wrote:
> 2009/10/13 Tom Lane <tgl@sss.pgh.pa.us>:
>> Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:
>>> Magnus Hagander wrote:
>>>> Actually, I found a note that said it's recommended to never increase
>>>> it about 65535 - so perhaps we should put our limit at that instead od
>>>> 32767?
>>> Yeah, setting it at 65535 seems like a good idea then. I'm tempted to
>>> backport this, although it's not strictly speaking a bug fix. Any
>>> objections?
>> Why isn't it a bug fix?  +1 for backport ...
>
> Yeah, +1 there.

Ok, committed.

--
  Heikki Linnakangas
  EnterpriseDB   http://www.enterprisedb.com

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Heikki Linnakangas
Date:
Tom Lane wrote:
> Peter Eisentraut <peter_e@gmx.net> writes:
>> A small wish in case we go with this: The constant should be named
>> something like PG_...; otherwise it looks like we are defining or
>> overriding an official symbol from the GSS API.
>
> I'd be inclined to just s/2000/32767/ and not bother with a symbol,
> misleadingly named or otherwise.  If the value were actually being
> used in more than one place, it'd be a different story, but to be
> so used it would likely need a completely different name.

It is used in two places in that file: pg_GSS_recvauth() and
pg_SSPI_recvauth(). (the original patch neglected SSPI)

I'll rename it to PG_MAX_AUTH_TOKEN_LENGTH, unless someone has a better
suggestion.

--
  Heikki Linnakangas
  EnterpriseDB   http://www.enterprisedb.com

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
"Turner, Ian"
Date:
> I'll rename it to PG_MAX_AUTH_TOKEN_LENGTH, unless someone has a better
> suggestion.

If we are not changing this for all authentication schemes, then the name s=
hould probably reflect that this is for GSS and SSPI only (not even KRB5).

--Ian

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
Tom Lane
Date:
"Turner, Ian" <Ian.Turner@deshaw.com> writes:
>> I'll rename it to PG_MAX_AUTH_TOKEN_LENGTH, unless someone has a better
>> suggestion.

> If we are not changing this for all authentication schemes, then the name should probably reflect that this is for
GSSand SSPI only (not even KRB5). 

Then we'd have to rename the symbol anytime we applied it to some new
auth scheme.  The original naming complaint reflected a concern that
the symbol looked like it was supplied by the system headers, rather
than being of Postgres origin.  Heikki's suggestion deals with that,
and I think it's fine as-is.

            regards, tom lane

Re: Kerberos authentication, Active Directory, and PostgreSQL

From
"Turner, Ian"
Date:
> The original naming complaint reflected a concern that
> the symbol looked like it was supplied by the system headers, rather
> than being of Postgres origin.  Heikki's suggestion deals with that,
> and I think it's fine as-is.

OK, fine with me.

--Ian