From e6befdc9d1666667835dc49d3b61bb526d74b69d Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 25 Mar 2005 00:34:31 +0000
Subject: [PATCH] Kerberos fixes from Magnus Hagander --- in theory Kerberos 5
 auth should work on Windows now.  Also, rename set_noblock to pg_set_noblock;
 since it is included in libpq, the former name polluted application
 namespace.

---
 configure                           | 121 +++++++++++++++++++++++++++-
 configure.in                        |  19 +++--
 src/backend/postmaster/pgstat.c     |   6 +-
 src/backend/postmaster/postmaster.c |  10 +--
 src/include/port.h                  |   5 +-
 src/interfaces/libpq/Makefile       |   4 +-
 src/interfaces/libpq/fe-auth.c      |  21 ++---
 src/interfaces/libpq/fe-connect.c   |   4 +-
 src/port/noblock.c                  |  27 ++++++-
 9 files changed, 182 insertions(+), 35 deletions(-)

diff --git a/configure b/configure
index 22a2ca9a62e..b77ec52aa8c 100755
--- a/configure
+++ b/configure
@@ -6358,7 +6358,8 @@ done
 fi
 
 if test "$with_krb5" = yes ; then
-  echo "$as_me:$LINENO: checking for library containing com_err" >&5
+  if test "$PORTNAME" != "win32"; then
+     echo "$as_me:$LINENO: checking for library containing com_err" >&5
 echo $ECHO_N "checking for library containing com_err... $ECHO_C" >&6
 if test "${ac_cv_search_com_err+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
@@ -6470,7 +6471,7 @@ echo "$as_me: error: could not find function 'com_err' required for Kerberos 5"
    { (exit 1); exit 1; }; }
 fi
 
-  echo "$as_me:$LINENO: checking for library containing krb5_encrypt" >&5
+     echo "$as_me:$LINENO: checking for library containing krb5_encrypt" >&5
 echo $ECHO_N "checking for library containing krb5_encrypt... $ECHO_C" >&6
 if test "${ac_cv_search_krb5_encrypt+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
@@ -6582,7 +6583,7 @@ echo "$as_me: error: could not find function 'krb5_encrypt' required for Kerbero
    { (exit 1); exit 1; }; }
 fi
 
-  echo "$as_me:$LINENO: checking for library containing krb5_sendauth" >&5
+     echo "$as_me:$LINENO: checking for library containing krb5_sendauth" >&5
 echo $ECHO_N "checking for library containing krb5_sendauth... $ECHO_C" >&6
 if test "${ac_cv_search_krb5_sendauth+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
@@ -6694,6 +6695,120 @@ echo "$as_me: error: could not find function 'krb5_sendauth' required for Kerber
    { (exit 1); exit 1; }; }
 fi
 
+  else
+     echo "$as_me:$LINENO: checking for library containing com_err" >&5
+echo $ECHO_N "checking for library containing com_err... $ECHO_C" >&6
+if test "${ac_cv_search_com_err+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_com_err=no
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char com_err ();
+#ifdef F77_DUMMY_MAIN
+#  ifdef __cplusplus
+     extern "C"
+#  endif
+   int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+com_err ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_com_err="none required"
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_com_err" = no; then
+  for ac_lib in 'comerr32 -lkrb5_32'; do
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char com_err ();
+#ifdef F77_DUMMY_MAIN
+#  ifdef __cplusplus
+     extern "C"
+#  endif
+   int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+com_err ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_search_com_err="-l$ac_lib"
+break
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_com_err" >&5
+echo "${ECHO_T}$ac_cv_search_com_err" >&6
+if test "$ac_cv_search_com_err" != no; then
+  test "$ac_cv_search_com_err" = "none required" || LIBS="$ac_cv_search_com_err $LIBS"
+
+else
+  { { echo "$as_me:$LINENO: error: could not find function 'com_err' required for Kerberos 5" >&5
+echo "$as_me: error: could not find function 'com_err' required for Kerberos 5" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+  fi
 fi
 
 if test "$with_openssl" = yes ; then
diff --git a/configure.in b/configure.in
index ffc118ea8b7..d8da7cd4ffb 100644
--- a/configure.in
+++ b/configure.in
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-dnl $PostgreSQL: pgsql/configure.in,v 1.406 2005/03/11 17:20:33 momjian Exp $
+dnl $PostgreSQL: pgsql/configure.in,v 1.407 2005/03/25 00:34:19 tgl Exp $
 dnl
 dnl Developers, please strive to achieve this order:
 dnl
@@ -673,12 +673,17 @@ if test "$with_krb4" = yes ; then
 fi
 
 if test "$with_krb5" = yes ; then
-  AC_SEARCH_LIBS(com_err, [krb5 'krb5 -ldes -lasn1 -lroken' com_err], [],
-                 [AC_MSG_ERROR([could not find function 'com_err' required for Kerberos 5])])
-  AC_SEARCH_LIBS(krb5_encrypt, [krb5 'krb5 -ldes -lasn1 -lroken' crypto k5crypto], [],
-                 [AC_MSG_ERROR([could not find function 'krb5_encrypt' required for Kerberos 5])])
-  AC_SEARCH_LIBS(krb5_sendauth, [krb5 'krb5 -ldes -lasn1 -lroken'], [],
-                 [AC_MSG_ERROR([could not find function 'krb5_sendauth' required for Kerberos 5])])
+  if test "$PORTNAME" != "win32"; then
+     AC_SEARCH_LIBS(com_err, [krb5 'krb5 -ldes -lasn1 -lroken' com_err], [],
+                    [AC_MSG_ERROR([could not find function 'com_err' required for Kerberos 5])])
+     AC_SEARCH_LIBS(krb5_encrypt, [krb5 'krb5 -ldes -lasn1 -lroken' crypto k5crypto], [],
+                    [AC_MSG_ERROR([could not find function 'krb5_encrypt' required for Kerberos 5])])
+     AC_SEARCH_LIBS(krb5_sendauth, [krb5 'krb5 -ldes -lasn1 -lroken'], [],
+                    [AC_MSG_ERROR([could not find function 'krb5_sendauth' required for Kerberos 5])])
+  else
+     AC_SEARCH_LIBS(com_err, 'comerr32 -lkrb5_32', [],
+                    [AC_MSG_ERROR([could not find function 'com_err' required for Kerberos 5])])
+  fi
 fi
 
 if test "$with_openssl" = yes ; then
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 9d418f9cd45..2d06cbf146d 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -13,7 +13,7 @@
  *
  *	Copyright (c) 2001-2005, PostgreSQL Global Development Group
  *
- *	$PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.87 2005/01/01 05:43:07 momjian Exp $
+ *	$PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.88 2005/03/25 00:34:21 tgl Exp $
  * ----------
  */
 #include "postgres.h"
@@ -422,7 +422,7 @@ pgstat_init(void)
 	 * messages will be discarded; backends won't block waiting to send
 	 * messages to the collector.
 	 */
-	if (!set_noblock(pgStatSock))
+	if (!pg_set_noblock(pgStatSock))
 	{
 		ereport(LOG,
 				(errcode_for_socket_access(),
@@ -1766,7 +1766,7 @@ pgstat_recvbuffer(void)
 	 * Set the write pipe to nonblock mode, so that we cannot block when
 	 * the collector falls behind.
 	 */
-	if (!set_noblock(writePipe))
+	if (!pg_set_noblock(writePipe))
 		ereport(ERROR,
 				(errcode_for_socket_access(),
 				 errmsg("could not set statistics collector pipe to nonblocking mode: %m")));
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index a8aae43b6fe..a7d289ffb37 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.449 2005/03/24 18:16:17 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.450 2005/03/25 00:34:21 tgl Exp $
  *
  * NOTES
  *
@@ -1246,10 +1246,10 @@ ServerLoop(void)
 			PgStatPID = pgstat_start();
 
 		/*
-		 * Touch the socket and lock file at least every hour, to
+		 * Touch the socket and lock file every 58 minutes, to
 		 * ensure that they are not removed by overzealous /tmp-cleaning
-		 * tasks.  Set to 58 minutes so a cleaner never sees the
-		 * file as an hour old.
+		 * tasks.  We assume no one runs cleaners with cutoff times of
+		 * less than an hour ...
 		 */
 		now = time(NULL);
 		if (now - last_touch_time >= 58 * 60)
@@ -2479,7 +2479,7 @@ report_fork_failure_to_client(Port *port, int errnum)
 			 strerror(errnum));
 
 	/* Set port to non-blocking.  Don't do send() if this fails */
-	if (!set_noblock(port->sock))
+	if (!pg_set_noblock(port->sock))
 		return;
 
 	send(port->sock, buffer, strlen(buffer) + 1, 0);
diff --git a/src/include/port.h b/src/include/port.h
index 5a3a46ec016..4869ee66265 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/port.h,v 1.73 2005/03/16 21:27:23 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/port.h,v 1.74 2005/03/25 00:34:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,7 +20,8 @@
 #include <ctype.h>
 
 /* non-blocking */
-extern bool set_noblock(int sock);
+extern bool pg_set_noblock(int sock);
+extern bool pg_set_block(int sock);
 
 /* Portable path handling for Unix/Win32 */
 
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index f856927bb58..92ff20e6d93 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -5,7 +5,7 @@
 # Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $PostgreSQL: pgsql/src/interfaces/libpq/Makefile,v 1.130 2005/03/14 17:27:50 momjian Exp $
+# $PostgreSQL: pgsql/src/interfaces/libpq/Makefile,v 1.131 2005/03/25 00:34:28 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -55,7 +55,7 @@ endif
 # matter.)
 SHLIB_LINK += $(filter -lcrypt -ldes -lkrb -lcom_err -lcrypto -lk5crypto -lkrb5 -lssl -lsocket -lnsl -lresolv -lintl, $(LIBS)) $(PTHREAD_LIBS)
 ifeq ($(PORTNAME), win32)
-SHLIB_LINK += -lshfolder -lwsock32 -lws2_32 $(filter -leay32 -lssleay32, $(LIBS))
+SHLIB_LINK += -lshfolder -lwsock32 -lws2_32 $(filter -leay32 -lssleay32 -lcomerr32 -lkrb5_32, $(LIBS))
 endif
 
 
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 065eba35814..0dda34401bb 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -10,7 +10,7 @@
  * exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.99 2005/01/12 21:37:54 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.100 2005/03/25 00:34:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -367,7 +367,13 @@ pg_krb5_sendauth(char *PQerrormsg, int sock, const char *hostname)
 	krb5_principal server;
 	krb5_auth_context auth_context = NULL;
 	krb5_error *err_ret = NULL;
-	int			flags;
+
+	if (!hostname)
+	{
+		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+				 "pg_krb5_sendauth: hostname must be specified for Kerberos authentication\n");
+		return STATUS_ERROR;
+	}
 
 	ret = pg_krb5_init(PQerrormsg);
 	if (ret != STATUS_OK)
@@ -388,8 +394,7 @@ pg_krb5_sendauth(char *PQerrormsg, int sock, const char *hostname)
 	 * socket, and we have to block somehow to do mutual authentication
 	 * anyway. So we temporarily make it blocking.
 	 */
-	flags = fcntl(sock, F_GETFL);
-	if (flags < 0 || fcntl(sock, F_SETFL, (long) (flags & ~O_NONBLOCK)))
+	if (!pg_set_block(sock))
 	{
 		char		sebuf[256];
 
@@ -436,7 +441,7 @@ pg_krb5_sendauth(char *PQerrormsg, int sock, const char *hostname)
 
 	krb5_free_principal(pg_krb5_context, server);
 
-	if (fcntl(sock, F_SETFL, (long) flags))
+	if (!pg_set_noblock(sock))
 	{
 		char		sebuf[256];
 
@@ -599,8 +604,7 @@ fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
 							   (struct sockaddr_in *) & conn->raddr.addr,
 								 hostname) != STATUS_OK)
 			{
-				snprintf(PQerrormsg, PQERRORMSG_LENGTH,
-					libpq_gettext("Kerberos 4 authentication failed\n"));
+				/* PQerrormsg already filled in */
 				pgunlock_thread();
 				return STATUS_ERROR;
 			}
@@ -618,8 +622,7 @@ fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
 			if (pg_krb5_sendauth(PQerrormsg, conn->sock,
 								 hostname) != STATUS_OK)
 			{
-				snprintf(PQerrormsg, PQERRORMSG_LENGTH,
-					libpq_gettext("Kerberos 5 authentication failed\n"));
+				/* PQerrormsg already filled in */
 				pgunlock_thread();
 				return STATUS_ERROR;
 			}
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 188c80a72be..af80b857b9c 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.303 2005/02/22 04:42:20 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.304 2005/03/25 00:34:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1211,7 +1211,7 @@ keep_going:						/* We will come back to here until there
 							continue;
 						}
 					}
-					if (!set_noblock(conn->sock))
+					if (!pg_set_noblock(conn->sock))
 					{
 						printfPQExpBuffer(&conn->errorMessage,
 										  libpq_gettext("could not set socket to non-blocking mode: %s\n"),
diff --git a/src/port/noblock.c b/src/port/noblock.c
index d1431545989..904f40b5df3 100644
--- a/src/port/noblock.c
+++ b/src/port/noblock.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/port/noblock.c,v 1.5 2004/12/31 22:03:53 pgsql Exp $
+ *	  $PostgreSQL: pgsql/src/port/noblock.c,v 1.6 2005/03/25 00:34:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,7 +18,7 @@
 #include <fcntl.h>
 
 bool
-set_noblock(int sock)
+pg_set_noblock(int sock)
 {
 #if !defined(WIN32) && !defined(__BEOS__)
 	return (fcntl(sock, F_SETFL, O_NONBLOCK) != -1);
@@ -34,3 +34,26 @@ set_noblock(int sock)
 #endif
 #endif
 }
+
+
+bool
+pg_set_block(int sock)
+{
+#if !defined(WIN32) && !defined(__BEOS__)
+	int flags;
+	flags = fcntl(sock, F_GETFL);
+	if (flags < 0 || fcntl(sock, F_SETFL, (long) (flags & ~O_NONBLOCK)))
+		return false;
+	return true;
+#else
+	long		ioctlsocket_ret = 0;
+
+	/* Returns non-0 on failure, while fcntl() returns -1 on failure */
+#ifdef WIN32
+	return (ioctlsocket(sock, FIONBIO, &ioctlsocket_ret) == 0);
+#endif
+#ifdef __BEOS__
+	return (ioctl(sock, FIONBIO, &ioctlsocket_ret) == 0);
+#endif
+#endif
+}
-- 
GitLab