Skip site navigation (1) Skip section navigation (2)

Re: Kerberos v5 support

From: Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us>
To: Garrett Wollman <wollman(at)khavrinen(dot)lcs(dot)mit(dot)edu>
Cc: pgsql-patches(at)postgresql(dot)org
Subject: Re: Kerberos v5 support
Date: 2000-11-06 17:05:01
Message-ID: 200011061705.MAA22568@candle.pha.pa.us (view raw or flat)
Thread:
Lists: pgsql-patches
I have applied some kerberos changes to the current snapshot a few
months ago.  Can you grab that and let me know what you would like
changed?  Thanks.


> I thought I sent this back in September, but I can't find anything in
> the mailing-list archives, so I am assuming it fell into a black hole.
> 
> Enclosed please find a set of patches, relative to 7.0.2, which will
> result in Kerberos v5 support which both compiles and works (as in,
> I've successfully authenticated as a remote client).
> 
> Our pg_hba.conf file then looks like:
> 
> local        all                                           trust
> host         all         0.0.0.0        0.0.0.0         krb5
> 
> However, that `trust' is tempered by changes to the startup scripts
> (not included here) which force the local-domain socket to mode 600,
> thereby ensuring that all normal clients connect via an authenticated
> network connection.
> 
> You can see from some of the comments that I'd like this to be made
> stronger in a number of ways.  This patch set simply gets pgsql up to
> the minimum acceptable level of security for our environment and
> application.
> 
> My original message follows.
> 
> ------------------------------------------------------------------------
> 
> The enclosed patches fix the Kerberos v5 support in libpq and the
> backend.  It was totally broken before, now it's still broken but
> works.  (That is to say: before, it didn't work, and now it does work
> but doesn't provide the level of security it should.  Still better
> than plaintext passwords.)  So far as I can tell, the original code
> was written for an early beta version, and rotted severely in the
> intervening years.  We actually need authentication to work, which is
> why I'm doing this now.
> 
> A few notes:
> 
> - See the comment near pg_an_to_ln() about one part of the brokenness.
> 
> - As implemented, this code will not work over PF_LOCAL sockets.
> 
> - Some things don't work correctly in the absence of a `local all
> trust' line in pg_hba.conf, and PGUSER needs to be set in order for
> *that* to work.
> 
> - E2E encryption would really be preferable.  It looks fairly easy to
> do in the fe->be side of the protocol, but it's not obviously possible
> for the other direction.  In any event, I wanted to confine my changes
> to the smallest number of source files, so I didn't make any effort to
> implement this.  Either way, a protocol change is required.
> 
> -GAWollman
> 
> # This is a shell archive.  Save it in a file, remove anything before
> # this line, and then unpack it by entering "sh file".  Note, it may
> # create directories; files and directories will be owned by you and
> # have default permissions.
> #
> # This archive contains:
> #
> #	patch-be
> #	patch-bf
> #	patch-bg
> #	patch-bh
> #
> echo x - patch-be
> sed 's/^X//' >patch-be << 'END-of-patch-be'
> X--- backend/libpq/auth.c.orig	Wed Apr 12 13:15:13 2000
> X+++ backend/libpq/auth.c	Wed Sep 27 23:33:17 2000
> X@@ -142,7 +142,4 @@
> X 
> X #ifdef KRB5
> X-/* This needs to be ifdef'd out because krb5.h doesn't exist.  This needs
> X-   to be fixed.
> X-*/
> X /*----------------------------------------------------------------
> X  * MIT Kerberos authentication system - protocol version 5
> X@@ -150,5 +147,15 @@
> X  */
> X 
> X-#include "krb5/krb5.h"
> X+#include "krb5.h"
> X+#ifndef PG_KRB_SRVNAM
> X+#define	PG_KRB_SRVNAM	"pgsql"
> X+#endif
> X+#ifndef PG_KRB_KEYTAB
> X+#define PG_KRB_KEYTAB	"FILE:/etc/keytab.pgsql"
> X+#endif
> X+
> X+static krb5_context	mycontext;
> X+static int		mycontext_inited;
> X+static krb5_keytab	keytab;
> X 
> X /*
> X@@ -156,12 +163,11 @@
> X  *				  name
> X  *
> X- * XXX Assumes that the first aname component is the user name.  This is NOT
> X- *	   necessarily so, since an aname can actually be something out of your
> X- *	   worst X.400 nightmare, like
> X- *		  ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki(at)CS(dot)BERKELEY(dot)EDU
> X- *	   Note that the MIT an_to_ln code does the same thing if you don't
> X- *	   provide an aname mapping database...it may be a better idea to use
> X- *	   krb5_an_to_ln, except that it punts if multiple components are found,
> X- *	   and we can't afford to punt.
> X+ * XXX - this is totally broken (and potentially insecure on the server side).
> X+ * The correct mechanism is to use the entire principal name, and make
> X+ * the server do a table lookup to discover the mapping.
> X+ * (In the protocol as it stands, if user jrl(at)A(dot)EXAMPLE(dot)COM authenticates to
> X+ * a server in the B.EXAMPLE.COM realm, the server will accept him as
> X+ * local-user `jrl' regardless of whether or not jrl(at)A(dot)EXAMPLE(dot)COM is
> X+ * the same user as jrl(at)B(dot)EXAMPLE(dot)COM(dot))
> X  */
> X static char *
> X@@ -200,68 +206,117 @@
> X pg_krb5_recvauth(Port *port)
> X {
> X-	char		servbuf[MAXHOSTNAMELEN + 1 +
> X-									sizeof(PG_KRB_SRVNAM)];
> X-	char	   *hostp,
> X-			   *kusername = (char *) NULL;
> X+	char		hostbuf[MAXHOSTNAMELEN + 1];
> X+	char		*kusername = (char *) NULL;
> X 	krb5_error_code code;
> X-	krb5_principal client,
> X-				server;
> X-	krb5_address sender_addr;
> X-	krb5_rdreq_key_proc keyproc = (krb5_rdreq_key_proc) NULL;
> X-	krb5_pointer keyprocarg = (krb5_pointer) NULL;
> X+	krb5_principal	server;
> X+	krb5_auth_context authctx;
> X+	krb5_authenticator *them;
> X+
> X+	if (!mycontext_inited)
> X+	{
> X+		code = krb5_init_context(&mycontext);
> X+		if (code)
> X+		{
> X+			snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X+				 "pg_krb5_recvauth: krb5_init_context: %s\n",
> X+				 error_message(code));
> X+			fputs(PQerrormsg, stderr);
> X+			pqdebug("%s", PQerrormsg);
> X+			return STATUS_ERROR;
> X+		}
> X+		if (strcmp(PG_KRB_KEYTAB, "default") == 0)
> X+		{
> X+			code = krb5_kt_default(mycontext, &keytab);
> X+		}
> X+		else
> X+		{
> X+			code = krb5_kt_resolve(mycontext, PG_KRB_KEYTAB,
> X+					       &keytab);
> X+		}
> X+		if (code)
> X+		{
> X+			snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X+				 "pg_krb5_recvauth: keytab %s: %s\n",
> X+				 PG_KRB_KEYTAB,
> X+				 error_message(code));
> X+			fputs(PQerrormsg, stderr);
> X+			pqdebug("%s", PQerrormsg);
> X+			return STATUS_ERROR;
> X+		}
> X+		mycontext_inited = 1;
> X+	}
> X 
> X-	/*
> X-	 * Set up server side -- since we have no ticket file to make this
> X-	 * easy, we construct our own name and parse it.  See note on
> X-	 * canonicalization above.
> X-	 */
> X-	strcpy(servbuf, PG_KRB_SRVNAM);
> X-	*(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
> X-	if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
> X-		strcpy(hostp, "localhost");
> X-	if (hostp = strchr(hostp, '.'))
> X-		*hostp = '\0';
> X-	if (code = krb5_parse_name(servbuf, &server))
> X+	code = krb5_auth_con_init(mycontext, &authctx);
> X+	if (code)
> X+	{
> X+		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X+			 "pg_krb5_recvauth: krb5_auth_con_init: %s\n",
> X+			 error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X+		pqdebug("%s", PQerrormsg);
> X+		return STATUS_ERROR;
> X+	}
> X+
> X+	if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
> X 	{
> X 		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X-		"pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n", code);
> X-		com_err("pg_krb5_recvauth", code, "in krb5_parse_name");
> X+			 "pg_krb5_recvauth: gethostname: %s\n",
> X+			 strerror(errno));
> X+		fputs(PQerrormsg, stderr);
> X+		pqdebug("%s", PQerrormsg);
> X+		krb5_auth_con_free(mycontext, authctx);
> X 		return STATUS_ERROR;
> X 	}
> X 
> X+	code = krb5_sname_to_principal(mycontext, hostbuf, PG_KRB_SRVNAM,
> X+				       KRB5_NT_SRV_HST, &server);
> X+	if (code)
> X+	{
> X+		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X+			 "pg_krb5_recvauth: krb5_sname_to_principal: %s\n",
> X+			 error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X+		pqdebug("%s", PQerrormsg);
> X+		krb5_auth_con_free(mycontext, authctx);
> X+		return STATUS_ERROR;
> X+	}		
> X+
> X 	/*
> X 	 * krb5_sendauth needs this to verify the address in the client
> X 	 * authenticator.
> X 	 */
> X-	sender_addr.addrtype = port->raddr.in.sin_family;
> X-	sender_addr.length = sizeof(port->raddr.in.sin_addr);
> X-	sender_addr.contents = (krb5_octet *) & (port->raddr.in.sin_addr);
> X-
> X-	if (strcmp(PG_KRB_SRVTAB, ""))
> X+#define	ALL	(KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR | \
> X+		 KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)
> X+	code = krb5_auth_con_genaddrs(mycontext, authctx, port->sock, ALL);
> X+#undef ALL
> X+
> X+	code = krb5_recvauth(mycontext, &authctx, (krb5_pointer)&port->sock,
> X+			     PG_KRB5_VERSION, server, 0, keytab, 
> X+			     (krb5_ticket **)0);
> X+	if (code)
> X 	{
> X-		keyproc = krb5_kt_read_service_key;
> X-		keyprocarg = PG_KRB_SRVTAB;
> X+		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X+			 "pg_krb5_recvauth: krb5_recvauth: %s\n",
> X+			 error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X+		pqdebug("%s", PQerrormsg);
> X+		krb5_free_principal(mycontext, server);
> X+		krb5_auth_con_free(mycontext, authctx);
> X+		return STATUS_ERROR;
> X 	}
> X+	krb5_free_principal(mycontext, server);
> X 
> X-	if (code = krb5_recvauth((krb5_pointer) & port->sock,
> X-							 PG_KRB5_VERSION,
> X-							 server,
> X-							 &sender_addr,
> X-							 (krb5_pointer) NULL,
> X-							 keyproc,
> X-							 keyprocarg,
> X-							 (char *) NULL,
> X-							 (krb5_int32 *) NULL,
> X-							 &client,
> X-							 (krb5_ticket **) NULL,
> X-							 (krb5_authenticator **) NULL))
> X+	code = krb5_auth_con_getauthenticator(mycontext, authctx, &them);
> X+	if (code)
> X 	{
> X 		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X-		 "pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n", code);
> X-		com_err("pg_krb5_recvauth", code, "in krb5_recvauth");
> X-		krb5_free_principal(server);
> X+		 "pg_krb5_recvauth: getauthenticator: %s\n",
> X+			 error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X+		pqdebug("%s", PQerrormsg);
> X+		krb5_free_principal(mycontext, server);
> X+		krb5_auth_con_free(mycontext, authctx);
> X 		return STATUS_ERROR;
> X 	}
> X-	krb5_free_principal(server);
> X 
> X 	/*
> X@@ -270,13 +325,18 @@
> X 	 * postmaster startup packet.
> X 	 */
> X-	if ((code = krb5_unparse_name(client, &kusername)))
> X+	if ((code = krb5_unparse_name(mycontext, them->client, &kusername)))
> X 	{
> X 		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X-				 "pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n", code);
> X-		com_err("pg_krb5_recvauth", code, "in krb5_unparse_name");
> X-		krb5_free_principal(client);
> X+			 "pg_krb5_recvauth: krb5_unparse_name: %s\n",
> X+			 error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X+		pqdebug("%s", PQerrormsg);
> X+		krb5_free_authenticator(mycontext, them);
> X+		krb5_auth_con_free(mycontext, authctx);
> X 		return STATUS_ERROR;
> X 	}
> X-	krb5_free_principal(client);
> X+	krb5_free_authenticator(mycontext, them);
> X+	krb5_auth_con_free(mycontext, authctx);
> X+
> X 	if (!kusername)
> X 	{
> X@@ -288,5 +348,5 @@
> X 	}
> X 	kusername = pg_an_to_ln(kusername);
> X-	if (strncmp(username, kusername, SM_USER))
> X+	if (strncmp(port->user, kusername, SM_USER))
> X 	{
> X 		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X@@ -294,8 +354,8 @@
> X 		fputs(PQerrormsg, stderr);
> X 		pqdebug("%s", PQerrormsg);
> X-		pfree(kusername);
> X+		free(kusername);
> X 		return STATUS_ERROR;
> X 	}
> X-	pfree(kusername);
> X+	free(kusername);
> X 	return STATUS_OK;
> X }
> END-of-patch-be
> echo x - patch-bf
> sed 's/^X//' >patch-bf << 'END-of-patch-bf'
> Xdiff -ru2 old/configure.in configure.in
> X--- old/configure.in	Wed May 24 18:43:59 2000
> X+++ configure.in	Tue Sep 26 22:39:46 2000
> X@@ -369,4 +369,55 @@
> X export USE_ODBC
> X 
> X+AC_ARG_WITH(
> X+    krb5,
> X+    [  --with-krb5[=PREFIX]    build Kerberos 5 authentication support ],
> X+    [
> X+	case "$withval" in
> X+	y | ye | yes)	USE_KRB5=true;;
> X+	n | no)	USE_KRB5=false;;
> X+	*)	USE_KRB5=true
> X+		KRB5_INCS="-I$withval/include $KRB5_INCS"
> X+		KRB5_LIBS="-L$withval/lib $KRB5_LIBS";;
> X+	esac
> X+    ],
> X+    [ USE_KRB5=false ]
> X+)
> X+
> X+AC_ARG_WITH(
> X+    krb-service-name,
> X+    [  --with-krb-service-name=NAME authenticate as Kerberos principal NAME ],
> X+    [  KRB_SRVNAM="$withval" ],
> X+    [  unset KRB_SRVNAM ]
> X+)
> X+
> X+AC_ARG_WITH(
> X+    krb-keytab,
> X+    [  --with-krb-keytab=FILE:FILENAME use Kerberos v5 keytab FILENAME ],
> X+    [  KRB_KEYTAB="$withval" ],
> X+    [  unset KRB_KEYTAB ]
> X+)
> X+
> X+export USE_KRB5
> X+export KRB5_INCS
> X+export KRB5_LIBS
> X+
> X+AC_ARG_WITH(
> X+    openssl,
> X+    [  --with-openssl[=PREFIX] build OpenSSL transport support ],
> X+    [
> X+	case "$withval" in
> X+	y | ye | yes)	USE_OPENSSL=true;;
> X+	n | no)	USE_OPENSSL=false;;
> X+	*)	USE_OPENSSL=true
> X+		OPENSSL_INCS="-I$withval $OPENSSL_INCS"
> X+		OPENSSL_LIBS="-L$withval $OPENSSL_LIBS -lopenssl -lcrypto";;
> X+	esac
> X+    ],
> X+    [ USE_OPENSSL=false ]
> X+)
> X+export USE_OPENSSL
> X+export OPENSSL_INCS
> X+export OPENSSL_LIBS
> X+
> X AC_MSG_CHECKING(setproctitle)
> X AC_ARG_WITH(
> X@@ -509,4 +560,6 @@
> X AC_SUBST(USE_ODBC)
> X AC_SUBST(MULTIBYTE)
> X+AC_SUBST(USE_KRB5)
> X+AC_SUBST(USE_OPENSSL)
> X 
> X dnl Check for C++ support (allow override if needed)
> X@@ -1312,4 +1365,50 @@
> X 	CPPFLAGS="$ice_save_CPPFLAGS"
> X 	LDFLAGS="$ice_save_LDFLAGS"
> X+fi
> X+
> X+dnl
> X+dnl User requested Kerberos support in libpq; see if the required
> X+dnl header files and libraries are actually there.
> X+dnl
> X+if $USE_KRB5; then
> X+	AC_CHECKING(if Kerberos 5 environment is complete)
> X+	OCFLAGS="$CFLAGS"
> X+	OCPPFLAGS="$CPPFLAGS"
> X+	OLIBS="$LIBS"
> X+	if test "$KRB5_INCS"; then
> X+		CFLAGS="$CFLAGS $KRB5_INCS"
> X+		CPPFLAGS="$CPPFLAGS $KRB5_INCS"
> X+	fi
> X+	if test "$KRB5_LIBS"; then
> X+		LIBS="$LIBS $KRB5_LIBS"
> X+	fi
> X+	AC_CHECK_HEADERS(krb5.h)
> X+	AC_CHECK_LIB(krb5, krb5_recvauth, , , [-lk5crypto -lcom_err])
> X+	if test "$ac_cv_header_krb5_h" = "no"; then
> X+		AC_MSG_WARN([krb5.h not found; disabling Kerberos v5 support])
> X+		USE_KRB5=false
> X+		CFLAGS="$OCFLAGS"
> X+		LIBS="$OLIBS"
> X+	else
> X+		if test "$ac_cv_lib_krb5" = "no"; then
> X+			AC_MSG_WARN([libkrb5 not found; disabling Kerberos v5 support])
> X+			USE_KRB5=false
> X+		else
> X+		fi
> X+	fi
> X+	if $USE_KRB5; then
> X+		CFLAGS="$CFLAGS -DKRB5 -DUSE_KRB5"
> X+		LIBS="$LIBS -lkrb5 -lk5crypto -lcom_err"
> X+		if test "$KRB_SRVNAM"; then
> X+			CFLAGS="$CFLAGS -DPG_KRB_SRVNAM=\\\"$KRB_SRVNAM\\\""
> X+		fi
> X+		if test "$KRB_KEYTAB"; then
> X+			CFLAGS="$CFLAGS -DPG_KRB_KEYTAB=\\\"$KRB_KEYTAB\\\""
> X+		fi
> X+	else
> X+		CFLAGS="$OCFLAGS"
> X+		CPPFLAGS="$OCPPFLAGS"
> X+		LIBS="$OLIBS"
> X+	fi
> X fi
> X 
> END-of-patch-bf
> echo x - patch-bg
> sed 's/^X//' >patch-bg << 'END-of-patch-bg'
> Xdiff -ru2 old/interfaces/libpq/Makefile.in interfaces/libpq/Makefile.in
> X--- old/interfaces/libpq/Makefile.in	Thu Apr 13 20:42:06 2000
> X+++ interfaces/libpq/Makefile.in	Tue Sep 26 23:50:45 2000
> X@@ -34,4 +34,8 @@
> X # make sure it gets included in shared libpq.
> X SHLIB_LINK+= $(findstring -lcrypt,$(LIBS))
> X+SHLIB_LINK+= $(filter -L%,$(LIBS))
> X+SHLIB_LINK+= $(findstring -lkrb5,$(LIBS))
> X+SHLIB_LINK+= $(findstring -lk5crypto,$(LIBS))
> X+SHLIB_LINK+= $(findstring -lcom_err,$(LIBS))
> X 
> X # Shared library stuff, also default 'all' target
> END-of-patch-bg
> echo x - patch-bh
> sed 's/^X//' >patch-bh << 'END-of-patch-bh'
> X--- interfaces/libpq/fe-auth.c.orig	Wed Apr 12 13:17:13 2000
> X+++ interfaces/libpq/fe-auth.c	Wed Sep 27 23:15:30 2000
> X@@ -235,5 +235,9 @@
> X  */
> X 
> X-#include "krb5/krb5.h"
> X+#include <fcntl.h>
> X+#include "krb5.h"
> X+#ifndef PG_KRB_SRVNAM
> X+#define	PG_KRB_SRVNAM	"pgsql"
> X+#endif
> X 
> X /*
> X@@ -241,12 +245,11 @@
> X  *				  name
> X  *
> X- * XXX Assumes that the first aname component is the user name.  This is NOT
> X- *	   necessarily so, since an aname can actually be something out of your
> X- *	   worst X.400 nightmare, like
> X- *		  ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki(at)CS(dot)BERKELEY(dot)EDU
> X- *	   Note that the MIT an_to_ln code does the same thing if you don't
> X- *	   provide an aname mapping database...it may be a better idea to use
> X- *	   krb5_an_to_ln, except that it punts if multiple components are found,
> X- *	   and we can't afford to punt.
> X+ * XXX - this is totally broken (and potentially insecure on the server side).
> X+ * The correct mechanism is to use the entire principal name, and make
> X+ * the server do a table lookup to discover the mapping.
> X+ * (In the protocol as it stands, if user jrl(at)A(dot)EXAMPLE(dot)COM authenticates to
> X+ * a server in the B.EXAMPLE.COM realm, the server will accept him as
> X+ * local-user `jrl' regardless of whether or not jrl(at)A(dot)EXAMPLE(dot)COM is
> X+ * the same user as jrl(at)B(dot)EXAMPLE(dot)COM(dot))
> X  */
> X static char *
> X@@ -260,63 +263,37 @@
> X }
> X 
> X+static krb5_context mycontext;
> X+static int mycontext_inited;
> X+static krb5_ccache ccache;
> X 
> X-/*
> X- * pg_krb5_init -- initialization performed before any Kerberos calls are made
> X- *
> X- * With v5, we can no longer set the ticket (credential cache) file name;
> X- * we now have to provide a file handle for the open (well, "resolved")
> X- * ticket file everywhere.
> X- *
> X- */
> X-static int
> X-			krb5_ccache
> X+static krb5_error_code
> X pg_krb5_init(void)
> X {
> X 	krb5_error_code code;
> X-	char	   *realm,
> X-			   *defname;
> X-	char		tktbuf[MAXPGPATH];
> X-	static krb5_ccache ccache = (krb5_ccache) NULL;
> X 
> X-	if (ccache)
> X-		return ccache;
> X-
> X-	/*
> X-	 * If the user set PGREALM, then we use a ticket file with a special
> X-	 * name: <usual-ticket-file-name>@<PGREALM-value>
> X-	 */
> X-	if (!(defname = krb5_cc_default_name()))
> X-	{
> X-		(void) sprintf(PQerrormsg,
> X-					   "pg_krb5_init: krb5_cc_default_name failed\n");
> X-		return (krb5_ccache) NULL;
> X-	}
> X-	strcpy(tktbuf, defname);
> X-	if (realm = getenv("PGREALM"))
> X-	{
> X-		strcat(tktbuf, "@");
> X-		strcat(tktbuf, realm);
> X-	}
> X+	if (mycontext_inited)
> X+		return 0;
> X 
> X-	if (code = krb5_cc_resolve(tktbuf, &ccache))
> X-	{
> X-		(void) sprintf(PQerrormsg,
> X-		   "pg_krb5_init: Kerberos error %d in krb5_cc_resolve\n", code);
> X-		com_err("pg_krb5_init", code, "in krb5_cc_resolve");
> X-		return (krb5_ccache) NULL;
> X-	}
> X-	return ccache;
> X+	code = krb5_init_context(&mycontext);
> X+	if (code)
> X+		return code;
> X+
> X+	code = krb5_cc_default(mycontext, &ccache);
> X+	if (code)
> X+		return code;
> X+	mycontext_inited = 1;
> X+	return 0;
> X }
> X 
> X /*
> X  * pg_krb5_authname -- returns a pointer to static space containing whatever
> X- *					   name the user has authenticated to the system
> X+ * 		       name the user has authenticated to the system
> X  *
> X  * We obtain this information by digging around in the ticket file.
> X+ * XXX see comments above
> X  */
> X-static const char *
> X-pg_krb5_authname(const char *PQerrormsg)
> X+static char *
> X+pg_krb5_authname(char *PQerrormsg)
> X {
> X-	krb5_ccache ccache;
> X 	krb5_principal principal;
> X 	krb5_error_code code;
> X@@ -326,22 +303,33 @@
> X 		return authname;
> X 
> X-	ccache = pg_krb5_init();	/* don't free this */
> X+	code = pg_krb5_init();
> X+	if (code)
> X+	{
> X+		sprintf(PQerrormsg, "pg_krb5_init: %s\n",
> X+			error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X+		return (char *)NULL;
> X+	}
> X 
> X-	if (code = krb5_cc_get_principal(ccache, &principal))
> X+	code = krb5_cc_get_principal(mycontext, ccache, &principal);
> X+	if (code)
> X 	{
> X 		(void) sprintf(PQerrormsg,
> X-					   "pg_krb5_authname: Kerberos error %d in krb5_cc_get_principal\n", code);
> X-		com_err("pg_krb5_authname", code, "in krb5_cc_get_principal");
> X+			       "pg_krb5_authname: krb5_cc_get_principal: %s\n",
> X+			       error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X 		return (char *) NULL;
> X 	}
> X-	if (code = krb5_unparse_name(principal, &authname))
> X+	code = krb5_unparse_name(mycontext, principal, &authname);
> X+	if (code)
> X 	{
> X 		(void) sprintf(PQerrormsg,
> X-					   "pg_krb5_authname: Kerberos error %d in krb5_unparse_name\n", code);
> X-		com_err("pg_krb5_authname", code, "in krb5_unparse_name");
> X-		krb5_free_principal(principal);
> X+			       "pg_krb5_authname: krb5_unparse_name: %s\n",
> X+			       error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X+		krb5_free_principal(mycontext, principal);
> X 		return (char *) NULL;
> X 	}
> X-	krb5_free_principal(principal);
> X+	krb5_free_principal(mycontext, principal);
> X 	return pg_an_to_ln(authname);
> X }
> X@@ -349,107 +337,125 @@
> X /*
> X  * pg_krb5_sendauth -- client routine to send authentication information to
> X- *					   the server
> X- *
> X- * This routine does not do mutual authentication, nor does it return enough
> X- * information to do encrypted connections.  But then, if we want to do
> X- * encrypted connections, we'll have to redesign the whole RPC mechanism
> X- * anyway.
> X+ *		       the server
> X  *
> X- * Server hostnames are canonicalized v4-style, i.e., all domain suffixes
> X- * are simply chopped off.	Hence, we are assuming that you've entered your
> X- * server instances as
> X- *		<value-of-PG_KRB_SRVNAM>/<canonicalized-hostname>
> X- * in the PGREALM (or local) database.	This is probably a bad assumption.
> X  */
> X static int
> X-pg_krb5_sendauth(const char *PQerrormsg, int sock,
> X-				 struct sockaddr_in * laddr,
> X-				 struct sockaddr_in * raddr,
> X-				 const char *hostname)
> X+pg_krb5_sendauth(char *PQerrormsg, int sock,
> X+		 struct sockaddr_in * laddr,
> X+		 struct sockaddr_in * raddr,
> X+		 const char *hostname)
> X {
> X-	char		servbuf[MAXHOSTNAMELEN + 1 +
> X-									sizeof(PG_KRB_SRVNAM)];
> X-	const char *hostp;
> X-	const char *realm;
> X+	int sflags;
> X+	char servbuf[MAXHOSTNAMELEN + 1];
> X 	krb5_error_code code;
> X-	krb5_principal client,
> X-				server;
> X-	krb5_ccache ccache;
> X+	krb5_principal server;
> X 	krb5_error *error = (krb5_error *) NULL;
> X+	krb5_auth_context authctx;
> X 
> X-	ccache = pg_krb5_init();	/* don't free this */
> X+	code = pg_krb5_init();
> X+	if (code)
> X+	{
> X+		sprintf(PQerrormsg, "pg_krb5_init: %s\n",
> X+			error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X+		return STATUS_ERROR;
> X+	}
> X 
> X-	/*
> X-	 * set up client -- this is easy, we can get it out of the ticket
> X-	 * file.
> X-	 */
> X-	if (code = krb5_cc_get_principal(ccache, &client))
> X+	code = krb5_auth_con_init(mycontext, &authctx);
> X+	if (code)
> X 	{
> X-		(void) sprintf(PQerrormsg,
> X-					   "pg_krb5_sendauth: Kerberos error %d in krb5_cc_get_principal\n", code);
> X-		com_err("pg_krb5_sendauth", code, "in krb5_cc_get_principal");
> X+		sprintf(PQerrormsg,
> X+			"pg_krb5_recvauth: krb5_auth_con_init: %s\n",
> X+			error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X 		return STATUS_ERROR;
> X 	}
> X 
> X-	/*
> X-	 * set up server -- canonicalize as described above
> X-	 */
> X-	strcpy(servbuf, PG_KRB_SRVNAM);
> X-	*(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
> X-	if (hostname || *hostname)
> X-		strncpy(++hostp, hostname, MAXHOSTNAMELEN);
> X-	else
> X-	{
> X-		if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
> X-			strcpy(hostp, "localhost");
> X-	}
> X-	if (hostp = strchr(hostp, '.'))
> X-		*hostp = '\0';
> X-	if (realm = getenv("PGREALM"))
> X+	if (hostname == 0 || *hostname == '\0')
> X 	{
> X-		strcat(servbuf, "@");
> X-		strcat(servbuf, realm);
> X+		if (gethostname(servbuf, MAXHOSTNAMELEN) < 0)
> X+		{
> X+			sprintf(PQerrormsg,
> X+				 "pg_krb5_sendauth: gethostname: %s\n",
> X+				 strerror(errno));
> X+			fputs(PQerrormsg, stderr);
> X+			krb5_auth_con_free(mycontext, authctx);
> X+			return STATUS_ERROR;
> X+		}
> X+		hostname = servbuf;
> X 	}
> X-	if (code = krb5_parse_name(servbuf, &server))
> X+
> X+	code = krb5_sname_to_principal(mycontext, hostname, PG_KRB_SRVNAM,
> X+				       KRB5_NT_SRV_HST, &server);
> X+
> X+	if (code)
> X 	{
> X-		(void) sprintf(PQerrormsg,
> X-		"pg_krb5_sendauth: Kerberos error %d in krb5_parse_name\n", code);
> X-		com_err("pg_krb5_sendauth", code, "in krb5_parse_name");
> X-		krb5_free_principal(client);
> X+		sprintf(PQerrormsg,
> X+			"pg_krb5_sendauth: krb5_sname_to_principal: %s\n",
> X+			error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X+		krb5_auth_con_free(mycontext, authctx);
> X+		return STATUS_ERROR;
> X+	}
> X+
> X+#define	ALL	(KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR | \
> X+		 KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)
> X+	code = krb5_auth_con_genaddrs(mycontext, authctx, sock, ALL);
> X+#undef ALL
> X+	if (code)
> X+	{
> X+		sprintf(PQerrormsg,
> X+			"pg_krb5_sendauth: krb5_auth_con_genaddrs: %s\n",
> X+			error_message(code));
> X+		fputs(PQerrormsg, stderr);
> X+		krb5_free_principal(mycontext, server);
> X+		krb5_auth_con_free(mycontext, authctx);
> X 		return STATUS_ERROR;
> X 	}
> X 
> X+
> X+	/*
> X+	 * krb5_sendauth does not appreciate getting a non-blocking file
> X+	 * descriptor.  So, we set it to blocking mode and then reset
> X+	 * it afterwards.
> X+	 */
> X+	sflags = fcntl(sock, F_GETFL, 0);
> X+	fcntl(sock, F_SETFL, sflags & ~O_NONBLOCK);
> X+
> X 	/*
> X 	 * The only thing we want back from krb5_sendauth is an error status
> X-	 * and any error messages.
> X+	 * and any error messages.  If we cared, we could get the session
> X+	 * key(s) from the auth context and stick them somewhere to encrypt
> X+	 * the whole data stream.  However, this would mean a major change
> X+	 * in the protocol, and I'm not prepared to do that right now.
> X+	 * (It should work to encrypt the session using SSL, if a bit of a
> X+	 * muchness.)
> X 	 */
> X-	if (code = krb5_sendauth((krb5_pointer) & sock,
> X-							 PG_KRB5_VERSION,
> X-							 client,
> X-							 server,
> X-							 (krb5_flags) 0,
> X-							 (krb5_checksum *) NULL,
> X-							 (krb5_creds *) NULL,
> X-							 ccache,
> X-							 (krb5_int32 *) NULL,
> X-							 (krb5_keyblock **) NULL,
> X-							 &error,
> X-							 (krb5_ap_rep_enc_part **) NULL))
> X+	code = krb5_sendauth(mycontext, &authctx, (krb5_pointer) &sock,
> X+			     PG_KRB5_VERSION, (krb5_principal) NULL,
> X+			     server, AP_OPTS_MUTUAL_REQUIRED,
> X+			     (krb5_data *) NULL, (krb5_creds *) NULL,
> X+			     ccache, &error, (krb5_ap_rep_enc_part **) NULL,
> X+			     (krb5_creds **) NULL);
> X+	fcntl(sock, F_SETFL, sflags);
> X+	if (code)
> X 	{
> X 		if ((code == KRB5_SENDAUTH_REJECTED) && error)
> X 		{
> X-			(void) sprintf(PQerrormsg,
> X-				  "pg_krb5_sendauth: authentication rejected: \"%*s\"\n",
> X-						   error->text.length, error->text.data);
> X+			sprintf(PQerrormsg,
> X+				"pg_krb5_sendauth: authentication rejected: \"%.*s\"\n",
> X+				error->text.length, error->text.data);
> X 		}
> X 		else
> X 		{
> X-			(void) sprintf(PQerrormsg,
> X-						   "pg_krb5_sendauth: Kerberos error %d in krb5_sendauth\n", code);
> X-			com_err("pg_krb5_sendauth", code, "in krb5_sendauth");
> X+			sprintf(PQerrormsg,
> X+				"pg_krb5_sendauth: krb5_sendauth: %s\n", 
> X+				error_message(code));
> X 		}
> X 	}
> X-	krb5_free_principal(client);
> X-	krb5_free_principal(server);
> X+	krb5_free_principal(mycontext, server);
> X+	if (error != 0)
> X+		krb5_free_error(mycontext, error);
> X+	krb5_auth_con_free(mycontext, authctx);
> X 	return code ? STATUS_ERROR : STATUS_OK;
> X }
> END-of-patch-bh
> exit
> 
> 
> 


-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman(at)candle(dot)pha(dot)pa(dot)us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

In response to

Responses

pgsql-patches by date

Next:From: Peter EisentrautDate: 2000-11-06 18:06:12
Subject: Re: Minor make bug on AIX
Previous:From: Pete FormanDate: 2000-11-06 16:59:08
Subject: Minor make bug on AIX

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group