Re: Kerberos v5 support - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: Kerberos v5 support |
Date | |
Msg-id | 200011061705.MAA22568@candle.pha.pa.us Whole thread Raw |
In response to | Kerberos v5 support (Garrett Wollman <wollman@khavrinen.lcs.mit.edu>) |
Responses |
Re: Kerberos v5 support
|
List | 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@CS.BERKELEY.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@A.EXAMPLE.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@A.EXAMPLE.COM is > X+ * the same user as jrl@B.EXAMPLE.COM.) > 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@CS.BERKELEY.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@A.EXAMPLE.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@A.EXAMPLE.COM is > X+ * the same user as jrl@B.EXAMPLE.COM.) > 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@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
pgsql-patches by date: