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
Views: Raw Message | Whole Thread | Download mbox | Resend email
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

Browse pgsql-patches by date

  From Date Subject
Next Message Peter Eisentraut 2000-11-06 18:06:12 Re: Minor make bug on AIX
Previous Message Pete Forman 2000-11-06 16:59:08 Minor make bug on AIX